recipe_custom_action.rst 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. Creating a Custom Admin Action
  2. ==============================
  3. This is a full working example of creating a custom list action for SonataAdmin.
  4. The example is based on an existing ``CarAdmin`` class in an ``AcmeDemoBundle``. It is
  5. assumed you already have an admin service up and running.
  6. The recipe
  7. ----------
  8. SonataAdmin provides a very straight-forward way of adding your own custom actions.
  9. To do this we need to:
  10. - extend the ``SonataAdmin:CRUD`` Controller and tell our admin class to use it
  11. - create the custom action in our Controller
  12. - create a template to show the action in the list view
  13. - add the route and the new action in the Admin class
  14. Extending the Admin Controller
  15. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  16. First you need to create your own Controller extending the one from SonataAdmin
  17. .. code-block:: php
  18. <?php
  19. // src/Acme/DemoBundle/Controller/CRUDController.php
  20. namespace Acme\DemoBundle\Controller;
  21. use Sonata\AdminBundle\Controller\CRUDController as Controller;
  22. class CRUDController extends Controller
  23. {
  24. // ...
  25. }
  26. Admin classes by default use the ``SonataAdmin:CRUD`` controller, this is the third parameter
  27. of an admin service definition, you need to change it to your own.
  28. Either by using XML:
  29. .. code-block:: xml
  30. <!-- src/Acme/DemoBundle/Resources/config/admin.xml -->
  31. ...
  32. <service id="acme.demo.admin.car" class="Acme\DemoBundle\Admin\CarAdmin">
  33. <tag name="sonata.admin" manager_type="orm" group="Demo" label="Car" />
  34. <argument />
  35. <argument>Acme\DemoBundle\Entity\Car</argument>
  36. <argument>AcmeDemoBundle:CRUD</argument>
  37. ...
  38. </service>
  39. ...
  40. Or by overwriting the configuration in your ``config.yml``:
  41. .. code-block:: yaml
  42. # app/config/config.yml
  43. services:
  44. acme.demo.admin.car:
  45. class: Acme\DemoBundle\Admin\CarAdmin
  46. tags:
  47. - { name: sonata.admin, manager_type: orm, group: Demo, label: Car }
  48. arguments:
  49. - null
  50. - Acme\DemoBundle\Entity\Car
  51. - AcmeDemoBundle:CRUD
  52. For more information about service configuration please refer to Step 3 of :doc:`../reference/getting_started`
  53. Create the custom action in your Controller
  54. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  55. Now it is time to actually create your custom action here, for this example I chose
  56. to implement a ``clone`` action.
  57. .. code-block:: php
  58. <?php // src/Acme/DemoBundle/Controller/CRUDController.php
  59. namespace Acme\DemoBundle\Controller;
  60. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  61. use Sonata\AdminBundle\Controller\CRUDController as Controller;
  62. use Symfony\Component\HttpFoundation\RedirectResponse;
  63. class CRUDController extends Controller
  64. {
  65. public function cloneAction()
  66. {
  67. $object = $this->admin->getSubject();
  68. if (!$object) {
  69. throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
  70. }
  71. $clonedObject = clone $object; // Careful, you may need to overload the __clone method of your object
  72. // to set its id to null
  73. $clonedObject->setName($object->getName()." (Clone)");
  74. $this->admin->create($clonedObject);
  75. $this->addFlash('sonata_flash_success', 'Cloned successfully');
  76. return new RedirectResponse($this->admin->generateUrl('list'));
  77. }
  78. }
  79. Here we first get the id of the object, see if it exists then clone it and insert the clone
  80. as a new object. Finally we set a flash message indicating success and redirect to the list view.
  81. Using template in new controller
  82. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  83. If you want to render something here you can create new template anywhere, extend sonata layout
  84. and use `sonata_admin_content` block.
  85. .. code-block:: html+jinja
  86. {% extends 'SonataAdminBundle::standard_layout.html.twig' %}
  87. {% block sonata_admin_content %}
  88. Your content here
  89. {% endblock %}
  90. Create a template for the new action
  91. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  92. You need to tell SonataAdmin how to render your new action. You do that by
  93. creating a ``list__action_clone.html.twig`` in the namespace of your custom
  94. Admin Controller.
  95. .. code-block:: html+jinja
  96. {# src/Acme/DemoBundle/Resources/views/CRUD/list__action_clone.html.twig #}
  97. <a class="btn btn-sm" href="{{ admin.generateObjectUrl('clone', object) }}">clone</a>
  98. Right now ``clone`` is not a known route, we define it in the next step.
  99. Bringing it all together
  100. ^^^^^^^^^^^^^^^^^^^^^^^^
  101. What is left now is actually adding your custom action to the admin class.
  102. You have to add the new route in ``configureRoutes``:
  103. .. code-block:: php
  104. protected function configureRoutes(RouteCollection $collection)
  105. {
  106. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  107. }
  108. This gives us a route like ``../admin/sonata/demo/car/1/clone``.
  109. You could also just write ``$collection->add('clone');`` to get a route like ``../admin/sonata/demo/car/clone?id=1``
  110. Next we have to add the action in ``configureListFields`` specifying the template we created.
  111. .. code-block:: php
  112. protected function configureListFields(ListMapper $listMapper)
  113. {
  114. $listMapper
  115. // other fields...
  116. ->add('_action', 'actions', array(
  117. 'actions' => array(
  118. 'Clone' => array(
  119. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  120. )
  121. )
  122. ))
  123. ;
  124. }
  125. The full ``CarAdmin.php`` example looks like this:
  126. .. code-block:: php
  127. <?php
  128. // src/Acme/DemoBundle/Admin/CarAdmin.php
  129. namespace Acme\DemoBundle\Admin;
  130. // ...
  131. use Sonata\AdminBundle\Route\RouteCollection;
  132. class CarAdmin extends Admin
  133. {
  134. // ...
  135. protected function configureListFields(ListMapper $listMapper)
  136. {
  137. $listMapper
  138. ->addIdentifier('name')
  139. ->add('engine')
  140. ->add('rescueEngine')
  141. ->add('createdAt')
  142. ->add('_action', 'actions', array(
  143. 'actions' => array(
  144. 'Clone' => array(
  145. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  146. )
  147. )
  148. ));
  149. }
  150. protected function configureRoutes(RouteCollection $collection)
  151. {
  152. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  153. }
  154. }