Skip to main content

Sylius Resource Bundle Routing Demystified

· 3 min read
Stephan Hochdörfer
Head of IT Business Operations

The Sylius Resource Bundle is using annotations to define the operations an entity supports. These operations will generate a Symfony routing configuration automatically.

While experimenting with the Resource Bundle and a custom Location entity some time ago, I ran into the following exception while trying to access the "locations/new" route to create a new Location entity:

404 Resource has not been found.

I was confused at first. Why does the Resource bundle want to return a resource when I am accessing the URL to create a new entity? That did not make sense to me.

I decided to check the generated routes to see if maybe I had messed up something. Thankfully, Symfony ships a debug:router command which shows you all the available routes in your application:

./bin/console debug:router | grep "location"

The command output showed the following result:

app_location_show             GET            ANY      ANY    /locations/{id}
app_location_index GET ANY ANY /locations
app_location_create GET|POST ANY ANY /locations/new
app_location_bulk_delete DELETE|POST ANY ANY /locations/bulk_delete
app_location_update GET|PUT|POST ANY ANY /locations/{id}/edit
app_location_delete DELETE|POST ANY ANY /locations/{id}/delete

The issue became clear: the order of routes in Symfony is crucial. Since app_location_show appears before app_location_create, Symfony evaluates the show route first. As a result, when it encounters the string "new" in the URL, it mistakenly interprets it as the id parameter for the show route. This leads to a 404 error, because the bundle is unable to find a database entry with an id of "new".

That means we have to change the order the routes are generated. But how?

The solution is straightforward: Change the order of the operation attributes. The order in which these attributes are listed determines the sequence of the generated routes. Through experimentation, I recommend the following attribute order:

<?php

namespace App\Entity;

use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\BulkDelete;
use Sylius\Resource\Metadata\Create;
use Sylius\Resource\Metadata\Delete;
use Sylius\Resource\Metadata\Index;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Resource\Metadata\Show;
use Sylius\Resource\Metadata\Update;
use Sylius\Resource\Model\ResourceInterface;

#[AsResource(
templatesDir: '@SyliusAdminUi/crud',
)]
#[Index]
#[Create]
#[BulkDelete]
#[Show]
#[Update]
#[Delete]
#[ORM\Entity]
#[ORM\Table(name: 'location')]
class Location implements ResourceInterface
{
// ...
}

I've used the same attribute order for many of my entities in several applications and haven't been running into any issues.