batch_actions.rst 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. Batch actions
  2. =============
  3. Batch actions are actions triggered on a set of selected models (all of them or only a specific subset).
  4. Defining new actions
  5. --------------------
  6. You can easily add some custom batch action in the list view. By default the ``delete`` action allows you to remove several entries at once.
  7. Override the ``getBatchActions`` from your ``Admin`` class to define custom batch actions. For example, we define here a new ``merge`` action.
  8. .. code-block:: php
  9. <?php
  10. // In your Admin class
  11. public function getBatchActions()
  12. {
  13. // retrieve the default (currently only the delete action) actions
  14. $actions = parent::getBatchActions();
  15. // check user permissions
  16. if($this->hasRoute('edit') && $this->isGranted('EDIT') && $this->hasRoute('delete') && $this->isGranted('DELETE')){
  17. $actions['merge']=[
  18. 'label' => $this->trans('action_merge', array(), 'SonataAdminBundle'),
  19. 'ask_confirmation' => true // If true, a confirmation will be asked before performing the action
  20. ];
  21. }
  22. return $actions;
  23. }
  24. (Optional) Overriding the batch selection template
  25. --------------------------------------------------
  26. Obviously, a merge action requires two kind of selection : a set of source model to merge into one target model. By default, this bundle only enable the user to select some model, but there is only one selection kind. Thus you will need to override the ``list__batch.html.twig`` template to display both a checkbox (source selection) and a radio (target selection) for each model row. See Symfony bundle overriding mechanism for further explanation.
  27. .. code-block:: html+jinja
  28. {# in Acme/ProjectBundle/Resources/views/CRUD/list__batch.html.twig #}
  29. {# See SonataAdminBundle:CRUD:list__batch.html.twig for the current default template #}
  30. <td class="sonata-ba-list-field sonata-ba-list-field-batch">
  31. <input type="checkbox" name="idx[]" value="{{ admin.id(object) }}" />
  32. {# the new radio #}
  33. <input type="radio" name="targetId" value="{{ admin.id(object) }}" />
  34. </td>
  35. And add this:
  36. .. code-block:: php
  37. <?php
  38. // In Acme/ProjectBundle/AcmeProjectBundle.php
  39. public function getParent()
  40. {
  41. return 'SonataAdminBundle';
  42. }
  43. (Optional) Overriding the default relevancy check function
  44. ----------------------------------------------------------
  45. By default, batch actions are not executed if no model was selected, and the user is notified of this lack of selection. If your custom batch action need some more complex logic to determine if an action can be performed or not, just define the ``batchActionMyActionIsRelevant`` method in your ``CRUDController`` class. This check is performed before any confirmation, to make sure there is actually something to confirm. This method may return three different values :
  46. - ``true``: The batch action is relevant and can be applied.
  47. - a string: The batch action is not relevant given the current request parameters (for example the ``target`` is missing for a ``merge`` action). The returned string is the message that inform the user why the action is aborted.
  48. - ``false``: Same as above, with the default "action aborted, no model selected" notification message.
  49. .. code-block:: php
  50. <?php
  51. // In Acme/Controller/CRUDController.php
  52. public function batchActionMergeIsRelevant(array $normalizedSelectedIds, $allEntitiesSelected)
  53. {
  54. // here you have access to all POST parameters, if you use some custom ones
  55. // POST parameters are kept even after the confirmation page.
  56. $parameterBag = $this->get('request')->request;
  57. // check that a target has been chosen
  58. if (!$parameterBag->has('targetId')) {
  59. return 'flash_batch_merge_no_target';
  60. }
  61. $normalizedTargetId = $parameterBag->get('targetId');
  62. // if all entities are selected, a merge can be done
  63. if ($allEntitiesSelected) {
  64. return true;
  65. }
  66. // filter out the target from the selected models
  67. $normalizedSelectedIds = array_filter($normalizedSelectedIds,
  68. function($normalizedSelectedId) use($normalizedTargetId){
  69. return $normalizedSelectedId !== $normalizedTargetId;
  70. }
  71. );
  72. // if at least one but not the target model is selected, a merge can be done.
  73. return count($normalizedSelectedIds) > 0;
  74. }
  75. Define the core action logic
  76. ----------------------------
  77. The method ``batchActionMyAction`` will be executed to achieve the core logic. The selected models are passed to the method through a query argument retrieving them. If for some reason it makes sense to perform your batch action without the default selection method (for example you defined another way, at template level, to select model at a lower granularity), the passed query is ``null``.
  78. .. code-block:: php
  79. <?php
  80. // In Acme/Controller/CRUDController.php
  81. public function batchActionMerge(ProxyQueryInterface $selectedModelQuery)
  82. {
  83. if ($this->admin->isGranted('EDIT') === false || $this->admin->isGranted('DELETE') === false)
  84. {
  85. throw new AccessDeniedException();
  86. }
  87. $request = $this->get('request');
  88. $modelManager = $this->admin->getModelManager();
  89. $target = $modelManager->find($this->admin->getClass(), $request->get('targetId'));
  90. if( $target === null){
  91. $this->get('session')->setFlash('sonata_flash_info', 'flash_batch_merge_no_target');
  92. return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
  93. }
  94. $selectedModels = $selectedModelQuery->execute();
  95. // do the merge work here
  96. try {
  97. foreach ($selectedModels as $selectedModel) {
  98. $modelManager->delete($selectedModel);
  99. }
  100. $modelManager->update($selectedModel);
  101. } catch (\Exception $e) {
  102. $this->get('session')->setFlash('sonata_flash_error', 'flash_batch_merge_error');
  103. return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
  104. }
  105. $this->get('session')->setFlash('sonata_flash_success', 'flash_batch_merge_success');
  106. return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
  107. }