You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

845 lines
31KB

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