vendor/easycorp/easyadmin-bundle/src/Factory/ActionFactory.php line 73

Open in your IDE?
  1. <?php
  2. namespace EasyCorp\Bundle\EasyAdminBundle\Factory;
  3. use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection;
  4. use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
  5. use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
  6. use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
  7. use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionConfigDto;
  8. use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionDto;
  9. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  10. use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
  11. use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
  12. use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  15. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  16. use function Symfony\Component\String\u;
  17. use Symfony\Contracts\Translation\TranslatorInterface;
  18. /**
  19. * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  20. */
  21. final class ActionFactory
  22. {
  23. private $adminContextProvider;
  24. private $authChecker;
  25. private $translator;
  26. private $adminUrlGenerator;
  27. private $csrfTokenManager;
  28. public function __construct(AdminContextProvider $adminContextProvider, AuthorizationCheckerInterface $authChecker, TranslatorInterface $translator, AdminUrlGenerator $adminUrlGenerator, CsrfTokenManagerInterface $csrfTokenManager)
  29. {
  30. $this->adminContextProvider = $adminContextProvider;
  31. $this->authChecker = $authChecker;
  32. $this->translator = $translator;
  33. $this->adminUrlGenerator = $adminUrlGenerator;
  34. $this->csrfTokenManager = $csrfTokenManager;
  35. }
  36. public function processEntityActions(EntityDto $entityDto, ActionConfigDto $actionsDto): void
  37. {
  38. $currentPage = $this->adminContextProvider->getContext()->getCrud()->getCurrentPage();
  39. $entityActions = [];
  40. foreach ($actionsDto->getActions()->all() as $actionDto) {
  41. if (!$actionDto->isEntityAction()) {
  42. continue;
  43. }
  44. if (false === $this->authChecker->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => $actionDto, 'entity' => $entityDto])) {
  45. continue;
  46. }
  47. if (false === $actionDto->shouldBeDisplayedFor($entityDto)) {
  48. continue;
  49. }
  50. if ('' === $actionDto->getCssClass()) {
  51. $defaultCssClass = 'action-'.$actionDto->getName();
  52. if (Crud::PAGE_INDEX !== $currentPage) {
  53. $defaultCssClass .= ' btn';
  54. }
  55. $actionDto->setCssClass($defaultCssClass);
  56. }
  57. $entityActions[] = $this->processAction($currentPage, $actionDto, $entityDto);
  58. }
  59. $entityDto->setActions(ActionCollection::new($entityActions));
  60. }
  61. public function processGlobalActions(ActionConfigDto $actionsDto = null): ActionCollection
  62. {
  63. if (null === $actionsDto) {
  64. $actionsDto = $this->adminContextProvider->getContext()->getCrud()->getActionsConfig();
  65. }
  66. $currentPage = $this->adminContextProvider->getContext()->getCrud()->getCurrentPage();
  67. $globalActions = [];
  68. foreach ($actionsDto->getActions()->all() as $actionDto) {
  69. if (!$actionDto->isGlobalAction() && !$actionDto->isBatchAction()) {
  70. continue;
  71. }
  72. if (false === $this->authChecker->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => $actionDto, 'entity' => null])) {
  73. continue;
  74. }
  75. if (Crud::PAGE_INDEX !== $currentPage && $actionDto->isBatchAction()) {
  76. throw new \RuntimeException(sprintf('Batch actions can be added only to the "index" page, but the "%s" batch action is defined in the "%s" page.', $actionDto->getName(), $currentPage));
  77. }
  78. if ('' === $actionDto->getCssClass()) {
  79. $actionDto->setCssClass('btn action-'.$actionDto->getName());
  80. }
  81. $globalActions[] = $this->processAction($currentPage, $actionDto);
  82. }
  83. return ActionCollection::new($globalActions);
  84. }
  85. private function processAction(string $pageName, ActionDto $actionDto, ?EntityDto $entityDto = null): ActionDto
  86. {
  87. $adminContext = $this->adminContextProvider->getContext();
  88. $translationDomain = $adminContext->getI18n()->getTranslationDomain();
  89. $defaultTranslationParameters = $adminContext->getI18n()->getTranslationParameters();
  90. $currentPage = $adminContext->getCrud()->getCurrentPage();
  91. $actionDto->setHtmlAttribute('data-action-name', $actionDto->getName());
  92. if (false === $actionDto->getLabel()) {
  93. $actionDto->setHtmlAttribute('title', $actionDto->getName());
  94. } else {
  95. $uLabel = u($actionDto->getLabel());
  96. // labels with this prefix are considered internal and must be translated
  97. // with 'EasyAdminBundle' translation domain, regardless of the backend domain
  98. if ($uLabel->startsWith('__ea__')) {
  99. $uLabel = $uLabel->after('__ea__');
  100. $translationDomain = 'EasyAdminBundle';
  101. }
  102. $translationParameters = array_merge($defaultTranslationParameters, $actionDto->getTranslationParameters());
  103. $label = $uLabel->toString();
  104. $translatedActionLabel = empty($label) ? $label : $this->translator->trans($label, $translationParameters, $translationDomain);
  105. $actionDto->setLabel($translatedActionLabel);
  106. }
  107. $defaultTemplatePath = $adminContext->getTemplatePath('crud/action');
  108. $actionDto->setTemplatePath($actionDto->getTemplatePath() ?? $defaultTemplatePath);
  109. $actionDto->setLinkUrl($this->generateActionUrl($currentPage, $adminContext->getRequest(), $actionDto, $entityDto));
  110. if (!$actionDto->isGlobalAction() && \in_array($pageName, [Crud::PAGE_EDIT, Crud::PAGE_NEW], true)) {
  111. $actionDto->setHtmlAttribute('form', sprintf('%s-%s-form', $pageName, $entityDto->getName()));
  112. }
  113. if (Action::DELETE === $actionDto->getName()) {
  114. $actionDto->addHtmlAttributes([
  115. 'formaction' => $this->adminUrlGenerator->setAction(Action::DELETE)->setEntityId($entityDto->getPrimaryKeyValue())->removeReferrer()->generateUrl(),
  116. 'data-bs-toggle' => 'modal',
  117. 'data-bs-target' => '#modal-delete',
  118. ]);
  119. }
  120. if ($actionDto->isBatchAction()) {
  121. $actionDto->addHtmlAttributes([
  122. 'data-bs-toggle' => 'modal',
  123. 'data-bs-target' => '#modal-batch-action',
  124. 'data-action-csrf-token' => $this->csrfTokenManager->getToken('ea-batch-action-'.$actionDto->getName()),
  125. 'data-action-batch' => 'true',
  126. 'data-entity-fqcn' => $adminContext->getCrud()->getEntityFqcn(),
  127. 'data-action-url' => $actionDto->getLinkUrl(),
  128. ]);
  129. }
  130. return $actionDto;
  131. }
  132. private function generateActionUrl(string $currentAction, Request $request, ActionDto $actionDto, ?EntityDto $entityDto = null): string
  133. {
  134. if (null !== $url = $actionDto->getUrl()) {
  135. if (\is_callable($url)) {
  136. return null !== $entityDto ? $url($entityDto->getInstance()) : $url();
  137. }
  138. return $url;
  139. }
  140. if (null !== $routeName = $actionDto->getRouteName()) {
  141. $routeParameters = $actionDto->getRouteParameters();
  142. if (\is_callable($routeParameters) && null !== $entityInstance = $entityDto->getInstance()) {
  143. $routeParameters = $routeParameters($entityInstance);
  144. }
  145. return $this->adminUrlGenerator->unsetAllExcept(EA::MENU_INDEX, EA::SUBMENU_INDEX)->includeReferrer()->setRoute($routeName, $routeParameters)->generateUrl();
  146. }
  147. $requestParameters = [
  148. EA::CRUD_CONTROLLER_FQCN => $request->query->get(EA::CRUD_CONTROLLER_FQCN),
  149. EA::CRUD_ACTION => $actionDto->getCrudActionName(),
  150. EA::REFERRER => $this->generateReferrerUrl($request, $actionDto, $currentAction),
  151. ];
  152. if (\in_array($actionDto->getName(), [Action::INDEX, Action::NEW, Action::SAVE_AND_ADD_ANOTHER, Action::SAVE_AND_RETURN], true)) {
  153. $requestParameters[EA::ENTITY_ID] = null;
  154. } elseif (null !== $entityDto) {
  155. $requestParameters[EA::ENTITY_ID] = $entityDto->getPrimaryKeyValueAsString();
  156. }
  157. return $this->adminUrlGenerator->unsetAllExcept(EA::MENU_INDEX, EA::SUBMENU_INDEX, EA::FILTERS, EA::PAGE)->setAll($requestParameters)->generateUrl();
  158. }
  159. private function generateReferrerUrl(Request $request, ActionDto $actionDto, string $currentAction): ?string
  160. {
  161. $nextAction = $actionDto->getName();
  162. if (Action::DETAIL === $currentAction) {
  163. if (Action::EDIT === $nextAction) {
  164. return $this->adminUrlGenerator->removeReferrer()->generateUrl();
  165. }
  166. }
  167. if (Action::INDEX === $currentAction) {
  168. return $this->adminUrlGenerator->removeReferrer()->generateUrl();
  169. }
  170. if (Action::NEW === $currentAction) {
  171. return null;
  172. }
  173. $referrer = $request->query->get(EA::REFERRER);
  174. $referrerParts = parse_url((string) $referrer);
  175. parse_str($referrerParts[EA::QUERY] ?? '', $referrerQueryStringVariables);
  176. $referrerCrudAction = $referrerQueryStringVariables[EA::CRUD_ACTION] ?? null;
  177. if (Action::EDIT === $currentAction) {
  178. if (\in_array($referrerCrudAction, [Action::INDEX, Action::DETAIL], true)) {
  179. return $referrer;
  180. }
  181. }
  182. return $this->adminUrlGenerator->removeReferrer()->generateUrl();
  183. }
  184. }