recipe_custom_action.rst 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. $id = $this->get('request')->get($this->admin->getIdParameter());
  68. $object = $this->admin->getObject($id);
  69. if (!$object) {
  70. throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
  71. }
  72. $clonedObject = clone $object; // Careful, you may need to overload the __clone method of your object
  73. // to set its id to null
  74. $clonedObject->setName($object->getName()." (Clone)");
  75. $this->admin->create($clonedObject);
  76. $this->addFlash('sonata_flash_success', 'Cloned successfully');
  77. return new RedirectResponse($this->admin->generateUrl('list'));
  78. }
  79. }
  80. Here we first get the id of the object, see if it exists then clone it and insert the clone
  81. as a new object. Finally we set a flash message indicating success and redirect to the list view.
  82. Create a template for the new action
  83. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  84. You need to tell SonataAdmin how to render your new action. You do that by
  85. creating a ``list__action_clone.html.twig`` in the namespace of your custom
  86. Admin Controller.
  87. .. code-block:: html+jinja
  88. {# src/Acme/DemoBundle/Resources/views/CRUD/list__action_clone.html.twig #}
  89. <a class="btn btn-sm" href="{{ admin.generateObjectUrl('clone', object) }}">clone</a>
  90. Right now ``clone`` is not a known route, we define it in the next step.
  91. Bringing it all together
  92. ^^^^^^^^^^^^^^^^^^^^^^^^
  93. What is left now is actually adding your custom action to the admin class.
  94. You have to add the new route in ``configureRoutes``:
  95. .. code-block:: php
  96. protected function configureRoutes(RouteCollection $collection)
  97. {
  98. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  99. }
  100. This gives us a route like ``../admin/sonata/demo/car/1/clone``.
  101. You could also just write ``$collection->add('clone');`` to get a route like ``../admin/sonata/demo/car/clone?id=1``
  102. Next we have to add the action in ``configureListFields`` specifying the template we created.
  103. .. code-block:: php
  104. protected function configureListFields(ListMapper $listMapper)
  105. {
  106. $listMapper
  107. // other fields...
  108. ->add('_action', 'actions', array(
  109. 'actions' => array(
  110. 'Clone' => array(
  111. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  112. )
  113. )
  114. ))
  115. ;
  116. }
  117. The full ``CarAdmin.php`` example looks like this:
  118. .. code-block:: php
  119. <?php
  120. // src/Acme/DemoBundle/Admin/CarAdmin.php
  121. namespace Acme\DemoBundle\Admin;
  122. // ...
  123. use Sonata\AdminBundle\Route\RouteCollection;
  124. class CarAdmin extends Admin
  125. {
  126. // ...
  127. protected function configureListFields(ListMapper $listMapper)
  128. {
  129. $listMapper
  130. ->addIdentifier('name')
  131. ->add('engine')
  132. ->add('rescueEngine')
  133. ->add('createdAt')
  134. ->add('_action', 'actions', array(
  135. 'actions' => array(
  136. 'Clone' => array(
  137. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  138. )
  139. )
  140. ));
  141. }
  142. protected function configureRoutes(RouteCollection $collection)
  143. {
  144. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  145. }
  146. }