123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- Creating a Custom Admin Action
- ==============================
- This is a full working example of creating a custom list action for SonataAdmin.
- The example is based on an existing ``CarAdmin`` class in an ``AppBundle``.
- It is assumed you already have an admin service up and running.
- The recipe
- ----------
- SonataAdmin provides a very straight-forward way of adding your own custom actions.
- To do this we need to:
- - extend the ``SonataAdmin:CRUD`` Controller and tell our admin class to use it
- - create the custom action in our Controller
- - create a template to show the action in the list view
- - add the route and the new action in the Admin class
- Extending the Admin Controller
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- First you need to create your own Controller extending the one from SonataAdmin
- .. code-block:: php
- <?php
- // src/AppBundle/Controller/CRUDController.php
- namespace AppBundle\Controller;
- use Sonata\AdminBundle\Controller\CRUDController as Controller;
- class CRUDController extends Controller
- {
- // ...
- }
- Admin classes by default use the ``SonataAdmin:CRUD`` controller, this is the third parameter
- of an admin service definition, you need to change it to your own.
- Register the Admin as a Service
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Either by using XML:
- .. code-block:: xml
- <!-- src/AppBundle/Resources/config/admin.xml -->
- <service id="app.admin.car" class="AppBundle\Admin\CarAdmin">
- <tag name="sonata.admin" manager_type="orm" group="Demo" label="Car" />
- <argument />
- <argument>AppBundle\Entity\Car</argument>
- <argument>AppBundle:CRUD</argument>
- </service>
- or by adding it to your ``admin.yml``:
- .. code-block:: yaml
- # src/AppBundle/Resources/config/admin.yml
- services:
- app.admin.car:
- class: AppBundle\Admin\CarAdmin
- tags:
- - { name: sonata.admin, manager_type: orm, group: Demo, label: Car }
- arguments:
- - null
- - AppBundle\Entity\Car
- - AppBundle:CRUD
- public: true
- For more information about service configuration please refer to Step 3 of :doc:`../reference/getting_started`
- Create the custom action in your Controller
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Now it is time to actually create your custom action here, for this example I chose
- to implement a ``clone`` action.
- .. code-block:: php
- <?php
- // src/AppBundle/Controller/CRUDController.php
- namespace AppBundle\Controller;
- use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
- use Sonata\AdminBundle\Controller\CRUDController as Controller;
- use Symfony\Component\HttpFoundation\RedirectResponse;
- class CRUDController extends Controller
- {
- /**
- * @param $id
- */
- public function cloneAction($id)
- {
- $object = $this->admin->getSubject();
- if (!$object) {
- throw new NotFoundHttpException(sprintf('unable to find the object with id: %s', $id));
- }
- // Be careful, you may need to overload the __clone method of your object
- // to set its id to null !
- $clonedObject = clone $object;
- $clonedObject->setName($object->getName().' (Clone)');
- $this->admin->create($clonedObject);
- $this->addFlash('sonata_flash_success', 'Cloned successfully');
- return new RedirectResponse($this->admin->generateUrl('list'));
- // if you have a filtered list and want to keep your filters after the redirect
- // return new RedirectResponse($this->admin->generateUrl('list', $this->admin->getFilterParameters()));
- }
- }
- Here we first get the object, see if it exists then clone it and insert the clone
- as a new object. Finally we set a flash message indicating success and redirect to the list view.
- If you want to add the current filter parameters to the redirect url you can add them to the `generateUrl` method:
- .. code-block:: php
- return new RedirectResponse($this->admin->generateUrl('list', array('filter' => $this->admin->getFilterParameters())));
- Using template in new controller
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- If you want to render something here you can create new template anywhere, extend sonata layout
- and use `sonata_admin_content` block.
- .. code-block:: html+jinja
- {% extends 'SonataAdminBundle::standard_layout.html.twig' %}
- {% block sonata_admin_content %}
- Your content here
- {% endblock %}
- Create a template for the new action
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- You need to tell SonataAdmin how to render your new action. You do that by
- creating a ``list__action_clone.html.twig`` in the namespace of your custom
- Admin Controller.
- .. code-block:: html+jinja
- {# src/AppBundle/Resources/views/CRUD/list__action_clone.html.twig #}
- <a class="btn btn-sm" href="{{ admin.generateObjectUrl('clone', object) }}">clone</a>
- Right now ``clone`` is not a known route, we define it in the next step.
- Bringing it all together
- ^^^^^^^^^^^^^^^^^^^^^^^^
- What is left now is actually adding your custom action to the admin class.
- You have to add the new route in ``configureRoutes``:
- .. code-block:: php
- // ...
- use Sonata\AdminBundle\Route\RouteCollection;
- protected function configureRoutes(RouteCollection $collection)
- {
- $collection->add('clone', $this->getRouterIdParameter().'/clone');
- }
- This gives us a route like ``../admin/app/car/1/clone``.
- You could also just write ``$collection->add('clone');`` to get a route like ``../admin/app/car/clone?id=1``
- Next we have to add the action in ``configureListFields`` specifying the template we created.
- .. code-block:: php
- protected function configureListFields(ListMapper $listMapper)
- {
- $listMapper
- // other fields...
- ->add('_action', null, array(
- 'actions' => array(
- // ...
- 'clone' => array(
- 'template' => 'AppBundle:CRUD:list__action_clone.html.twig'
- )
- )
- ))
- ;
- }
- The full ``CarAdmin.php`` example looks like this:
- .. code-block:: php
- <?php
- // src/AppBundle/Admin/CarAdmin.php
- namespace AppBundle\Admin;
- use Sonata\AdminBundle\Admin\AbstractAdmin;
- use Sonata\AdminBundle\Datagrid\DatagridMapper;
- use Sonata\AdminBundle\Datagrid\ListMapper;
- use Sonata\AdminBundle\Form\FormMapper;
- use Sonata\AdminBundle\Route\RouteCollection;
- use Sonata\AdminBundle\Show\ShowMapper;
- class CarAdmin extends AbstractAdmin
- {
- protected function configureRoutes(RouteCollection $collection)
- {
- $collection->add('clone', $this->getRouterIdParameter().'/clone');
- }
- protected function configureDatagridFilters(DatagridMapper $datagridMapper)
- {
- // ...
- }
- protected function configureFormFields(FormMapper $formMapper)
- {
- // ...
- }
- protected function configureListFields(ListMapper $listMapper)
- {
- $listMapper
- ->addIdentifier('name')
- ->add('engine')
- ->add('rescueEngine')
- ->add('createdAt')
- ->add('_action', null, array(
- 'actions' => array(
- 'show' => array(),
- 'edit' => array(),
- 'delete' => array(),
- 'clone' => array(
- 'template' => 'AppBundle:CRUD:list__action_clone.html.twig'
- )
- )
- ));
- }
- protected function configureShowFields(ShowMapper $showMapper)
- {
- // ...
- }
- }
- .. note::
- If you want to render a custom controller action in a template by using the
- render function in twig you need to add ``_sonata_admin`` as an attribute. For
- example; ``{{ render(controller('AppBundle:XxxxCRUD:comment', {'_sonata_admin':
- 'sonata.admin.xxxx' })) }}``. This has to be done because the moment the
- rendering should happen the routing, which usually sets the value of this
- parameter, is not involved at all, and then you will get an error "There is no
- _sonata_admin defined for the controller
- AppBundle\Controller\XxxxCRUDController and the current route ' '."
|