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.

622 satır
23KB

  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\Context\AdminContext;
  14. use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController;
  15. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  16. use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
  17. use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
  18. use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
  19. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
  20. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
  21. use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
  22. use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
  23. use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
  24. use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
  25. use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory;
  26. use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
  27. use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
  28. use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
  29. use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
  30. use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
  31. use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
  32. use Lc\SovBundle\Doctrine\Extension\SeoInterface;
  33. use Lc\SovBundle\Doctrine\Extension\SortableInterface;
  34. use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
  35. use Lc\SovBundle\Doctrine\Extension\TreeInterface;
  36. use Lc\SovBundle\Field\CollectionField;
  37. use Lc\SovBundle\Form\Common\PositionType;
  38. use Lc\SovBundle\Translation\TranslatorAdmin;
  39. use Symfony\Component\Form\Extension\Core\Type\CollectionType;
  40. use Symfony\Component\Form\Extension\Core\Type\TextType;
  41. use Symfony\Component\HttpFoundation\RequestStack;
  42. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  43. abstract class AbstractAdminController extends EaAbstractCrudController
  44. {
  45. public static function getSubscribedServices()
  46. {
  47. return array_merge(
  48. parent::getSubscribedServices(),
  49. [
  50. 'session' => SessionInterface::class,
  51. 'request' => RequestStack::class,
  52. 'em' => EntityManagerInterface::class,
  53. 'translator_admin' => TranslatorAdmin::class,
  54. ]
  55. );
  56. }
  57. public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore
  58. {
  59. $this->overrideGlobalActions($responseParameters->get('global_actions'));
  60. $this->overrideEntitiesActions($responseParameters->get('entities'));
  61. if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
  62. $responseParameters->set('fields', $this->configureFields('index'));
  63. }
  64. return $responseParameters;
  65. }
  66. public function overrideEntitiesActions(?EntityCollection $entities): void
  67. {
  68. }
  69. public function overrideGlobalActions(?ActionCollection $actions): void
  70. {
  71. if ($actions) {
  72. $context = $this->get(AdminContextProvider::class)->getContext();
  73. $adminUrlGenerator = $this->get(AdminUrlGenerator::class);
  74. foreach ($actions as $i => $action) {
  75. //récriture du bouton 'retour au parent'
  76. if ($action->getName() == 'index_parent') {
  77. $entity = $context->getEntity()->getInstance();
  78. if ($entity !== null) {
  79. if ($entity->getParent() !== null) {
  80. $url = $adminUrlGenerator
  81. ->setController($context->getCrud()->getControllerFqcn())
  82. ->set('entityId', $entity->getParent()->getId())
  83. ->generateUrl();
  84. $action->setLinkUrl($url);
  85. }
  86. } else {
  87. unset($actions[$i]);
  88. }
  89. }
  90. if ($action->getName() == 'sort') {
  91. $entityId = $context->getRequest()->get('entityId');
  92. if ($entityId != null) {
  93. $url = $adminUrlGenerator
  94. ->setController($context->getCrud()->getControllerFqcn())
  95. ->setAction($action->getName())
  96. ->set('entityId', $entityId)
  97. ->generateUrl();
  98. $action->setLinkUrl($url);
  99. }
  100. }
  101. }
  102. }
  103. }
  104. public function configureCrud(Crud $crud): Crud
  105. {
  106. $crud = parent::configureCrud($crud);
  107. $this->setMaxResults($crud);
  108. if ($this->isInstanceOf(SortableInterface::class)) {
  109. $crud->setDefaultSort(['position' => 'ASC']);
  110. }
  111. return $crud;
  112. }
  113. public function setMaxResults(Crud $crud): void
  114. {
  115. $entityClass = $this->getEntityFqcn();
  116. $paramListMaxResults = 'listMaxResults';
  117. $paramSessionListMaxResults = $entityClass.'-'.$paramListMaxResults;
  118. $requestListMaxResults = $this->get('request')->getCurrentRequest()->get($paramListMaxResults);
  119. if ($requestListMaxResults) {
  120. $this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults);
  121. }
  122. $maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get(
  123. $paramSessionListMaxResults
  124. ) : 30;
  125. $crud->setPaginatorPageSize($maxResults);
  126. }
  127. public function configureFields(string $pageName): iterable
  128. {
  129. $seoPanel = $confPanel = array();
  130. if ($this->isInstanceOf(SeoInterface::class)) {
  131. $seoPanel = [
  132. FormField::addPanel('seo')->setTemplateName('crud/field/generic'),
  133. TextField::new('metaTitle')->setLabel('Meta Title')->setHelp(
  134. 'Affiché dans les résultats de recherche Google'
  135. )->hideOnIndex(),
  136. TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp(
  137. 'Affiché dans les résultats de recherche Google'
  138. )->hideOnIndex(),
  139. CollectionField::new('oldUrls')
  140. ->setFormTypeOption('entry_type', TextType::class)->setLabel(
  141. 'Anciennes urls du document'
  142. )->hideOnIndex(),
  143. ];
  144. }
  145. if ($this->isInstanceOf(DevAliasInterface::class)) {
  146. $confPanel = [
  147. FormField::addPanel('configuration')->setTemplateName('crud/field/generic'),
  148. TextField::new('devAlias')->hideOnIndex(),
  149. ];
  150. }
  151. return array_merge($seoPanel, $confPanel);
  152. }
  153. public function sort(AdminContext $context)
  154. {
  155. $event = new BeforeCrudActionEvent($context);
  156. $this->get('event_dispatcher')->dispatch($event);
  157. if ($event->isPropagationStopped()) {
  158. return $event->getResponse();
  159. }
  160. //if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) {
  161. if (!$this->isInstanceOf(SortableInterface::class)) {
  162. throw new ForbiddenActionException($context);
  163. }
  164. $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
  165. $filters = $this->get(FilterFactory::class)->create(
  166. $context->getCrud()->getFiltersConfig(),
  167. $fields,
  168. $context->getEntity()
  169. );
  170. $queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);
  171. $paginator = $this->get(PaginatorFactory::class)->create($queryBuilder);
  172. $entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults());
  173. $this->get(EntityFactory::class)->processFieldsForAll($entities, $fields);
  174. $sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults()))
  175. ->add(
  176. 'entities',
  177. CollectionType::class,
  178. array(
  179. 'required' => true,
  180. 'allow_add' => true,
  181. 'entry_type' => PositionType::class,
  182. )
  183. )
  184. ->getForm();
  185. $entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn());
  186. $repository = $entityManager->getRepository($this->getEntityFqcn());
  187. $sortableForm->handleRequest($context->getRequest());
  188. if ($sortableForm->isSubmitted() && $sortableForm->isValid()) {
  189. foreach ($sortableForm->get('entities')->getData() as $elm) {
  190. $entityInstance = $repository->find($elm['id']);
  191. $entityDto = $context->getEntity()->newWithInstance($entityInstance);
  192. if (!$entityDto->isAccessible()) {
  193. throw new InsufficientEntityPermissionException($context);
  194. }
  195. $event = new BeforeEntityDeletedEvent($entityInstance);
  196. $this->get('event_dispatcher')->dispatch($event);
  197. $entityInstance = $event->getEntityInstance();
  198. $entityInstance->setPosition($elm['position']);
  199. $this->updateEntity($entityManager, $entityInstance);
  200. $this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
  201. }
  202. $url = $this->get(AdminUrlGenerator::class)
  203. ->setAction(Action::INDEX)
  204. ->generateUrl();
  205. $this->addFlash('success', $this->translatorAdmin->transFlashMessage('sort'), array());
  206. return $this->redirect($url);
  207. }
  208. $responseParameters = $this->configureResponseParameters(
  209. KeyValueStore::new(
  210. [
  211. 'pageName' => Crud::PAGE_INDEX,
  212. 'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
  213. 'entities' => $entities,
  214. 'paginator' => $paginator,
  215. 'global_actions' => array(),
  216. 'batch_actions' => array(),
  217. 'filters' => $filters,
  218. 'sortable_form' => $sortableForm,
  219. ]
  220. )
  221. );
  222. $responseParameters->set('fields', $this->configureFields('index'));
  223. $event = new AfterCrudActionEvent($context, $responseParameters);
  224. $this->get('event_dispatcher')->dispatch($event);
  225. if ($event->isPropagationStopped()) {
  226. return $event->getResponse();
  227. }
  228. return $responseParameters;
  229. }
  230. public function createIndexQueryBuilder(
  231. SearchDto $searchDto,
  232. EntityDto $entityDto,
  233. FieldCollection $fields,
  234. FilterCollection $filters
  235. ): QueryBuilder {
  236. $queryBuilder = parent::createIndexQueryBuilder(
  237. $searchDto,
  238. $entityDto,
  239. $fields,
  240. $filters
  241. );
  242. //TOdo utiliser les repositoryQuery ?
  243. if ($this->isInstanceOf(TreeInterface::class)) {
  244. $entityId = $searchDto->getRequest()->get('entityId');
  245. if ($entityId !== null) {
  246. $queryBuilder->andWhere('entity.parent = :entityId');
  247. $queryBuilder->setParameter('entityId', $searchDto->getRequest()->get('entityId'));
  248. } else {
  249. $queryBuilder->andWhere('entity.parent IS NULL');
  250. }
  251. }
  252. return $queryBuilder;
  253. }
  254. public function createSortQueryBuilder(
  255. SearchDto $searchDto,
  256. EntityDto $entityDto,
  257. FieldCollection $fields,
  258. FilterCollection $filters
  259. ): QueryBuilder {
  260. $queryBuilder = $this->createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);
  261. return $queryBuilder;
  262. }
  263. public function edit(AdminContext $context)
  264. {
  265. $response = parent::edit($context);;
  266. // on vide le flash bag si édition en ajax (notification déjà affichée en Javascript)
  267. if ($context->getRequest()->isXmlHttpRequest()) {
  268. $this->get('session')->getFlashBag()->clear();
  269. }
  270. return $response;
  271. }
  272. public function isInstanceOf(string $interfaceName): bool
  273. {
  274. return in_array($interfaceName, class_implements($this->getEntityFqcn()));
  275. }
  276. public function getControllerFqcnByInterface(string $interface): string
  277. {
  278. $context = $this->get(AdminContextProvider::class)->getContext();
  279. return $context->getCrudControllers()->findCrudFqcnByEntityFqcn(
  280. $this->get('em')->getEntityName($interface)
  281. );
  282. }
  283. public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
  284. {
  285. $entityManager->update($entityInstance);
  286. $entityManager->flush();
  287. }
  288. public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
  289. {
  290. $entityManager->create($entityInstance);
  291. $entityManager->flush();
  292. }
  293. public function configureActions(Actions $actions): Actions
  294. {
  295. $this->buildIndexActions($actions);
  296. $this->buildEditActions($actions);
  297. $this->buildDetailActions($actions);
  298. $this->buildNewActions($actions);
  299. $this->handleTranslatableEntityActions($actions);
  300. $this->handleSortableEntityActions($actions);
  301. $this->handleTreeEntityActions($actions);
  302. /*$actions->reorder(Crud::PAGE_EDIT, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_CONTINUE, Action::DELETE]);
  303. $actions->reorder(Crud::PAGE_NEW, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_ADD_ANOTHER]);*/
  304. return $actions;
  305. }
  306. public function buildIndexActions(Actions $actions): void
  307. {
  308. $this->actionUpdate(
  309. $actions,
  310. Crud::PAGE_INDEX,
  311. Action::NEW,
  312. [
  313. 'icon' => 'plus',
  314. 'label' => $this->get('translator_admin')->transAction('create'),
  315. 'add_class' => 'btn-sm',
  316. ]
  317. );
  318. $this->actionUpdate(
  319. $actions,
  320. Crud::PAGE_INDEX,
  321. Action::EDIT,
  322. [
  323. 'class' => 'btn btn-sm btn-primary',
  324. 'icon' => 'edit',
  325. 'label' => false,
  326. 'html_attributes' => array(
  327. 'data-toggle' => 'tooltip',
  328. 'title' => $this->get('translator_admin')->transAction('edit'),
  329. ),
  330. ]
  331. );
  332. $this->actionUpdate(
  333. $actions,
  334. Crud::PAGE_INDEX,
  335. Action::DETAIL,
  336. [
  337. 'icon' => 'eye',
  338. 'add_class' => 'btn btn-sm btn-success',
  339. 'label' => false,
  340. 'html_attributes' => array(
  341. 'data-toggle' => 'tooltip',
  342. 'title' => $this->get('translator_admin')->transAction('detail'),
  343. ),
  344. ]
  345. );
  346. $this->actionUpdate(
  347. $actions,
  348. Crud::PAGE_INDEX,
  349. Action::DELETE,
  350. [
  351. 'icon' => 'trash',
  352. 'dropdown' => true,
  353. 'label' => $this->get('translator_admin')->transAction('delete'),
  354. ]
  355. );
  356. $this->actionUpdate(
  357. $actions,
  358. Crud::PAGE_INDEX,
  359. Action::BATCH_DELETE,
  360. [
  361. 'class' => 'btn btn-sm btn-danger',
  362. 'icon' => 'trash',
  363. 'label' => $this->get('translator_admin')->transAction('delete'),
  364. ]
  365. );
  366. }
  367. public function buildEditActions(Actions $actions): void
  368. {
  369. $actions->add(Crud::PAGE_EDIT, Action::INDEX);
  370. $actions->add(Crud::PAGE_EDIT, Action::DELETE);
  371. $this->actionUpdate(
  372. $actions,
  373. Crud::PAGE_EDIT,
  374. Action::SAVE_AND_RETURN,
  375. [
  376. 'add_class' => 'float-right',
  377. 'icon' => 'check',
  378. 'label' => $this->get('translator_admin')->transAction('save_and_return'),
  379. ]
  380. );
  381. $this->actionUpdate(
  382. $actions,
  383. Crud::PAGE_EDIT,
  384. Action::INDEX,
  385. [
  386. 'icon' => 'chevron-left',
  387. 'class' => 'btn btn-link',
  388. 'label' => $this->get('translator_admin')->transAction('back_index'),
  389. ]
  390. );
  391. $this->actionUpdate(
  392. $actions,
  393. Crud::PAGE_EDIT,
  394. Action::SAVE_AND_CONTINUE,
  395. [
  396. 'class' => 'btn btn-info float-right',
  397. 'label' => $this->get('translator_admin')->transAction('save_and_continue'),
  398. ]
  399. );
  400. $this->actionUpdate(
  401. $actions,
  402. Crud::PAGE_EDIT,
  403. Action::DELETE,
  404. [
  405. 'icon' => 'trash',
  406. 'class' => 'btn btn-outline-danger action-delete',
  407. 'label' => $this->get('translator_admin')->transAction('delete'),
  408. ]
  409. );
  410. }
  411. public function buildDetailActions(Actions $actions): void
  412. {
  413. }
  414. public function buildNewActions(Actions $actions): void
  415. {
  416. $actions->add(Crud::PAGE_NEW, Action::INDEX);
  417. $this->actionUpdate(
  418. $actions,
  419. Crud::PAGE_EDIT,
  420. Action::SAVE_AND_RETURN,
  421. [
  422. 'add_class' => 'float-right',
  423. 'icon' => 'check',
  424. 'label' => $this->get('translator_admin')->transAction('save_and_return'),
  425. ]
  426. );
  427. $this->actionUpdate(
  428. $actions,
  429. Crud::PAGE_EDIT,
  430. Action::INDEX,
  431. [
  432. 'icon' => 'chevron-left',
  433. 'class' => 'btn btn-link',
  434. 'label' => $this->get('translator_admin')->transAction('back_index'),
  435. ]
  436. );
  437. $this->actionUpdate(
  438. $actions,
  439. Crud::PAGE_EDIT,
  440. Action::SAVE_AND_ADD_ANOTHER,
  441. [
  442. 'class' => 'btn btn-info float-right',
  443. 'label' => $this->get('translator_admin')->transAction('save_and_add_another'),
  444. ]
  445. );
  446. }
  447. public function handleTranslatableEntityActions(Actions $actions): void
  448. {
  449. if ($this->isInstanceOf(TranslatableInterface::class)) {
  450. $actions->update(
  451. Crud::PAGE_INDEX,
  452. Action::EDIT,
  453. function (Action $action) {
  454. $action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig');
  455. return $action;
  456. }
  457. );
  458. }
  459. }
  460. public function handleSortableEntityActions(Actions $actions): void
  461. {
  462. if ($this->isInstanceOf(SortableInterface::class)) {
  463. $sortAction = Action::new('sort', $this->get('translator_admin')->transAction('sort'), 'fa fa-sort')
  464. ->linkToCrudAction('sort')
  465. ->setCssClass('btn btn-sm btn-success')
  466. ->createAsGlobalAction();
  467. $actions->add(Crud::PAGE_INDEX, $sortAction);
  468. }
  469. }
  470. public function handleTreeEntityActions(Actions $actions): void
  471. {
  472. if ($this->isInstanceOf(TreeInterface::class)) {
  473. $indexChildAction = Action::new(
  474. 'index_children',
  475. $this->get('translator_admin')->transAction('index_children'),
  476. 'fa fa-list'
  477. )
  478. ->linkToCrudAction(Action::INDEX)
  479. ->setLabel('')
  480. ->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants'))
  481. ->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig')
  482. ->setCssClass('btn btn-sm btn-success');
  483. $backParentAction = Action::new(
  484. 'index_parent',
  485. $this->get('translator_admin')->transAction('index_parent'),
  486. 'fa fa-chevron-left'
  487. )
  488. ->linkToCrudAction(Action::INDEX)
  489. ->setCssClass('btn btn-sm btn-info')
  490. ->createAsGlobalAction();
  491. $actions->add(Crud::PAGE_INDEX, $backParentAction);
  492. $actions->add(Crud::PAGE_INDEX, $indexChildAction);
  493. }
  494. }
  495. public function actionUpdate($actions, $crudActionName, $actionName, array $button): void
  496. {
  497. if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) {
  498. $actions->update(
  499. $crudActionName,
  500. $actionName,
  501. function (Action $action) use ($button) {
  502. if (isset($button['add_class'])) {
  503. $action->addCssClass($button['add_class']);
  504. }
  505. if (isset($button['class'])) {
  506. $action->setCssClass($button['class']);
  507. }
  508. if (isset($button['icon'])) {
  509. $action->setIcon('fa fa-'.$button['icon']);
  510. }
  511. if (isset($button['label'])) {
  512. $action->setLabel($button['label']);
  513. }
  514. if (isset($button['dropdown']) && $button['dropdown']) {
  515. $action->addCssClass('in-dropdown');
  516. }
  517. if (isset($button['html_attributes']) && $button['html_attributes']) {
  518. $action->setHtmlAttributes($button['html_attributes']);
  519. }
  520. return $action;
  521. }
  522. );
  523. }
  524. }
  525. }