選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

868 行
32KB

  1. <?php
  2. namespace Lc\SovBundle\Controller;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Doctrine\ORM\QueryBuilder;
  5. use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection;
  6. use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection;
  7. use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
  8. use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
  9. use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
  10. use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
  11. use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
  12. use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
  13. use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
  14. use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
  15. use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\CrudControllerInterface;
  16. use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController;
  17. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  18. use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
  19. use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
  20. use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
  21. use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
  22. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
  23. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
  24. use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
  25. use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
  26. use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory;
  27. use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
  28. use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
  29. use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory;
  30. use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
  31. use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
  32. use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
  33. use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
  34. use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
  35. use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
  36. use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
  37. use Lc\CaracoleBundle\Model\Section\SectionInterface;
  38. use Lc\SovBundle\Component\EntityComponent;
  39. use Lc\SovBundle\Definition\ActionDefinition;
  40. use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
  41. use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
  42. use Lc\SovBundle\Doctrine\Extension\SeoInterface;
  43. use Lc\SovBundle\Doctrine\Extension\SortableInterface;
  44. use Lc\SovBundle\Doctrine\Extension\StatusInterface;
  45. use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
  46. use Lc\SovBundle\Doctrine\Extension\TreeInterface;
  47. use Lc\SovBundle\Field\CollectionField;
  48. use Lc\SovBundle\Field\Filter\FilterManager;
  49. use Lc\SovBundle\Field\ImageManagerField;
  50. use Lc\SovBundle\Form\Common\FiltersFormType;
  51. use Lc\SovBundle\Form\Common\PositionType;
  52. use Lc\SovBundle\Model\User\UserInterface;
  53. use Lc\SovBundle\Repository\EntityRepository;
  54. use Lc\SovBundle\Repository\RepositoryQueryInterface;
  55. use Lc\SovBundle\Translation\FlashBagTranslator;
  56. use Lc\SovBundle\Translation\TranslatorAdmin;
  57. use Symfony\Component\Form\Extension\Core\Type\CollectionType;
  58. use Symfony\Component\Form\Extension\Core\Type\TextType;
  59. use Symfony\Component\Form\FormInterface;
  60. use Symfony\Component\HttpFoundation\JsonResponse;
  61. use Symfony\Component\HttpFoundation\RequestStack;
  62. use Symfony\Component\HttpFoundation\Response;
  63. abstract class AbstractAdminController extends EaAbstractCrudController
  64. {
  65. use ControllerTrait;
  66. protected FormInterface $filtersForm;
  67. protected bool $isRepositoryQueryFiltered = false;
  68. abstract public function getRepositoryQuery(): RepositoryQueryInterface;
  69. public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore
  70. {
  71. if ($responseParameters->get('global_actions')) {
  72. $this->overrideGlobalActions($responseParameters->get('global_actions'));
  73. }
  74. if ($responseParameters->get('entities')) {
  75. $this->overrideEntitiesActions($responseParameters->get('entities'), $responseParameters->get('pageName'));
  76. }
  77. if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
  78. $responseParameters->set('fields', $this->configureFields('index'));
  79. if (isset($this->filtersForm)) {
  80. $responseParameters->set('filters_form', $this->filtersForm);
  81. }
  82. }
  83. $responseParameters->set('translation_entity_name', $this->getTranslationEntityName());
  84. return $responseParameters;
  85. }
  86. public function getTranslationEntityName()
  87. {
  88. return $this->getEntityFqcn();
  89. }
  90. public function overrideEntitiesActions(?EntityCollection $entities, string $pageName): void
  91. {
  92. }
  93. public function overrideGlobalActions(?ActionCollection $actions): void
  94. {
  95. if ($actions) {
  96. $context = $this->get(AdminContextProvider::class)->getContext();
  97. $adminUrlGenerator = $this->get(AdminUrlGenerator::class);
  98. foreach ($actions as $i => $action) {
  99. //récriture du bouton 'retour au parent'
  100. if ($action->getName() == 'index_parent') {
  101. $entity = $context->getEntity()->getInstance();
  102. if ($entity !== null) {
  103. if ($entity->getParent() !== null) {
  104. $url = $adminUrlGenerator
  105. ->setController($context->getCrud()->getControllerFqcn())
  106. ->set('entityId', $entity->getParent()->getId())
  107. ->generateUrl();
  108. $action->setLinkUrl($url);
  109. }
  110. } else {
  111. unset($actions[$i]);
  112. }
  113. }
  114. if ($action->getName() == 'sort') {
  115. $entityId = $context->getRequest()->get('entityId');
  116. if ($entityId != null) {
  117. $url = $adminUrlGenerator
  118. ->setController($context->getCrud()->getControllerFqcn())
  119. ->setAction($action->getName())
  120. ->set('entityId', $entityId)
  121. ->generateUrl();
  122. $action->setLinkUrl($url);
  123. }
  124. }
  125. if ($action->getName() == ActionDefinition::WRITE_TO_USER) {
  126. $entity = $context->getEntity()->getInstance();
  127. if ($entity !== null) {
  128. if (method_exists($entity, 'getUser')) {
  129. $url = $this->generateEaUrl(UserA)->setController($context->getCrud()->getControllerFqcn())
  130. ->set('entityId', $entity->getParent()->getId())
  131. ->generateUrl();
  132. $action->setLinkUrl($url);
  133. }
  134. } else {
  135. unset($actions[$i]);
  136. }
  137. }
  138. }
  139. }
  140. }
  141. protected function getRequestCrudAction(): string
  142. {
  143. return $this->getRequestStack()->getCurrentRequest()->get('crudAction');
  144. }
  145. public function configureCrud(Crud $crud): Crud
  146. {
  147. $crud = parent::configureCrud($crud);
  148. if ($this->getRequestCrudAction() === ActionDefinition::SORT) {
  149. $crud->setPaginatorPageSize(9999);
  150. } else {
  151. $this->setMaxResults($crud);
  152. }
  153. $crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]);
  154. if ($this->isInstanceOf(SortableInterface::class)) {
  155. $crud->setDefaultSort(['position' => 'ASC']);
  156. } else {
  157. $crud->setDefaultSort(['id' => 'DESC']);
  158. }
  159. return $crud;
  160. }
  161. public function setMaxResults(Crud $crud): void
  162. {
  163. $entityClass = $this->getEntityFqcn();
  164. $paramListMaxResults = 'listMaxResults';
  165. $paramSessionListMaxResults = $entityClass . '-' . $paramListMaxResults;
  166. $requestListMaxResults = $this->get(RequestStack::class)->getCurrentRequest()->get($paramListMaxResults);
  167. if ($requestListMaxResults) {
  168. $this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults);
  169. }
  170. $maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get(
  171. $paramSessionListMaxResults
  172. ) : 30;
  173. $crud->setPaginatorPageSize($maxResults);
  174. }
  175. public function getSeoPanel(): ?array
  176. {
  177. if ($this->isInstanceOf(SeoInterface::class)) {
  178. return [
  179. FormField::addPanel('seo')->setTemplateName('crud/field/generic'),
  180. TextField::new('metaTitle')->setLabel('Meta Title')->setHelp(
  181. 'Affiché dans les résultats de recherche Google'
  182. )->hideOnIndex(),
  183. TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp(
  184. 'Affiché dans les résultats de recherche Google'
  185. )->hideOnIndex(),
  186. CollectionField::new('oldUrls')
  187. ->setFormTypeOption('entry_type', TextType::class)->setLabel(
  188. 'Anciennes urls du document'
  189. )->hideOnIndex(),
  190. ];
  191. } else {
  192. return null;
  193. }
  194. }
  195. public function getConfPanel(): ?array
  196. {
  197. if ($this->isInstanceOf(DevAliasInterface::class)) {
  198. return [
  199. FormField::addPanel('configuration')->setTemplateName('crud/field/generic'),
  200. TextField::new('devAlias')->hideOnIndex(),
  201. ];
  202. } else {
  203. return null;
  204. }
  205. }
  206. public function sort(AdminContext $context)
  207. {
  208. $event = new BeforeCrudActionEvent($context);
  209. $this->get('event_dispatcher')->dispatch($event);
  210. if ($event->isPropagationStopped()) {
  211. return $event->getResponse();
  212. }
  213. //if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) {
  214. if (!$this->isInstanceOf(SortableInterface::class)) {
  215. throw new ForbiddenActionException($context);
  216. }
  217. $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
  218. $filters = $this->get(FilterFactory::class)->create(
  219. $context->getCrud()->getFiltersConfig(),
  220. $fields,
  221. $context->getEntity()
  222. );
  223. $queryBuilder = $this->createSortQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);
  224. $paginator = $this->get(PaginatorFactory::class)->create($queryBuilder);
  225. $entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults());
  226. $this->get(EntityFactory::class)->processFieldsForAll($entities, $fields);
  227. $sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults()))
  228. ->add(
  229. 'entities',
  230. CollectionType::class,
  231. array(
  232. 'required' => true,
  233. 'allow_add' => true,
  234. 'entry_type' => PositionType::class,
  235. )
  236. )
  237. ->getForm();
  238. $entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn());
  239. $repository = $entityManager->getRepository($this->getEntityFqcn());
  240. $sortableForm->handleRequest($context->getRequest());
  241. if ($sortableForm->isSubmitted() && $sortableForm->isValid()) {
  242. foreach ($sortableForm->get('entities')->getData() as $elm) {
  243. $entityInstance = $repository->find($elm['id']);
  244. $entityDto = $context->getEntity()->newWithInstance($entityInstance);
  245. if (!$entityDto->isAccessible()) {
  246. throw new InsufficientEntityPermissionException($context);
  247. }
  248. $event = new BeforeEntityDeletedEvent($entityInstance);
  249. $this->get('event_dispatcher')->dispatch($event);
  250. $entityInstance = $event->getEntityInstance();
  251. $entityInstance->setPosition($elm['position']);
  252. $this->updateEntity($entityManager, $entityInstance);
  253. $this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
  254. }
  255. $url = $this->get(AdminUrlGenerator::class)
  256. ->setAction(ActionDefinition::INDEX)
  257. ->generateUrl();
  258. $this->addFlashTranslator('success', 'sorted');
  259. return $this->redirect($url);
  260. }
  261. $responseParameters = $this->configureResponseParameters(
  262. KeyValueStore::new(
  263. [
  264. 'pageName' => Crud::PAGE_INDEX,
  265. 'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
  266. 'entities' => $entities,
  267. 'paginator' => $paginator,
  268. 'global_actions' => array(),
  269. 'batch_actions' => array(),
  270. 'filters' => $filters,
  271. 'sortable_form' => $sortableForm,
  272. ]
  273. )
  274. );
  275. $responseParameters->set('fields', $this->configureFields('index'));
  276. $event = new AfterCrudActionEvent($context, $responseParameters);
  277. $this->get('event_dispatcher')->dispatch($event);
  278. if ($event->isPropagationStopped()) {
  279. return $event->getResponse();
  280. }
  281. return $responseParameters;
  282. }
  283. public function duplicate(
  284. AdminContext $context,
  285. EntityComponent $entityComponent,
  286. TranslatorAdmin $translatorAdmin,
  287. EntityManagerInterface $em
  288. )
  289. {
  290. if (!$this->isGranted(
  291. Permission::EA_EXECUTE_ACTION,
  292. ['action' => ActionDefinition::DUPLICATE, 'entity' => $context->getEntity()]
  293. )) {
  294. throw new ForbiddenActionException($context);
  295. }
  296. if (!$context->getEntity()->isAccessible()) {
  297. throw new InsufficientEntityPermissionException($context);
  298. }
  299. $newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance());
  300. $em->create($newEntity);
  301. $em->flush();
  302. $url = $this->get(AdminUrlGenerator::class)
  303. ->setAction(ActionDefinition::EDIT)
  304. ->setEntityId($newEntity->getId())
  305. ->generateUrl();
  306. $this->addFlashTranslator('success', ActionDefinition::DUPLICATE);
  307. return $this->redirect($url);
  308. }
  309. public function isRepositoryQueryFiltered(): bool
  310. {
  311. if (($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered) {
  312. return true;
  313. } else {
  314. return false;
  315. }
  316. }
  317. public function createIndexRepositoryQuery(
  318. SearchDto $searchDto,
  319. EntityDto $entityDto,
  320. FieldCollection $fields,
  321. FilterCollection $filters
  322. ): RepositoryQueryInterface
  323. {
  324. $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
  325. $this->getRepositoryQuery(),
  326. $searchDto,
  327. $entityDto,
  328. $fields,
  329. $filters
  330. );
  331. // TODO : déplacer dans EntotyRepository
  332. if ($this->isInstanceOf(TreeInterface::class)) {
  333. if ($entityDto->getInstance()) {
  334. $repositoryQuery->filterByParent($entityDto->getInstance());
  335. } else {
  336. $repositoryQuery->filterIsParent();
  337. }
  338. }
  339. if ($this->isInstanceOf(StatusInterface::class)) {
  340. $repositoryQuery->filterIsOnlineAndOffline();
  341. }
  342. $this->filtersForm = $this->createForm(
  343. FiltersFormType::class,
  344. null,
  345. array(
  346. 'fields' => $fields,
  347. 'entity_dto' => $entityDto,
  348. 'entity_class' => $this->getEntityFqcn(),
  349. 'entity_name' => $entityDto->getName(),
  350. )
  351. );
  352. $filterManager = $this->get(FilterManager::class);
  353. $this->filtersForm->handleRequest($searchDto->getRequest());
  354. $this->isRepositoryQueryFiltered = $filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto);
  355. return $repositoryQuery;
  356. }
  357. public function createSortRepositoryQuery(
  358. SearchDto $searchDto,
  359. EntityDto $entityDto,
  360. FieldCollection $fields,
  361. FilterCollection $filters
  362. ): RepositoryQueryInterface
  363. {
  364. $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
  365. if ($this->isInstanceOf(StatusInterface::class)) {
  366. $repositoryQuery->filterIsOnline();
  367. }
  368. $repositoryQuery->orderBy('position', 'asc');
  369. return $repositoryQuery;
  370. }
  371. public function createIndexQueryBuilder(
  372. SearchDto $searchDto,
  373. EntityDto $entityDto,
  374. FieldCollection $fields,
  375. FilterCollection $filters
  376. ): QueryBuilder
  377. {
  378. $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
  379. return $repositoryQuery->getQueryBuilder();
  380. }
  381. public function createSortQueryBuilder(
  382. SearchDto $searchDto,
  383. EntityDto $entityDto,
  384. FieldCollection $fields,
  385. FilterCollection $filters
  386. ): QueryBuilder
  387. {
  388. $repositoryQuery = $this->createSortRepositoryQuery($searchDto, $entityDto, $fields, $filters);
  389. return $repositoryQuery->getQueryBuilder();
  390. }
  391. public function edit(AdminContext $context)
  392. {
  393. $response = parent::edit($context);;
  394. // on vide le flash bag si édition en ajax (notification déjà affichée en Javascript)
  395. if ($context->getRequest()->isXmlHttpRequest()) {
  396. $this->get('session')->getFlashBag()->clear();
  397. }
  398. return $response;
  399. }
  400. public function getControllerFqcnByInterface(string $interface): string
  401. {
  402. $context = $this->get(AdminContextProvider::class)->getContext();
  403. return $context->getCrudControllers()->findCrudFqcnByEntityFqcn(
  404. $this->get(EntityManagerInterface::class)->getEntityName($interface)
  405. );
  406. }
  407. public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
  408. {
  409. $entityManager->update($entityInstance);
  410. $entityManager->flush();
  411. $this->get(FlashBagTranslator::class)->add('success', 'updated', $this->getTranslationEntityName());
  412. }
  413. public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
  414. {
  415. $entityManager->create($entityInstance);
  416. $entityManager->flush();
  417. $this->get(FlashBagTranslator::class)->add('success', 'created', $this->getTranslationEntityName());
  418. }
  419. public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void
  420. {
  421. if ($this->isInstanceOf(StatusInterface::class)) {
  422. $entityInstance->setStatus(-1);
  423. $entityManager->update($entityInstance);
  424. } else {
  425. $entityManager->delete($entityInstance);
  426. }
  427. $entityManager->flush();
  428. $this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName());
  429. }
  430. public function configureActions(Actions $actions): Actions
  431. {
  432. $this->buildIndexActions($actions);
  433. $this->buildEditActions($actions);
  434. $this->buildDetailActions($actions);
  435. $this->buildNewActions($actions);
  436. $this->handleTranslatableEntityActions($actions);
  437. $this->handleSortableEntityActions($actions);
  438. $this->handleTreeEntityActions($actions);
  439. /*$actions->reorder(Crud::PAGE_EDIT, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_CONTINUE, ActionDefinition::DELETE]);
  440. $actions->reorder(Crud::PAGE_NEW, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_ADD_ANOTHER]);*/
  441. return $actions;
  442. }
  443. public function getDuplicateAction(): Action
  444. {
  445. $duplicateAction = Action::new(
  446. ActionDefinition::DUPLICATE,
  447. $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE),
  448. 'fa fa-fw fa-copy'
  449. )
  450. ->linkToCrudAction(ActionDefinition::DUPLICATE)
  451. ->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE))
  452. ->setCssClass('in-dropdown text-info action-confirm');
  453. return $duplicateAction;
  454. }
  455. public function buildIndexActions(Actions $actions): void
  456. {
  457. $actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction());
  458. $this->actionUpdate(
  459. $actions,
  460. Crud::PAGE_INDEX,
  461. ActionDefinition::NEW,
  462. [
  463. 'icon' => 'plus',
  464. 'label' => $this->get(TranslatorAdmin::class)->transAction('create'),
  465. 'add_class' => 'btn-sm',
  466. ]
  467. );
  468. $this->actionUpdate(
  469. $actions,
  470. Crud::PAGE_INDEX,
  471. ActionDefinition::EDIT,
  472. [
  473. 'class' => 'btn btn-sm btn-primary',
  474. 'icon' => 'edit',
  475. 'label' => false,
  476. 'html_attributes' => array(
  477. 'data-toggle' => 'tooltip',
  478. 'title' => $this->get(TranslatorAdmin::class)->transAction('edit'),
  479. ),
  480. ]
  481. );
  482. $this->actionUpdate(
  483. $actions,
  484. Crud::PAGE_INDEX,
  485. ActionDefinition::DETAIL,
  486. [
  487. 'icon' => 'eye',
  488. 'add_class' => 'btn btn-sm btn-success',
  489. 'label' => false,
  490. 'html_attributes' => array(
  491. 'data-toggle' => 'tooltip',
  492. 'title' => $this->get(TranslatorAdmin::class)->transAction('detail'),
  493. ),
  494. ]
  495. );
  496. $this->actionUpdate(
  497. $actions,
  498. Crud::PAGE_INDEX,
  499. ActionDefinition::DELETE,
  500. [
  501. 'icon' => 'trash',
  502. 'dropdown' => true,
  503. 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
  504. 'class' => 'dropdown-item text-danger in-dropdown action-delete',
  505. ]
  506. );
  507. $this->actionUpdate(
  508. $actions,
  509. Crud::PAGE_INDEX,
  510. ActionDefinition::BATCH_DELETE,
  511. [
  512. 'class' => 'btn btn-sm btn-danger',
  513. 'icon' => 'trash',
  514. 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
  515. ]
  516. );
  517. }
  518. public function buildEditActions(Actions $actions): void
  519. {
  520. $actions->add(Crud::PAGE_EDIT, ActionDefinition::INDEX);
  521. $actions->add(Crud::PAGE_EDIT, ActionDefinition::DELETE);
  522. $this->actionUpdate(
  523. $actions,
  524. Crud::PAGE_EDIT,
  525. ActionDefinition::SAVE_AND_RETURN,
  526. [
  527. 'add_class' => 'float-right ',
  528. 'icon' => 'check',
  529. 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
  530. ]
  531. );
  532. $this->actionUpdate(
  533. $actions,
  534. Crud::PAGE_EDIT,
  535. ActionDefinition::INDEX,
  536. [
  537. 'icon' => 'chevron-left',
  538. 'class' => 'btn btn-link',
  539. 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
  540. ]
  541. );
  542. $this->actionUpdate(
  543. $actions,
  544. Crud::PAGE_EDIT,
  545. ActionDefinition::SAVE_AND_CONTINUE,
  546. [
  547. 'class' => 'btn btn-info float-right action-save-continue',
  548. 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'),
  549. ]
  550. );
  551. $this->actionUpdate(
  552. $actions,
  553. Crud::PAGE_EDIT,
  554. ActionDefinition::DELETE,
  555. [
  556. 'icon' => 'trash',
  557. 'class' => 'btn btn-outline-danger action-delete',
  558. 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
  559. ]
  560. );
  561. }
  562. public function buildDetailActions(Actions $actions): void
  563. {
  564. }
  565. public function buildNewActions(Actions $actions): void
  566. {
  567. $actions->add(Crud::PAGE_NEW, ActionDefinition::INDEX);
  568. $this->actionUpdate(
  569. $actions,
  570. Crud::PAGE_NEW,
  571. ActionDefinition::SAVE_AND_RETURN,
  572. [
  573. 'add_class' => 'float-right',
  574. 'icon' => 'check',
  575. 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
  576. ]
  577. );
  578. $this->actionUpdate(
  579. $actions,
  580. Crud::PAGE_NEW,
  581. ActionDefinition::INDEX,
  582. [
  583. 'icon' => 'chevron-left',
  584. 'class' => 'btn btn-link',
  585. 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
  586. ]
  587. );
  588. $this->actionUpdate(
  589. $actions,
  590. Crud::PAGE_NEW,
  591. ActionDefinition::SAVE_AND_ADD_ANOTHER,
  592. [
  593. 'class' => 'btn btn-info float-right',
  594. 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'),
  595. ]
  596. );
  597. }
  598. public function handleTranslatableEntityActions(Actions $actions): void
  599. {
  600. if ($this->isInstanceOf(TranslatableInterface::class)) {
  601. $actions->update(
  602. Crud::PAGE_INDEX,
  603. ActionDefinition::EDIT,
  604. function (Action $action) {
  605. $action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig');
  606. return $action;
  607. }
  608. );
  609. }
  610. }
  611. public function handleSortableEntityActions(Actions $actions): void
  612. {
  613. if ($this->isInstanceOf(SortableInterface::class)) {
  614. $sortAction = Action::new(
  615. ActionDefinition::SORT,
  616. $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SORT),
  617. 'fa fa-sort'
  618. )
  619. ->linkToCrudAction(ActionDefinition::SORT)
  620. ->setCssClass('btn btn-sm btn-success')
  621. ->createAsGlobalAction();
  622. $actions->add(Crud::PAGE_INDEX, $sortAction);
  623. }
  624. }
  625. public function handleTreeEntityActions(Actions $actions): void
  626. {
  627. if ($this->isInstanceOf(TreeInterface::class)) {
  628. $indexChildAction = Action::new(
  629. ActionDefinition::INDEX_CHILDREN,
  630. $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_CHILDREN),
  631. 'fa fa-list'
  632. )
  633. ->linkToCrudAction(ActionDefinition::INDEX)
  634. ->setLabel('')
  635. ->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants'))
  636. ->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig')
  637. ->setCssClass('btn btn-sm btn-success');
  638. $backParentAction = Action::new(
  639. ActionDefinition::INDEX_PARENT,
  640. $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_PARENT),
  641. 'fa fa-chevron-left'
  642. )
  643. ->linkToCrudAction(ActionDefinition::INDEX)
  644. ->setCssClass('btn btn-sm btn-info')
  645. ->createAsGlobalAction();
  646. $actions->add(Crud::PAGE_INDEX, $backParentAction);
  647. $actions->add(Crud::PAGE_INDEX, $indexChildAction);
  648. }
  649. }
  650. public function actionUpdate($actions, $crudActionName, $actionName, array $button): void
  651. {
  652. if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) {
  653. $actions->update(
  654. $crudActionName,
  655. $actionName,
  656. function (Action $action) use ($button) {
  657. if (isset($button['add_class'])) {
  658. $action->addCssClass($button['add_class']);
  659. }
  660. if (isset($button['class'])) {
  661. $action->setCssClass($button['class']);
  662. }
  663. if (isset($button['icon'])) {
  664. $action->setIcon('fa fa-' . $button['icon']);
  665. }
  666. if (isset($button['label'])) {
  667. $action->setLabel($button['label']);
  668. }
  669. if (isset($button['dropdown']) && $button['dropdown']) {
  670. $action->addCssClass('in-dropdown');
  671. }
  672. if (isset($button['html_attributes']) && $button['html_attributes']) {
  673. $action->setHtmlAttributes($button['html_attributes']);
  674. }
  675. return $action;
  676. }
  677. );
  678. }
  679. }
  680. public function autocompleteFilter(AdminContext $context): JsonResponse
  681. {
  682. $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
  683. $this->getRepositoryQuery(),
  684. $context->getSearch(),
  685. $context->getEntity(),
  686. FieldCollection::new([]),
  687. FilterCollection::new()
  688. );
  689. if ($this->isInstanceOf(StatusInterface::class)) {
  690. $repositoryQuery->filterIsOnlineAndOffline();
  691. }
  692. $autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT);
  693. /** @var CrudControllerInterface $controller */
  694. $controller = $this->get(ControllerFactory::class)->getCrudControllerInstance(
  695. $autocompleteContext[EA::CRUD_CONTROLLER_FQCN],
  696. ActionDefinition::INDEX,
  697. $context->getRequest()
  698. );
  699. /** @var FieldDto $field */
  700. $field = FieldCollection::new(
  701. $controller->configureFields($autocompleteContext['originatingPage'])
  702. )->getByProperty($autocompleteContext['propertyName']);
  703. $filterManager = $this->get(FilterManager::class);
  704. $filteredValue = ['value' => $context->getRequest()->query->get('q')];
  705. $filterManager->applyFilter($repositoryQuery, $field, $filteredValue);
  706. $repositoryQuery->select('.' . $autocompleteContext['propertyName']);
  707. $responses = array();
  708. foreach ($repositoryQuery->find() as $result) {
  709. $responses[] = array_values($result)[0];
  710. }
  711. return JsonResponse::fromJsonString(json_encode($responses));
  712. }
  713. public function createCustomForm($class, $action, $controller, $entity, $dataInOption = true, $options = array())
  714. {
  715. if ($dataInOption) {
  716. $data = $entity;
  717. } else {
  718. $data = null;
  719. }
  720. $options['action'] = $this->get(AdminUrlGenerator::class)
  721. ->setAction($action)
  722. ->setController($controller)
  723. ->setEntityId($entity->getId())
  724. ->generateUrl();
  725. return $this->createForm($class, $data, $options);
  726. }
  727. public function eaBeforeCrudActionEventDelete(AdminContext $context): ?Response
  728. {
  729. $event = new BeforeCrudActionEvent($context);
  730. $this->container->get('event_dispatcher')->dispatch($event);
  731. if ($event->isPropagationStopped()) {
  732. return $event->getResponse();
  733. }
  734. if (!$this->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => Action::DELETE, 'entity' => $context->getEntity()])) {
  735. throw new ForbiddenActionException($context);
  736. }
  737. if (!$context->getEntity()->isAccessible()) {
  738. throw new InsufficientEntityPermissionException($context);
  739. }
  740. $csrfToken = $context->getRequest()->request->get('token');
  741. if (!$this->isCsrfTokenValid('ea-delete', $csrfToken)) {
  742. return $this->redirectToRoute($context->getDashboardRouteName());
  743. }
  744. return null;
  745. }
  746. }