CRUDController.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. namespace WorkflowBundle\Controller;
  3. use Base\AdminBundle\Controller\CRUDController as BaseCRUDController;
  4. use Doctrine\Common\Inflector\Inflector;
  5. use Symfony\Component\HttpFoundation\RedirectResponse;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  8. use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
  9. use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
  10. class CRUDController extends BaseCRUDController
  11. {
  12. /**
  13. * Batch action.
  14. *
  15. * @return Response|RedirectResponse
  16. *
  17. * @throws NotFoundHttpException If the HTTP method is not POST
  18. * @throws \RuntimeException If the batch action is not defined
  19. */
  20. public function batchAction()
  21. {
  22. $request = $this->getRequest();
  23. $restMethod = $this->getRestMethod();
  24. if ('POST' !== $restMethod) {
  25. throw $this->createNotFoundException(sprintf('Invalid request type "%s", POST expected', $restMethod));
  26. }
  27. // check the csrf token
  28. $this->validateCsrfToken('sonata.batch');
  29. $confirmation = $request->get('confirmation', false);
  30. if ($data = json_decode($request->get('data'), true)) {
  31. $action = $data['action'];
  32. $idx = $data['idx'];
  33. $allElements = $data['all_elements'];
  34. $request->request->replace(array_merge($request->request->all(), $data));
  35. } else {
  36. $request->request->set('idx', $request->get('idx', array()));
  37. $request->request->set('all_elements', $request->get('all_elements', false));
  38. $action = $request->get('action');
  39. $idx = $request->get('idx');
  40. $allElements = $request->get('all_elements');
  41. $data = $request->request->all();
  42. unset($data['_sonata_csrf_token']);
  43. }
  44. // NEXT_MAJOR: Remove reflection check.
  45. $reflector = new \ReflectionMethod($this->admin, 'getBatchActions');
  46. if ($reflector->getDeclaringClass()->getName() === get_class($this->admin)) {
  47. @trigger_error('Override Sonata\AdminBundle\Admin\AbstractAdmin::getBatchActions method'
  48. . ' is deprecated since version 3.2.'
  49. . ' Use Sonata\AdminBundle\Admin\AbstractAdmin::configureBatchActions instead.'
  50. . ' The method will be final in 4.0.', E_USER_DEPRECATED
  51. );
  52. }
  53. $batchActions = $this->admin->getBatchActions();
  54. if (!array_key_exists($action, $batchActions)) {
  55. throw new \RuntimeException(sprintf('The `%s` batch action is not defined', $action));
  56. }
  57. $camelizedAction = Inflector::classify($action);
  58. $isRelevantAction = sprintf('batchAction%sIsRelevant', $camelizedAction);
  59. if (method_exists($this, $isRelevantAction)) {
  60. $nonRelevantMessage = call_user_func(array($this, $isRelevantAction), $idx, $allElements, $request);
  61. } else {
  62. $nonRelevantMessage = count($idx) != 0 || $allElements; // at least one item is selected
  63. }
  64. if (!$nonRelevantMessage) { // default non relevant message (if false of null)
  65. $nonRelevantMessage = 'flash_batch_empty';
  66. }
  67. $datagrid = $this->admin->getDatagrid();
  68. $datagrid->buildPager();
  69. if (true !== $nonRelevantMessage) {
  70. $this->addFlash('sonata_flash_info', $nonRelevantMessage);
  71. return new RedirectResponse(
  72. $this->admin->generateUrl(
  73. 'list', array('filter' => $this->admin->getFilterParameters())
  74. )
  75. );
  76. }
  77. $askConfirmation = isset($batchActions[$action]['ask_confirmation']) ?
  78. $batchActions[$action]['ask_confirmation'] :
  79. true;
  80. if ($askConfirmation && $confirmation != 'ok') {
  81. $actionLabel = $batchActions[$action]['label'];
  82. $batchTranslationDomain = isset($batchActions[$action]['translation_domain']) ?
  83. $batchActions[$action]['translation_domain'] :
  84. $this->admin->getTranslationDomain();
  85. $formView = $datagrid->getForm()->createView();
  86. $this->setFormTheme($formView, $this->admin->getFilterTheme());
  87. return $this->render($this->admin->getTemplate('batch_confirmation'), array(
  88. 'action' => 'list',
  89. 'action_label' => $actionLabel,
  90. 'batch_translation_domain' => $batchTranslationDomain,
  91. 'datagrid' => $datagrid,
  92. 'form' => $formView,
  93. 'data' => $data,
  94. 'csrf_token' => $this->getCsrfToken('sonata.batch'),
  95. ), null);
  96. }
  97. $workflowBatchAction = isset($batchActions[$action]['workflow']) ?: false;
  98. // execute the action, batchActionXxxxx
  99. $finalAction = sprintf('batchAction%s', $camelizedAction);
  100. if (!is_callable(array($this, $finalAction)) && !$workflowBatchAction) {
  101. throw new \RuntimeException(sprintf('A `%s::%s` method must be callable', get_class($this), $finalAction));
  102. }
  103. $query = $datagrid->getQuery();
  104. $query->setFirstResult(null);
  105. $query->setMaxResults(null);
  106. $this->allElementsBatch = $allElements;
  107. $this->admin->preBatchAction($action, $query, $idx, $allElements);
  108. if (count($idx) > 0) {
  109. $this->admin->getModelManager()->addIdentifiersToQuery($this->admin->getClass(), $query, $idx);
  110. } elseif (!$allElements) {
  111. $query = null;
  112. }
  113. if ($workflowBatchAction) {
  114. return $this->runWorkflowBatchAction($batchActions[$action]['workflow'], $query);
  115. }
  116. return call_user_func(array($this, $finalAction), $query, $request);
  117. }
  118. /**
  119. * @param array $workflow
  120. * @param ProxyQueryInterface $selectedModelQuery
  121. *
  122. * @return RedirectResponse
  123. */
  124. public function runWorkflowBatchAction($workflow, ProxyQueryInterface $selectedModelQuery)
  125. {
  126. if ($this->admin->isGranted('EDIT') === false || $this->admin->isGranted('DELETE') === false) {
  127. throw new AccessDeniedException();
  128. }
  129. $session = $this->get('session')->getFlashBag();
  130. $translator = $this->get('translator');
  131. try {
  132. $workflowRegistry = $this->get('workflow.registry');
  133. $em = $this->get('doctrine.orm.entity_manager');
  134. $selectedModels = $selectedModelQuery->execute();
  135. foreach ($selectedModels as $selectedModel) {
  136. if ($workflowRegistry->get($selectedModel, $workflow['name'])->can($selectedModel, $workflow['transition'])) {
  137. $workflowName = "{$selectedModel->getWorkflowType()}.{$selectedModel->getWorkflowName()}";
  138. $this->get($workflowName)->apply($selectedModel, $workflow['transition']);
  139. $em->persist($selectedModel);
  140. $em->flush($selectedModel);
  141. }
  142. }
  143. $session->add('sonata_flash_success', $translator->trans('flash_workflow_batch_success', array(), 'WorkflowBundle'));
  144. } catch (\Exception $e) {
  145. $session->add('sonata_flash_error', $translator->trans('flash_workflow_batch_error', array(), 'WorkflowBundle'));
  146. $session->add('sonata_flash_error', $e->getMessage());
  147. }
  148. return new RedirectResponse($this->admin->generateUrl('list', array('filter' => $this->admin->getFilterParameters())));
  149. }
  150. }