Installation:
composer require ibexa/templated-uri-router
Add to composer.json if not using CLI:
"require": {
"ibexa/templated-uri-router": "^1.0"
}
Define Routes:
Create a YAML/array config file (e.g., routing.yml):
demo_route:
pattern: "/products/{category}"
First Use Case: Generate a templated URI in a controller or service:
use Hautelook\TemplatedUriRouter\Routing\Generator\Rfc6570Generator;
$routes = require __DIR__.'/routing.yml';
$generator = new Rfc6570Generator($routes, new \stdClass()); // Context (e.g., request params)
$uri = $generator->generate('demo_route', ['category' => '{category}']);
// Output: `/products/{category}`
Route Definition:
{id}, {*path}).api_route:
pattern: "/api/v1/{controller}/{action}.{_format}"
_format is reserved for Symfony’s format parameter.URI Generation:
{page}) or arrays (e.g., ['{filter}']) for query parameters:
$uri = $generator->generate('api_route', [
'controller' => 'users',
'action' => 'list',
'_format' => 'json',
'page' => ['{page}'],
'sort' => ['{sort}']
]);
// Output: `/api/v1/users/list.json{?page*,sort*}`
Integration with Laravel:
AppServiceProvider:
public function register()
{
$this->app->singleton('templated.uri.generator', function ($app) {
$routes = require __DIR__.'/../config/routing.php';
return new Rfc6570Generator($routes, new \stdClass());
});
}
use Illuminate\Support\Facades\App;
$uri = App::make('templated.uri.generator')->generate('demo_route', ['category' => 'electronics']);
Query Parameter Handling:
['{filter}', '{sort}'] // Output: `{?filter*,sort*}`
['page' => ['{page}'], 'limit' => ['{limit}']]
Context Injection:
$context = (object) ['default_category' => 'books'];
$generator = new Rfc6570Generator($routes, $context);
$uri = $generator->generate('demo_route', ['category' => '{category}']);
// If `category` is omitted, uses `default_category` from context.
Reserved Parameters:
_format, _locale, or _controller as route keys—these are reserved by Symfony/Laravel.bad_route:
pattern: "/{_format}" # May conflict with Laravel's format system.
Context Overrides:
$context = (object) ['category' => 'default'];
$uri = $generator->generate('demo_route', ['category' => '{category}']);
// Output: `/products/default` (not `/products/{category}`).
Query Parameter Escaping:
$safePage = htmlspecialchars($page);
$uri = $generator->generate('route', ['page' => $safePage]);
Route Key Collisions:
demo_route) are unique in your config.Invalid Patterns:
{} or invalid modifiers like *).bad_pattern: "/{category}" # Missing closing brace if written as `/{category`.
Missing Routes:
RouteNotFoundException if the route key doesn’t exist. Handle gracefully:
try {
$uri = $generator->generate('nonexistent_route', []);
} catch (\InvalidArgumentException $e) {
abort(404);
}
Custom Context:
$context = (object) [
'user' => auth()->user(),
'default_lang' => 'en'
];
Post-Processing:
Url::to() for additional logic:
$templatedUri = $generator->generate('route', ['{param}']);
$finalUri = url($templatedUri); // Add base URL, etc.
Middleware Integration:
public function handle($request, Closure $next)
{
$uri = app('templated.uri.generator')->generate('route', ['{token}' => $request->token]);
// Modify headers/response based on $uri.
return $next($request);
}
Testing:
$mockGenerator = Mockery::mock(Rfc6570Generator::class);
$mockGenerator->shouldReceive('generate')
->with('route', ['{param}'])
->andReturn('/expected/uri');
$this->app->instance('templated.uri.generator', $mockGenerator);
How can I help you explore Laravel packages today?