backend, Locastic Mar 17

Symfony Routing component – Customize URL Generation

2 min read –
symfony_blog_stephane_feature2

It all started with a small enhancement while developing some features on a Sylius eCommerce project. I came across a feature that really made me think hard about how to solve the problem.

The demand was pretty simple: “Being able to set a URL in Admin panel for a given entity” and each time we generate a route for this entity, if the URL is filled, it generates link to it instead of original resource.

How do you manage it in a Symfony project?

Well, the first idea that came to my mind was: let’s override each path generation in Twig/PHP and use a custom service. It could have worked but can you imagine the amount of work to override each path generation?

The Router

So while digging it I (re)discovered a component we all use, yet we maybe don’t really master – The Router.

Just to make a quick review of its purposes :

  • Generate URLs from route declaration
  • Match URL to a route

OK. Fair enough. About the “Match URL” part, this is not our concern right now, since the URL we want will perhaps be on another domain.

But let’s have a look at the “Generate URL from route” part.

It’s declared in “Symfony\Component\Routing\Generator\UrlGeneratorInterface” and its purpose is to parse all your declaration (whatever the format used) and check which one matches in order to generate the associated URL.
That is clearly where I have to do my cooking.

Then here we are! With a proper service decorator, you can easily add your custom behavior to this service and let’s say: intercept a specific route name then fetch in DB its information and maybe change the URL generated.

… and how does it look like?

public function generate(
$name,
$parameters = [],
$absolute = UrlGeneratorInterface::ABSOLUTE_PATH
): string {
if ('sylius_shop_product_index' === $name) {
$redirectRoute = $this->getTaxonRedirectRoute($parameters);

if (null !== $redirectRoute) {
return $redirectRoute;
}
}

return $this->router->generate($name, $parameters, $absolute);
}

In this case, I’m catching the ‘sylius_shop_product_index’ routes before they are generated. Then in the ‘getTaxonRedirectRoute()’ method, I’m checking if the taxon that has been given in parameters has its URL field filled. And if it has I’m simply returning it. Otherwise, I’m falling back to the default behavior of the router.

From now on, each call to the router, whether they are made via PHP or via Twig’s path() function, the custom generation will be called – great, isn’t it? Feel free to share your thoughts about the method.