recipe_custom_action.rst 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 your 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:`getting_started`
  53. Create the custom action in your Controller
  54. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  55. Now it's 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;
  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 new object. Finally we set a flash message indicating success and redirect to the list view.
  81. Create a template for the new action
  82. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  83. You need to tell SonataAdmin how to render your new action. You do that by creating a ``list__action_clone.html.twig`` in the
  84. namespace of your custom Admin Controller.
  85. .. code-block:: twig
  86. {# src/Acme/DemoBundle/Resources/views/CRUD/list__action_clone.html.twig #}
  87. <a href="{{ admin.generateObjectUrl('clone', object) }}">clone</a>
  88. Right now ``clone`` is not a known route, we define it in the next step.
  89. Bringing it all together
  90. ^^^^^^^^^^^^^^^^^^^^^^^^
  91. What's left now is actually adding your custom action to the admin class.
  92. You have to add the new route in ``configureRoutes``:
  93. .. code-block:: php
  94. protected function configureRoutes(RouteCollection $collection)
  95. {
  96. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  97. }
  98. This gives us a route like ``../admin/sonata/demo/car/1/clone``.
  99. You could also just do ``$collection->add('clone');`` to get a route like ``../admin/sonata/demo/car/clone?id=1``
  100. Next we have to add the action in ``configureListFields`` specifying the template we created.
  101. .. code-block:: php
  102. protected function configureListFields(ListMapper $listMapper)
  103. {
  104. $listMapper
  105. // other fields...
  106. ->add('_action', 'actions', array(
  107. 'actions' => array(
  108. 'Clone' => array(
  109. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  110. )
  111. )
  112. ))
  113. ;
  114. }
  115. The full example ``CarAdmin.php`` looks like this:
  116. .. code-block:: php
  117. <?php
  118. // src/Acme/DemoBundle/Admin/CarAdmin.php
  119. namespace Acme\DemoBundle\Admin;
  120. // ...
  121. use Sonata\AdminBundle\Route\RouteCollection;
  122. class CarAdmin extends Admin
  123. {
  124. // ...
  125. protected function configureListFields(ListMapper $listMapper)
  126. {
  127. $listMapper
  128. ->addIdentifier('name')
  129. ->add('engine')
  130. ->add('rescueEngine')
  131. ->add('createdAt')
  132. ->add('_action', 'actions', array(
  133. 'actions' => array(
  134. 'Clone' => array(
  135. 'template' => 'AcmeDemoBundle:CRUD:list__action_clone.html.twig'
  136. )
  137. )
  138. ));
  139. }
  140. protected function configureRoutes(RouteCollection $collection)
  141. {
  142. $collection->add('clone', $this->getRouterIdParameter().'/clone');
  143. }
  144. }