Routing
=======
The default routes used in the CRUD controller are accessible through the
``Admin`` class.
The ``Admin`` class contains two routing methods:
* ``getRoutes()``: Returns the available routes;
* ``generateUrl($name, $options)``: Generates the related routes.
Routing Definition
------------------
Route names
^^^^^^^^^^^
You can override the ``generateBaseRouteName()`` method inside your ``Admin`` class.
This represents the route prefix, to which an underscore and the action name will
be added to generate the actual route names::
// src/Admin/PostAdmin.php
final class PostAdmin extends AbstractAdmin
{
protected function generateBaseRouteName(bool $isChildAdmin = false): string
{
return 'sonata_post';
}
// will result in routes named:
// sonata_post_list
// sonata_post_create
// etc..
// ...
}
.. note::
This is the internal *name* given to a route (it has nothing to do with the route's visible *URL*).
By default the Admin will generate the route name for you, based on
the following format: 'admin_vendor_bundlename_entityname' so you will have
route names for your actions like 'admin_vendor_bundlename_entityname_list'.
If the Admin fails to find a baseRouteName for your Admin class a ``RuntimeException``
will be thrown with a related message.
If the admin class is a child of another admin class the route name will
be prefixed by the parent route name, example::
// src/Admin/PostAdmin.php
// The parent admin class
final class PostAdmin extends AbstractAdmin
{
protected function generateBaseRouteName(bool $isChildAdmin = false): string
{
return 'sonata_post';
}
}
.. code-block:: php
// src/Admin/CommentAdmin.php
// The child admin class
final class CommentAdmin extends AbstractAdmin
{
protected function generateBaseRouteName(bool $isChildAdmin = false): string
{
return 'comment';
}
// will result in routes named :
// sonata_post_comment_list
// sonata_post_comment_create
// etc..
// ...
}
Route patterns (URLs)
^^^^^^^^^^^^^^^^^^^^^
You can override the ``generateBaseRoutePattern()`` method to set a custom URL for a given ``Admin`` class.
For example, to use ``http://yourdomain.com/admin/foo`` as the base URL for
the ``FooAdmin`` class (instead of the default of ``http://yourdomain.com/admin/vendor/bundle/foo``)
use the following code::
// src/Admin/FooAdmin.php
final class FooAdmin extends AbstractAdmin
{
protected function generateBaseRoutePattern(bool $isChildAdmin = false): string
{
return 'foo';
}
}
You will then have route URLs like ``http://yourdomain.com/admin/foo/list`` and
``http://yourdomain.com/admin/foo/1/edit``
If the admin class is a child of another admin class the route pattern will
be prefixed by the parent route pattern, example::
// src/Admin/PostAdmin.php
// The parent admin class
final class PostAdmin extends AbstractAdmin
{
protected function generateBaseRoutePattern(bool $isChildAdmin = false): string
{
return 'post';
}
// ...
}
.. code-block:: php
// src/Admin/CommentAdmin.php
// The child admin class
final class CommentAdmin extends AbstractAdmin
{
protected function generateBaseRoutePattern(bool $isChildAdmin = false): string
{
return 'comment';
}
// ...
}
For comment you will then have route URLs like ``http://yourdomain.com/admin/post/{postId}/comment/list`` and
``http://yourdomain.com/admin/post/{postId}/comment/{commentId}/edit``
Routing usage
-------------
Inside a CRUD template, a route for the current ``Admin`` class can be generated via
the admin variable's ``generateUrl()`` command:
.. code-block:: html+twig
List
.. code-block:: html+twig
List
Note that you do not need to provide the Admin's route prefix (``baseRouteName``) to
generate a URL for the current Admin, only the action name is needed.
To generate a URL to a different Admin, call the Symfony Twig function ``path``
with the Route Name:
.. code-block:: html+twig
Post List
Create a route
--------------
You can register new routes by defining them in your ``Admin`` class. Only Admin
routes should be registered this way.
The routes you define in this way are generated within your Admin's context, and
the only required parameter to ``add()`` is the action name. The second parameter
can be used to define the URL format to append to ``baseRoutePattern``, if not set
explicitly this defaults to the action name::
// src/Admin/MediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class MediaAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection->add('myCustom'); // Action gets added automatically
$collection->add('view', $this->getRouterIdParameter().'/view');
}
}
Make use of all route parameters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As the ``add`` method create a Symfony ``Route``, you can use all constructor arguments of the ``Route`` as parameters
in the ``add`` method to set additional settings like this::
// src/Admin/MediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class MediaAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection->add(
'custom_action',
$this->getRouterIdParameter().'/custom-action',
[],
[],
[],
'',
['https'],
['GET', 'POST']
);
}
}
Other steps needed to create your new action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In addition to defining the route for your new action you also need to create a
handler for it in your Controller. By default Admin classes use ``Sonata\AdminBundle\Controller\CRUDController``
as their controller, but this can be changed by altering the third argument when defining your Admin service.
For example, lets change the Controller for our MediaAdmin class to ``App\Controller\MediaCRUDController``:
.. code-block:: yaml
# config/services.yaml
app.admin.media:
class: App\Admin\MediaAdmin
tags:
- { name: sonata.admin, model_class: App\Entity\Page, controller: App\Controller\MediaCRUDController, manager_type: orm, label: 'Media' }
We now need to create our Controller, the easiest way is to extend the
basic Sonata CRUD controller::
// src/Controller/MediaCRUDController.php
namespace App\Controller;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\Response;
class MediaCRUDController extends CRUDController
{
public function myCustomAction(): Response
{
// your code here ...
}
}
Removing a route
----------------
Extending ``Sonata\AdminBundle\Admin\AbstractAdmin`` will give your Admin classes the following
default routes:
* batch
* create
* delete
* export
* edit
* list
* show
You can view all of the current routes defined for an Admin class by using the console to run
.. code-block:: bash
bin/console sonata:admin:explain <>
for example if your Admin is called sonata.admin.foo you would run
.. code-block:: bash
bin/console sonata:admin:explain app.admin.foo
Sonata internally checks for the existence of a route before linking to it. As a result, removing a
route will prevent links to that action from appearing in the administrative interface. For example,
removing the 'create' route will prevent any links to "Add new" from appearing.
Removing a single route
^^^^^^^^^^^^^^^^^^^^^^^
Any single registered route can be removed by name::
// src/Admin/MediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class MediaAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection->remove('delete');
}
}
Removing all routes except named ones
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you want to disable all default Sonata routes except few allowed ones, you can use
the ``clearExcept()`` method. This method accepts an array of routes you want to keep active::
// src/Admin/MediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class MediaAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
// Only `list` and `edit` route will be active
$collection->clearExcept(['list', 'edit']);
// You can also pass a single string argument
$collection->clearExcept('list');
}
}
Removing all routes
^^^^^^^^^^^^^^^^^^^
If you want to remove all default routes, you can use ``clear()`` method::
// src/Admin/MediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class MediaAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
// All routes are removed
$collection->clear();
}
}
Removing routes only when an Admin is embedded
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To prevent some routes from being available when one Admin is embedded inside another one
(e.g. to remove the "add new" option when you embed ``TagAdmin`` within ``PostAdmin``) you
can use ``hasParentFieldDescription()`` to detect this case and remove the routes::
// src/Admin/TagAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class TagAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
// prevent display of "Add new" when embedding this form
if ($this->hasParentFieldDescription()) {
$collection->remove('create');
}
}
}
Restoring a single route
^^^^^^^^^^^^^^^^^^^^^^^^
Any previously removed route can be restored by name::
// src/Admin/DeletableMediaAdmin.php
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class DeletableMediaAdmin extends MediaAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection->restore('delete');
}
}
Persistent parameters
---------------------
In some cases, the interface might be required to pass the same parameters
across the different ``Admin``'s actions. Instead of setting them in the
template or doing other weird hacks, you can define a ``configurePersistentParameters()``
method. This method will be used when a link is being generated::
// src/Admin/MediaAdmin.php
final class MediaAdmin extends AbstractAdmin
{
protected function configurePersistentParameters(): array
{
if (!$this->getRequest()) {
return [];
}
return [
'provider' => $this->getRequest()->get('provider'),
'context' => $this->getRequest()->get('context', 'default'),
];
}
}
If you then call ``$admin->generateUrl('create')`` somewhere, the generated
URL looks like this: ``/admin/module/create?context=default``
Changing the default route in a List Action
-------------------------------------------
Usually the identifier column of a list action links to the edit screen. To change the
list action's links to point to a different action, set the ``route`` option in your call to
``ListMapper::addIdentifier()``. For example, to link to show instead of edit::
// src/Admin/PostAdmin.php
final class PostAdmin extends AbstractAdmin
{
protected function configureListFields(ListMapper $list): void
{
$list
->addIdentifier('name', null, [
'route' => [
'name' => 'show'
]
]);
}
}