laminas/laminas-router
Laminas Router provides flexible, composable routing for PHP applications, with HTTP/console route types, route matching and assembly, and integration points for Laminas MVC/Mezzio. Includes CI-tested components and configurable route stacks.
## Getting Started
### Minimal Setup in Laravel
To integrate `laminas/laminas-router` into a Laravel project, start by installing it via Composer:
```bash
composer require laminas/laminas-router
First Use Case: Basic HTTP Route Matching Leverage the package to create a lightweight router alongside Laravel's built-in router for specialized needs (e.g., API versioning, legacy systems, or custom middleware chains). Example:
use Laminas\Router\Http\Segment;
use Laminas\Router\Http\TreeRouteStack;
use Laminas\Http\PhpEnvironment\Request;
// Create a request object (Laravel's Request can be adapted)
$request = new Request();
// Define a route (e.g., `/blog/{year}/{month}`)
$route = new Segment([
'route' => '/blog/:year/:month',
'defaults' => ['controller' => 'BlogController', 'action' => 'index'],
'specs' => [
'year' => '[0-9]{4}',
'month' => '[0-9]{2}',
],
]);
// Build a router and match the request
$router = new TreeRouteStack();
$router->addRoute('blog', $route);
$match = $router->match($request);
if ($match) {
// Route matched; extract params
$params = $match->getParam('year'); // e.g., "2023"
}
Where to Look First
Segment, Regex, Hostname, etc.).TreeRouteStack for hierarchical route management (e.g., API versioning: /v1/users, /v2/users).Use Laminas Router for complex or legacy routes while letting Laravel handle the rest. Example:
// In a service provider (e.g., `AppServiceProvider`)
public function boot()
{
$router = new TreeRouteStack();
$router->addRoute('admin', new Segment([
'route' => '/admin/:action',
'defaults' => ['controller' => 'AdminController'],
]));
// Attach to Laravel's middleware pipeline
$this->app->router->extend('admin', function ($request) use ($router) {
$match = $router->match($request);
if ($match) {
return redirect()->route('admin', $match->getParams());
}
});
}
Generate URLs dynamically using Laminas Router’s getUri() method:
$route = new Segment([
'route' => '/products/:id',
'defaults' => ['controller' => 'ProductController', 'action' => 'show'],
]);
$router = new TreeRouteStack();
$router->addRoute('product', $route);
// Generate URL for product ID 42
$uri = $router->getUri()->setQuery(['id' => 42])->toString();
// Outputs: "/products/42"
Attach middleware to specific routes:
$route = new Segment([
'route' => '/secure',
'defaults' => ['controller' => 'SecureController'],
'may_terminate' => true, // Optional: for middleware termination
]);
// In Laravel's `HandleIncomingRequest` middleware
public function handle($request, Closure $next)
{
$match = $router->match($request);
if ($match && $match->getRouteName() === 'secure') {
if (!auth()->check()) {
return redirect()->route('login');
}
}
return $next($request);
}
Laminas Router supports console commands too:
use Laminas\Router\Route\Console;
$consoleRoute = new Console([
'route' => 'cache:clear',
'defaults' => ['command' => 'cache:clear'],
]);
$consoleRouter = new TreeRouteStack();
$consoleRouter->addRoute('cache-clear', $consoleRoute);
// Match a console command
$match = $consoleRouter->match(new Laminas\Console\ConsoleRequest('cache:clear'));
Use priority to control route matching order:
$route1 = new Segment(['route' => '/users', 'priority' => 10]);
$route2 = new Segment(['route' => '/users/:id', 'priority' => 20]);
$router = new TreeRouteStack();
$router->addRoute('users', $route1);
$router->addRoute('user', $route2); // Higher priority for dynamic routes
Case Sensitivity:
Laminas Router is case-sensitive by default. For case-insensitive routes, use a Regex route:
$route = new Regex([
'route' => '/users/(?<id>[a-z0-9]+)',
'defaults' => ['controller' => 'UserController'],
'specs' => ['id' => 'i'], // 'i' flag for case-insensitive
]);
Hostname Matching:
Hostname routes require exact matches unless configured otherwise. Use Hostname route type:
$route = new Hostname([
'route' => 'api.example.com',
'defaults' => ['controller' => 'ApiController'],
]);
Query String Handling:
Laminas Router ignores query strings by default. To include them, use Query route type or parse them manually:
$request->getQuery()->toArray(); // Manually handle queries
Route Matching Order:
Routes are matched in the order they are added. Use priority or TreeRouteStack for hierarchical matching.
Deprecated Properties:
Avoid using priority as a dynamic property (deprecated). Instead, set it in the constructor:
// Wrong (deprecated)
$route->priority = 10;
// Correct
$route = new Segment(['route' => '/test', 'priority' => 10]);
Dump Route Matches:
Use var_dump($match->getParams()) to inspect matched parameters.
Validate Routes: Test routes in isolation before integrating with Laravel:
$request = new Request();
$request->setUri('/blog/2023/05');
$match = $router->match($request);
assert($match !== null, "Route should match!");
Laravel Request Adaptation:
Convert Laravel’s Illuminate\Http\Request to Laminas PhpEnvironment\Request for compatibility:
$laminasRequest = new Request();
$laminasRequest->setUri($laravelRequest->getRequestUri())
->setMethod($laravelRequest->getMethod());
Custom Route Types:
Extend Laminas\Router\Http\AbstractRoute to create domain-specific routes (e.g., ApiRoute for versioned APIs).
Middleware Integration:
Use Laminas Router’s mayTerminate flag to short-circuit Laravel’s middleware pipeline for specific routes.
Route Caching: Cache compiled routes for performance:
$router = new TreeRouteStack();
$router->setCache(new \Laminas\Cache\Filesystem());
Route Plugins:
Use Laminas\Router\Http\RoutePluginManager to dynamically add route types or modifiers.
/v1/users, /v2/users). Avoid flat structures with thousands of routes.$router = new TreeRouteStack();
$router->setCache(new \Laminas\Cache\Psr6());
Route Model Binding: Combine Laminas Router with Laravel’s implicit binding:
$route = new Segment([
'route' => '/posts/:id',
'defaults' => ['controller' => 'PostController', 'action' => 'show'],
]);
// Laravel will automatically bind the `id` to the `Post` model.
Named Routes:
Use Laminas Router’s name parameter to generate URLs via Laravel’s route() helper:
$route = new Segment([
'route' => '/posts/:id',
'name' => 'posts.show',
]);
// Generate URL: route('posts.show', ['id' => 1])
API Resource Routing: For API resources, use Laminas Router to define versioned routes:
How can I help you explore Laravel packages today?