From 3cd4ef76bd3fca8fc4c5df637c227104b80d49e1 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Thu, 3 Jun 2021 13:51:20 +0200 Subject: [PATCH] add batch actions to CRUD --- core/Controller/Admin/Crud/CrudController.php | 48 ++++++++++++ core/Crud/CrudConfiguration.php | 30 ++++++++ .../crud-controller/CrudController.tpl.php | 16 ++++ core/Resources/translations/messages.fr.yaml | 4 + .../views/admin/crud/index.html.twig | 74 ++++++++++++++++--- core/Twig/Extension/CrudExtension.php | 8 +- 6 files changed, 166 insertions(+), 14 deletions(-) diff --git a/core/Controller/Admin/Crud/CrudController.php b/core/Controller/Admin/Crud/CrudController.php index 2b2cd42..2443d0e 100644 --- a/core/Controller/Admin/Crud/CrudController.php +++ b/core/Controller/Admin/Crud/CrudController.php @@ -163,6 +163,54 @@ abstract class CrudController extends AdminController return $this->json([]); } + protected function doBatch(int $page = 1, RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session): Response + { + $configuration = $this->getConfiguration(); + $datas = $request->request->get('batch', []); + + $context = $datas['context'] ?? 'index'; + $target = $datas['target'] ?? null; + $action = $datas['action'] ?? null; + $token = $datas['_token'] ?? null; + $items = $datas['items'] ?? []; + $batchAction = $configuration->getBatchAction($context, $action); + + if (empty($context) || empty($action) || empty($target)) { + return $this->json([]); + } + + if (!$this->isCsrfTokenValid('batch', $token) || empty($batchAction)) { + $this->addFlash('warning', 'The form is not valid.'); + + return $this->json([]); + } + + $callback = $batchAction['callback']; + + $this->applySort($context, $query, $request); + $this->updateFilters($request, $session); + + $query->useFilters($this->filters); + + if ($target === 'selection') { + $isSelection = true; + $pager = $query->paginate($page, $configuration->getMaxPerPage($context)); + } else { + $isSelection = false; + $pager = $query->find(); + } + + foreach ($pager as $key => $entity) { + if (($isSelection && isset($items[$key + 1])) || !$isSelection) { + $callback($entity, $entityManager); + } + } + + $this->addFlash('success', 'Batch action done.'); + + return $this->json([]); + } + protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null): Response { $configuration = $this->getConfiguration(); diff --git a/core/Crud/CrudConfiguration.php b/core/Crud/CrudConfiguration.php index 45bdb03..451e337 100644 --- a/core/Crud/CrudConfiguration.php +++ b/core/Crud/CrudConfiguration.php @@ -14,6 +14,7 @@ class CrudConfiguration protected array $pageTitles = []; protected array $pageRoutes = []; protected array $actions = []; + protected array $batchActions = []; protected array $actionTitles = []; protected array $forms = []; protected array $formOptions = []; @@ -110,6 +111,35 @@ class CrudConfiguration return $this->actions[$page][$action] ?? $default; } + public function setBatchAction(string $page, string $action, string $label, callable $callback): self + { + if (!isset($this->actions[$page])) { + $this->batchActions[$page] = []; + } + + $this->batchActions[$page][$action] = [ + 'label' => $label, + 'callback' => $callback, + ]; + + return $this; + } + + public function getBatchActions(string $page) + { + return $this->batchActions[$page] ?? []; + } + + public function getBatchAction(string $page, string $action) + { + return $this->batchActions[$page][$action] ?? null; + } + + public function hasBatchAction(string $page) + { + return !empty($this->batchActions[$page]); + } + /* -- */ public function setActionTitle(string $page, string $action, string $title): self diff --git a/core/Resources/maker/crud-controller/CrudController.tpl.php b/core/Resources/maker/crud-controller/CrudController.tpl.php index fc054f5..6a97eb8 100644 --- a/core/Resources/maker/crud-controller/CrudController.tpl.php +++ b/core/Resources/maker/crud-controller/CrudController.tpl.php @@ -66,6 +66,14 @@ class extends CrudController return $this->doSort($page, $query, $entityManager, $request, $session); } + /** + * @Route("/admin//batch/{page}", name="admin__batch", methods={"POST"}, requirements={"page":"\d+"}) + */ + public function batch(int $page = 1, RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session): Response + { + return $this->doBatch($page, $query, $entityManager, $request, $session); + } + /** * @Route("/admin//delete/{entity}", name="admin__delete", methods={"DELETE"}) */ @@ -87,6 +95,7 @@ class extends CrudController ->setPageRoute('edit', 'admin__edit') ->setPageRoute('show', 'admin__show') ->setPageRoute('sort', 'admin__sort') + ->setPageRoute('batch', 'admin__batch') ->setPageRoute('delete', 'admin__delete') ->setPageRoute('filter', 'admin__filter') @@ -108,9 +117,16 @@ class extends CrudController // ->setAction('edit', 'show', true) // ->setAction('edit', 'delete', true) + // ->setAction('show', 'back', true) + // ->setAction('show', 'edit', true) + // ->setField('index', 'Label', Field\TextField::class, [ // 'property' => 'label', // ]) + + // ->setBatchAction('index', 'delete', 'Delete', function(EntityInterface $entity, EntityManager $manager) { + // $manager->delete($entity); + // }) ; } diff --git a/core/Resources/translations/messages.fr.yaml b/core/Resources/translations/messages.fr.yaml index e886b76..1380aad 100644 --- a/core/Resources/translations/messages.fr.yaml +++ b/core/Resources/translations/messages.fr.yaml @@ -161,3 +161,7 @@ "Results": "Résultats" "Clean all cache": "Nettoyer tout le cache" "You can sort items with drag & drop": "Vous pouvez trier les élements via un glisser/déposer" +"Batch action done.": "Action par lot effectuée." +"For selection": "Pour la sélection" +"For all items": "Pour tous les éléments" +"Run": "Lancer" diff --git a/core/Resources/views/admin/crud/index.html.twig b/core/Resources/views/admin/crud/index.html.twig index ccb1686..80b857d 100644 --- a/core/Resources/views/admin/crud/index.html.twig +++ b/core/Resources/views/admin/crud/index.html.twig @@ -87,6 +87,12 @@ {% block list_header %} + {% if configuration.hasBatchAction(context) %} + + + + {% endif %} + {% for label, config in configuration.fields(context) %} {% block list_header_item %} {% set attr = config.options.attr is defined ? config.options.attr : [] %} @@ -133,7 +139,7 @@ {% endblock %} {% endfor %} - + {{ 'Actions'|trans }} @@ -174,6 +180,12 @@ {% endset -%} + {% if configuration.hasBatchAction(context) %} + + + + {% endif %} + {% for config in configuration.fields(context) %} {% set attr = config.options.attr is defined ? config.options.attr : [] %} {% set action = config.options.action is defined ? config.options.action : null %} @@ -193,7 +205,7 @@ {% endfor %} - + {% block list_item_actions_before %}{% endblock %} {% if configuration.action(context, 'show', true) %} @@ -224,17 +236,59 @@ {% endblock %} - {% if loop.last and isSortable %} - - - - {{ 'You can sort items with drag & drop'|trans }} - - + + {% if loop.last and (isSortable or configuration.hasBatchAction(context)) %} + {% block list_footer %} + {% set count = configuration.fields(context)|length + 1 %} + {% if configuration.hasBatchAction(context) %} + {% set count = count + 1 %} + {% endif %} + + + + {% if isSortable %} +
+ + {{ 'You can sort items with drag & drop'|trans }} +
+ {% endif %} + + {% if configuration.hasBatchAction(context) %} +
+
+ + + + +
+
+ {% endif %} + + + {% endblock %} {% endif %} {% else %} + {% set count = configuration.fields(context)|length + 1 %} + {% if configuration.hasBatchAction(context) %} + {% set count = count + 1 %} + {% endif %} + - +
diff --git a/core/Twig/Extension/CrudExtension.php b/core/Twig/Extension/CrudExtension.php index 8539800..dcf9894 100644 --- a/core/Twig/Extension/CrudExtension.php +++ b/core/Twig/Extension/CrudExtension.php @@ -53,16 +53,16 @@ class CrudExtension extends AbstractExtension } if (is_callable($hrefConfig)) { - $href = call_user_func($hrefConfig, $entity, $config['options']); + $attrs['href'] = call_user_func($hrefConfig, $entity, $config['options']); } else { - $href = $hrefConfig; + $attrs['href'] = $hrefConfig; } foreach ($attrs as $k => $v) { - $attributes .= sprintf('%s="%s" ', htmlspecialchars($k), htmlspecialchars($v)); + $attributes .= sprintf(' %s="%s" ', htmlspecialchars($k), htmlspecialchars($v)); } - $render = sprintf('%s', htmlspecialchars($href), $attributes, $render); + $render = sprintf('%s', $attributes, $render); } return $render;