webfactory/object-routing-bundle
Symfony bundle for object-oriented routing: map request parameters to domain objects and generate URLs directly from objects via configurable route providers, keeping controllers thin and URL logic reusable.
composer require webfactory/object-routing-bundle. If you are not using Symfony Flex, register the bundle class from the package README in config/bundles.php.README.md, DependencyInjection/Configuration.php, and Resources/config/services.*. This bundle is thin; most behavior lives in the underlying webfactory/object-routing library. Read that package’s README and its router/mapper classes before writing integration code.post_show with {id}), map App\Entity\Post to that route, then generate links from the object itself.// src/Entity/Post.php
// Exact attribute/annotation name depends on the bundle version; confirm in the source.
#[ObjectRoute('post_show', ['id' => 'id'])]
class Post { ... }
// Controller: inject the object-aware router service, not necessarily Symfony's RouterInterface.
use Webfactory\ObjectRouting\ObjectRouterInterface; // check exact FQCN
public function show(Post $post, ObjectRouterInterface $objectRouter): Response
{
$url = $objectRouter->generate($post); // /posts/42
// ...
}
{# Exact helper name may differ; check the bundle's Twig extension. #}
<a href="{{ object_path(post) }}">{{ post.title }}</a>
route('posts.show', $post) and instead derive the route from the object itself. The win is largest when many templates and controllers link to the same domain objects.App\Routing\ObjectUrlGenerator that injects the bundle’s router and exposes generate(object $object, array $parameters = []): string. This keeps the rest of your codebase independent of the bundle’s API and makes it trivial to mock or replace later.Post, User, and Product objects becomes simple: iterate and call $objectUrlGenerator->generate($item). This is the clearest day-to-day use case.id), and pass locale, page, or tracking params at call time if the router supports a parameters argument:$url = $objectUrlGenerator->generate($post, ['page' => 2]);
UrlGeneratorInterface with the generated path.generate($post) returns /posts/42. Add one assertion per mapped class. This catches missing mappings before a template does.path('post_show', {id: post.id}) calls until the object route is proven. Avoid a big-bang migration across the whole app.#. Do not let a missing mapping break a whole page.$router->generate($post) works. Symfony’s RouterInterface::generate() is typed to accept a string route name. This bundle may decorate the router, but it may instead expose a separate object router service or Twig function. Check the service definition and Twig extension before choosing the call site.Attribute/ObjectRoute.php vs Annotation/ObjectRoute.php) and that your annotation reader is configured if you are on annotations.bin/console cache:clear and check the annotation reader cache in dev.object_path, object_url, or override path. If you override path, test every template that uses it; a global override can surprise other bundles.composer.json, read the source, and keep the wrapper service so you can replace it with ~50 lines of custom code if the bundle falls behind.webfactory/object-routing for the interface) if you need dynamic mappings, e.g., from a database or for third-party classes. Symfony service decoration is usually cleaner than forking.How can I help you explore Laravel packages today?