|
@@ -1,16 +1,25 @@
|
|
|
Batch actions
|
|
|
=============
|
|
|
|
|
|
-Batch actions are actions triggered on a set of selected models (all of them or only a specific subset).
|
|
|
+Batch actions are actions triggered on a set of selected objects. By default
|
|
|
+Admins have a ``delete`` action which allows you to remove several entries at once.
|
|
|
|
|
|
Defining new actions
|
|
|
--------------------
|
|
|
|
|
|
-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.
|
|
|
+To create a new custom batch action which appears in the list view follow these steps:
|
|
|
|
|
|
-Override the ``getBatchActions`` from your ``Admin`` class to define custom batch actions.
|
|
|
-For example, we define here a new ``merge`` action.
|
|
|
+Override ``getBatchActions()`` in your ``Admin`` class to define the new batch actions
|
|
|
+by adding them to the $actions array. Each entry has two settings:
|
|
|
+
|
|
|
+- **label**: The name to use when offering this option to users, should be passed through the translator
|
|
|
+- **ask_confirmation**: defaults to true and means that the user will be asked for confirmation before the batch action is processed
|
|
|
+
|
|
|
+For example, lets define a new ``merge`` action which takes a number of source items and
|
|
|
+merges them onto a single target item. It should only be available when two conditions are met:
|
|
|
+
|
|
|
+- the EDIT and DELETE routes exist for this Admin (have not been disabled)
|
|
|
+- the logged in administrator has EDIT and DELETE permissions
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
@@ -20,15 +29,17 @@ For example, we define here a new ``merge`` action.
|
|
|
|
|
|
public function getBatchActions()
|
|
|
{
|
|
|
- // retrieve the default (currently only the delete action) actions
|
|
|
+ // retrieve the default batch actions (currently only delete)
|
|
|
$actions = parent::getBatchActions();
|
|
|
|
|
|
- // check user permissions
|
|
|
- if($this->hasRoute('edit') && $this->isGranted('EDIT') && $this->hasRoute('delete') && $this->isGranted('DELETE')){
|
|
|
- $actions['merge']=[
|
|
|
- 'label' => $this->trans('action_merge', array(), 'SonataAdminBundle'),
|
|
|
- 'ask_confirmation' => true // If true, a confirmation will be asked before performing the action
|
|
|
- ];
|
|
|
+ if (
|
|
|
+ $this->hasRoute('edit') && $this->isGranted('EDIT') &&
|
|
|
+ $this->hasRoute('delete') && $this->isGranted('DELETE')
|
|
|
+ ) {
|
|
|
+ $actions['merge'] = array(
|
|
|
+ 'label' => $this->trans('action_merge', array(), 'SonataAdminBundle'),
|
|
|
+ 'ask_confirmation' => true
|
|
|
+ );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -39,24 +50,24 @@ For example, we define here a new ``merge`` action.
|
|
|
(Optional) Overriding the batch selection template
|
|
|
--------------------------------------------------
|
|
|
|
|
|
-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.
|
|
|
+A merge action requires two kind of selection: a set of source objects to merge from
|
|
|
+and a target object to merge into. By default, batch_actions only let you select one set
|
|
|
+of objects to manipulate. We can override this behavior by changing our list template
|
|
|
+(``list__batch.html.twig``) and adding a radio button to choose the target object.
|
|
|
|
|
|
.. code-block:: html+jinja
|
|
|
|
|
|
{# in Acme/ProjectBundle/Resources/views/CRUD/list__batch.html.twig #}
|
|
|
+ {# See SonataAdminBundle:CRUD:list__batch.html.twig for the current default template #}
|
|
|
|
|
|
+ {% extends admin.getTemplate('base_list_field') %}
|
|
|
|
|
|
- {# See SonataAdminBundle:CRUD:list__batch.html.twig for the current default template #}
|
|
|
- <td class="sonata-ba-list-field sonata-ba-list-field-batch">
|
|
|
+ {% block field %}
|
|
|
<input type="checkbox" name="idx[]" value="{{ admin.id(object) }}" />
|
|
|
|
|
|
{# the new radio #}
|
|
|
<input type="radio" name="targetId" value="{{ admin.id(object) }}" />
|
|
|
- </td>
|
|
|
+ {% endblock %}
|
|
|
|
|
|
|
|
|
And add this:
|
|
@@ -64,35 +75,39 @@ And add this:
|
|
|
.. code-block:: php
|
|
|
|
|
|
<?php
|
|
|
-
|
|
|
- // In Acme/ProjectBundle/AcmeProjectBundle.php
|
|
|
+ // Acme/ProjectBundle/AcmeProjectBundle.php
|
|
|
|
|
|
public function getParent()
|
|
|
{
|
|
|
return 'SonataAdminBundle';
|
|
|
}
|
|
|
|
|
|
+See the [Symfony bundle overriding mechanism](http://symfony.com/doc/current/cookbook/bundles/inheritance.html)
|
|
|
+for further explanation of overriding bundle templates.
|
|
|
+
|
|
|
|
|
|
(Optional) Overriding the default relevancy check function
|
|
|
----------------------------------------------------------
|
|
|
|
|
|
-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 :
|
|
|
+By default, batch actions are not executed if no object was selected, and the user is notified of
|
|
|
+this lack of selection. If your custom batch action needs more complex logic to determine if
|
|
|
+an action can be performed or not, just define a ``batchAction<MyAction>IsRelevant`` method
|
|
|
+(e.g. ``batchActionMergeIsRelevant``) in your ``CRUDController`` class. This check is performed
|
|
|
+before the user is asked for confirmation, to make sure there is actually something to confirm.
|
|
|
+
|
|
|
+This method may return three different values:
|
|
|
|
|
|
- ``true``: The batch action is relevant and can be applied.
|
|
|
- - 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.
|
|
|
- ``false``: Same as above, with the default "action aborted, no model selected" notification message.
|
|
|
+ - 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 a message displayed to the user.
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
- // In Acme/Controller/CRUDController.php
|
|
|
+ // In Acme/ProjectBundle/Controller/CRUDController.php
|
|
|
|
|
|
- public function batchActionMergeIsRelevant(array $normalizedSelectedIds, $allEntitiesSelected)
|
|
|
+ public function batchActionMergeIsRelevant(array $selectedIds, $allEntitiesSelected)
|
|
|
{
|
|
|
// here you have access to all POST parameters, if you use some custom ones
|
|
|
// POST parameters are kept even after the confirmation page.
|
|
@@ -103,7 +118,7 @@ is actually something to confirm. This method may return three different values
|
|
|
return 'flash_batch_merge_no_target';
|
|
|
}
|
|
|
|
|
|
- $normalizedTargetId = $parameterBag->get('targetId');
|
|
|
+ $targetId = $parameterBag->get('targetId');
|
|
|
|
|
|
// if all entities are selected, a merge can be done
|
|
|
if ($allEntitiesSelected) {
|
|
@@ -111,35 +126,35 @@ is actually something to confirm. This method may return three different values
|
|
|
}
|
|
|
|
|
|
// filter out the target from the selected models
|
|
|
- $normalizedSelectedIds = array_filter($normalizedSelectedIds,
|
|
|
- function($normalizedSelectedId) use($normalizedTargetId){
|
|
|
- return $normalizedSelectedId !== $normalizedTargetId;
|
|
|
+ $selectedIds = array_filter($selectedIds,
|
|
|
+ function($selectedId) use($targetId){
|
|
|
+ return $selectedId !== $targetId;
|
|
|
}
|
|
|
);
|
|
|
|
|
|
// if at least one but not the target model is selected, a merge can be done.
|
|
|
- return count($normalizedSelectedIds) > 0;
|
|
|
+ return count($selectedIds) > 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
Define the core action logic
|
|
|
----------------------------
|
|
|
|
|
|
-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``.
|
|
|
+The method ``batchAction<MyAction>`` will be executed to process your batch. The selected
|
|
|
+objects are passed to this method through a query argument which can be used to retrieve 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``.
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
- // In Acme/Controller/CRUDController.php
|
|
|
+ // In Acme/ProjectBundle/Controller/CRUDController.php
|
|
|
|
|
|
public function batchActionMerge(ProxyQueryInterface $selectedModelQuery)
|
|
|
{
|
|
|
- if ($this->admin->isGranted('EDIT') === false || $this->admin->isGranted('DELETE') === false)
|
|
|
+ if (!$this->admin->isGranted('EDIT') || !$this->admin->isGranted('DELETE'))
|
|
|
{
|
|
|
throw new AccessDeniedException();
|
|
|
}
|
|
@@ -152,7 +167,9 @@ passed query is ``null``.
|
|
|
if( $target === null){
|
|
|
$this->addFlash('sonata_flash_info', 'flash_batch_merge_no_target');
|
|
|
|
|
|
- return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
|
|
|
+ return new RedirectResponse(
|
|
|
+ $this->admin->generateUrl('list',$this->admin->getFilterParameters())
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
$selectedModels = $selectedModelQuery->execute();
|
|
@@ -168,10 +185,14 @@ passed query is ``null``.
|
|
|
} catch (\Exception $e) {
|
|
|
$this->addFlash('sonata_flash_error', 'flash_batch_merge_error');
|
|
|
|
|
|
- return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
|
|
|
+ return new RedirectResponse(
|
|
|
+ $this->admin->generateUrl('list',$this->admin->getFilterParameters())
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
$this->addFlash('sonata_flash_success', 'flash_batch_merge_success');
|
|
|
|
|
|
- return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
|
|
|
+ return new RedirectResponse(
|
|
|
+ $this->admin->generateUrl('list',$this->admin->getFilterParameters())
|
|
|
+ );
|
|
|
}
|