Derafu: Routing - Elegant PHP Router with Plugin Architecture

GitHub last commit CI Workflow GitHub code size in bytes GitHub Issues Total Downloads Monthly Downloads

A lightweight, extensible PHP routing library that combines simplicity with power through its parser-based architecture.

Features

  • πŸ”Œ Plugin architecture with swappable parsers.
  • 🎯 Multiple routing strategies (static, dynamic, filesystem).
  • 🧩 Easy to extend with custom parsers.
  • πŸ“ Built-in filesystem routing for static sites.
  • πŸ”„ Support for different content types (.md, .twig, etc.).
  • πŸ› οΈ Clean separation of concerns.
  • πŸͺΆ Lightweight with zero dependencies.
  • ⚑ Fast pattern matching.
  • πŸ§ͺ Comprehensive test coverage.

Why Derafu\Routing?

Unlike traditional monolithic routers, Derafu\Routing uses a unique parser-based architecture that offers several advantages:

  • Modularity: Each routing strategy is encapsulated in its own parser.
  • Flexibility: Easy to add new routing patterns without modifying existing code.
  • Clarity: Clear separation between route matching and request handling.
  • Extensibility: Add custom parsers for specific routing needs.
  • Predictability: Each parser has a single responsibility.
  • Performance: Only load the parsers you need.

Installation

Install via Composer:

composer require derafu/routing

Basic Usage

use Derafu\Routing\Router;
use Derafu\Routing\Dispatcher;
use Derafu\Routing\Parser\StaticParser;
use Derafu\Routing\Parser\FileSystemParser;

// Create and configure router.
$router = new Router();
$router->addParser(new StaticParser());
$router->addParser(new FileSystemParser([__DIR__ . '/pages']));

// Add routes.
$router->addRoute('/', 'HomeController::index');
$router->addDirectory(__DIR__ . '/pages');

// Create and configure dispatcher.
$dispatcher = new Dispatcher([
    'md' => fn ($file, $params) => renderMarkdown($file),
    'twig' => fn($file, $params) => renderTwig($file, $params),
]);

// Handle request.
try {
    $route = $router->match();
    echo $dispatcher->dispatch($route);
} catch (RouterException $e) {
    // Handle error.
}

Available Parsers

StaticParser

Handles exact route matches:

$router->addRoute('/about', 'PagesController::about');

DynamicParser

Supports parameters and patterns:

$router->addRoute('/users/{id:\d+}', 'UserController::show');
$router->addRoute('/blog/{year}/{slug}', 'BlogController::post');

FileSystemParser

Maps URLs to files in directories:

$router->addDirectory(__DIR__ . '/pages');
// Examples:
// /about maps to /pages/about.md
// /contact maps to /pages/contact.html.twig

Creating Custom Parsers

Implement your own routing strategy by creating a parser:

class CustomParser implements ParserInterface
{
    public function parse(string $uri, array $routes): ?RouteMatch
    {
        // Your custom routing logic.
    }

    public function supports(Route $route): bool
    {
        // Define what routes this parser can handle.
    }
}

$router->addParser(new CustomParser());

File-based Routing Example

Perfect for static sites:

pages/
β”œβ”€β”€ about.md
β”œβ”€β”€ contact.html.twig
└── blog/
    β”œβ”€β”€ post-1.md
    └── post-2.md

URLs are automatically mapped to files:

  • /about β†’ pages/about.md
  • /contact β†’ pages/contact.html.twig
  • /blog/post-1 β†’ pages/blog/post-1.md

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

License

This package is open-sourced software licensed under the MIT license.