TranslatorAdmin::class, FlashBagTranslator::class => FlashBagTranslator::class, SessionInterface::class => SessionInterface::class, RequestStack::class => RequestStack::class, EntityManagerInterface::class => EntityManagerInterface::class, FilterManager::class => FilterManager::class, ComponentContainer::class => ComponentContainer::class, FileContainer::class => FileContainer::class, NewsletterContainer::class => NewsletterContainer::class, ReminderContainer::class => ReminderContainer::class, NewsContainer::class => NewsContainer::class, PageContainer::class => PageContainer::class, SiteContainer::class => SiteContainer::class, TicketContainer::class => TicketContainer::class, TicketMessageContainer::class => TicketMessageContainer::class, GroupUserContainer::class => GroupUserContainer::class, UserContainer::class => UserContainer::class, SiteSettingContainer::class => SiteSettingContainer::class, MailMailjetNotification::class => MailMailjetNotification::class, ] ); } public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore { if ($responseParameters->get('global_actions')) { $this->overrideGlobalActions($responseParameters->get('global_actions')); } if ($responseParameters->get('entities')) { $this->overrideEntitiesActions($responseParameters->get('entities')); } if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { $responseParameters->set('fields', $this->configureFields('index')); if ($this->filtersForm === null) { die('nncncd'); //TODO delete under code $options['fields'] = $responseParameters->get('fields'); $options['entity_class'] = $this->getEntityFqcn(); $options['entity_name'] = $responseParameters->get('entity')->getName(); $this->filtersForm = $this->createForm(FiltersFormType::class, null, $options); } $responseParameters->set('filters_form', $this->filtersForm); } $responseParameters->set('translation_entity_name', $this->getTranslationEntityName()); return $responseParameters; } public function getTranslationEntityName() { return $this->getEntityFqcn(); } public function overrideEntitiesActions(?EntityCollection $entities): void { } public function overrideGlobalActions(?ActionCollection $actions): void { if ($actions) { $context = $this->get(AdminContextProvider::class)->getContext(); $adminUrlGenerator = $this->get(AdminUrlGenerator::class); foreach ($actions as $i => $action) { //récriture du bouton 'retour au parent' if ($action->getName() == 'index_parent') { $entity = $context->getEntity()->getInstance(); if ($entity !== null) { if ($entity->getParent() !== null) { $url = $adminUrlGenerator ->setController($context->getCrud()->getControllerFqcn()) ->set('entityId', $entity->getParent()->getId()) ->generateUrl(); $action->setLinkUrl($url); } } else { unset($actions[$i]); } } if ($action->getName() == 'sort') { $entityId = $context->getRequest()->get('entityId'); if ($entityId != null) { $url = $adminUrlGenerator ->setController($context->getCrud()->getControllerFqcn()) ->setAction($action->getName()) ->set('entityId', $entityId) ->generateUrl(); $action->setLinkUrl($url); } } } } } public function configureCrud(Crud $crud): Crud { $crud = parent::configureCrud($crud); $this->setMaxResults($crud); $crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]); if ($this->isInstanceOf(SortableInterface::class)) { $crud->setDefaultSort(['position' => 'ASC']); } return $crud; } public function addFlashTranslator(string $type, $translationKeyName, $translationEntityName = null, $translationParam = array()):void { if ($translationEntityName === null && method_exists($this, 'getTranslationEntityName')) { $translationEntityName = $this->getTranslationEntityName(); } $this->get(FlashBagTranslator::class)->add($type, $translationKeyName, $translationEntityName, $translationParam); } public function setMaxResults(Crud $crud): void { $entityClass = $this->getEntityFqcn(); $paramListMaxResults = 'listMaxResults'; $paramSessionListMaxResults = $entityClass . '-' . $paramListMaxResults; $requestListMaxResults = $this->get(RequestStack::class)->getCurrentRequest()->get($paramListMaxResults); if ($requestListMaxResults) { $this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults); } $maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get( $paramSessionListMaxResults ) : 30; $crud->setPaginatorPageSize($maxResults); } public function getSeoPanel(): ?array { if ($this->isInstanceOf(SeoInterface::class)) { return [ FormField::addPanel('seo')->setTemplateName('crud/field/generic'), TextField::new('metaTitle')->setLabel('Meta Title')->setHelp( 'Affiché dans les résultats de recherche Google' )->hideOnIndex(), TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp( 'Affiché dans les résultats de recherche Google' )->hideOnIndex(), CollectionField::new('oldUrls') ->setFormTypeOption('entry_type', TextType::class)->setLabel( 'Anciennes urls du document' )->hideOnIndex(), ]; } else { return null; } } public function getConfPanel(): ?array { if ($this->isInstanceOf(DevAliasInterface::class)) { return [ FormField::addPanel('configuration')->setTemplateName('crud/field/generic'), TextField::new('devAlias')->hideOnIndex(), ]; } else { return null; } } public function sort(AdminContext $context) { $event = new BeforeCrudActionEvent($context); $this->get('event_dispatcher')->dispatch($event); if ($event->isPropagationStopped()) { return $event->getResponse(); } //if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) { if (!$this->isInstanceOf(SortableInterface::class)) { throw new ForbiddenActionException($context); } $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); $filters = $this->get(FilterFactory::class)->create( $context->getCrud()->getFiltersConfig(), $fields, $context->getEntity() ); $queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters); $paginator = $this->get(PaginatorFactory::class)->create($queryBuilder); $entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults()); $this->get(EntityFactory::class)->processFieldsForAll($entities, $fields); $sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults())) ->add( 'entities', CollectionType::class, array( 'required' => true, 'allow_add' => true, 'entry_type' => PositionType::class, ) ) ->getForm(); $entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn()); $repository = $entityManager->getRepository($this->getEntityFqcn()); $sortableForm->handleRequest($context->getRequest()); if ($sortableForm->isSubmitted() && $sortableForm->isValid()) { foreach ($sortableForm->get('entities')->getData() as $elm) { $entityInstance = $repository->find($elm['id']); $entityDto = $context->getEntity()->newWithInstance($entityInstance); if (!$entityDto->isAccessible()) { throw new InsufficientEntityPermissionException($context); } $event = new BeforeEntityDeletedEvent($entityInstance); $this->get('event_dispatcher')->dispatch($event); $entityInstance = $event->getEntityInstance(); $entityInstance->setPosition($elm['position']); $this->updateEntity($entityManager, $entityInstance); $this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance)); } $url = $this->get(AdminUrlGenerator::class) ->setAction(Action::INDEX) ->generateUrl(); $this->addFlashTranslator('success', 'sorted'); return $this->redirect($url); } $responseParameters = $this->configureResponseParameters( KeyValueStore::new( [ 'pageName' => Crud::PAGE_INDEX, 'templatePath' => '@LcSov/adminlte/crud/sort.html.twig', 'entities' => $entities, 'paginator' => $paginator, 'global_actions' => array(), 'batch_actions' => array(), 'filters' => $filters, 'sortable_form' => $sortableForm, ] ) ); $responseParameters->set('fields', $this->configureFields('index')); $event = new AfterCrudActionEvent($context, $responseParameters); $this->get('event_dispatcher')->dispatch($event); if ($event->isPropagationStopped()) { return $event->getResponse(); } return $responseParameters; } public function duplicate( AdminContext $context, EntityComponent $entityComponent, TranslatorAdmin $translatorAdmin, EntityManagerInterface $em ) { if (!$this->isGranted( Permission::EA_EXECUTE_ACTION, ['action' => "duplicate", 'entity' => $context->getEntity()] )) { throw new ForbiddenActionException($context); } if (!$context->getEntity()->isAccessible()) { throw new InsufficientEntityPermissionException($context); } $newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance()); $em->create($newEntity); $em->flush(); $url = $this->get(AdminUrlGenerator::class) ->setAction(Action::EDIT) ->setEntityId($newEntity->getId()) ->generateUrl(); $this->addFlashTranslator('success', 'duplicated'); return $this->redirect($url); } public function createIndexQueryBuilder( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): QueryBuilder { $queryBuilder = parent::createIndexQueryBuilder( $searchDto, $entityDto, $fields, $filters ); //TOdo utiliser les repositoryQuery ? if ($this->isInstanceOf(TreeInterface::class)) { $entityId = $searchDto->getRequest()->get('entityId'); if ($entityId !== null) { $queryBuilder->andWhereParent('entity', $entityId); } else { $queryBuilder->andWhereParentIsNull('entity'); } } $this->filtersForm = $this->createForm( FiltersFormType::class, null, array( 'fields' => $fields, 'entity_dto' => $entityDto, 'entity_class' => $this->getEntityFqcn(), 'entity_name' => $entityDto->getName(), ) ); $filterManager = $this->get(FilterManager::class); $this->filtersForm->handleRequest($searchDto->getRequest()); /*if (($this->filtersForm->isSubmitted() && $this->filtersForm->isValid())) { }*/ $filterManager->handleFiltersForm($queryBuilder, $this->filtersForm, $fields, $entityDto); return $queryBuilder; } public function createSortQueryBuilder( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): QueryBuilder { $queryBuilder = $this->createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters); return $queryBuilder; } public function edit(AdminContext $context) { $response = parent::edit($context);; // on vide le flash bag si édition en ajax (notification déjà affichée en Javascript) if ($context->getRequest()->isXmlHttpRequest()) { $this->get('session')->getFlashBag()->clear(); } return $response; } public function isInstanceOf(string $interfaceName): bool { return in_array($interfaceName, class_implements($this->getEntityFqcn())); } public function getControllerFqcnByInterface(string $interface): string { $context = $this->get(AdminContextProvider::class)->getContext(); return $context->getCrudControllers()->findCrudFqcnByEntityFqcn( $this->get(EntityManagerInterface::class)->getEntityName($interface) ); } public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void { $entityManager->update($entityInstance); $entityManager->flush(); $this->get(FlashBagTranslator::class)->add('success', 'updated', $this->getTranslationEntityName()); } public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void { $entityManager->create($entityInstance); $entityManager->flush(); $this->get(FlashBagTranslator::class)->add('success', 'created', $this->getTranslationEntityName()); } public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void { $entityManager->delete($entityInstance); $entityManager->flush(); $this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName()); } public function configureActions(Actions $actions): Actions { $this->buildIndexActions($actions); $this->buildEditActions($actions); $this->buildDetailActions($actions); $this->buildNewActions($actions); $this->handleTranslatableEntityActions($actions); $this->handleSortableEntityActions($actions); $this->handleTreeEntityActions($actions); /*$actions->reorder(Crud::PAGE_EDIT, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_CONTINUE, Action::DELETE]); $actions->reorder(Crud::PAGE_NEW, [Action::INDEX, Action::SAVE_AND_RETURN, Action::SAVE_AND_ADD_ANOTHER]);*/ return $actions; } public function getDuplicateAction(): Action { $duplicateAction = Action::new( 'duplicate', $this->get(TranslatorAdmin::class)->transAction('duplicate'), 'fa fa-fw fa-copy' ) ->linkToCrudAction('duplicate') ->setLabel($this->get(TranslatorAdmin::class)->transAction('duplicate')) ->setCssClass('in-dropdown text-info action-confirm'); return $duplicateAction; } public function buildIndexActions(Actions $actions): void { $actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction()); $this->actionUpdate( $actions, Crud::PAGE_INDEX, Action::NEW, [ 'icon' => 'plus', 'label' => $this->get(TranslatorAdmin::class)->transAction('create'), 'add_class' => 'btn-sm', ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, Action::EDIT, [ 'class' => 'btn btn-sm btn-primary', 'icon' => 'edit', 'label' => false, 'html_attributes' => array( 'data-toggle' => 'tooltip', 'title' => $this->get(TranslatorAdmin::class)->transAction('edit'), ), ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, Action::DETAIL, [ 'icon' => 'eye', 'add_class' => 'btn btn-sm btn-success', 'label' => false, 'html_attributes' => array( 'data-toggle' => 'tooltip', 'title' => $this->get(TranslatorAdmin::class)->transAction('detail'), ), ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, Action::DELETE, [ 'icon' => 'trash', 'dropdown' => true, 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, Action::BATCH_DELETE, [ 'class' => 'btn btn-sm btn-danger', 'icon' => 'trash', 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), ] ); } public function buildEditActions(Actions $actions): void { $actions->add(Crud::PAGE_EDIT, Action::INDEX); $actions->add(Crud::PAGE_EDIT, Action::DELETE); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::SAVE_AND_RETURN, [ 'add_class' => 'float-right ', 'icon' => 'check', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::INDEX, [ 'icon' => 'chevron-left', 'class' => 'btn btn-link', 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::SAVE_AND_CONTINUE, [ 'class' => 'btn btn-info float-right action-save-continue', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::DELETE, [ 'icon' => 'trash', 'class' => 'btn btn-outline-danger action-delete', 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), ] ); } public function buildDetailActions(Actions $actions): void { } public function buildNewActions(Actions $actions): void { $actions->add(Crud::PAGE_NEW, Action::INDEX); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::SAVE_AND_RETURN, [ 'add_class' => 'float-right', 'icon' => 'check', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::INDEX, [ 'icon' => 'chevron-left', 'class' => 'btn btn-link', 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, Action::SAVE_AND_ADD_ANOTHER, [ 'class' => 'btn btn-info float-right', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'), ] ); } public function handleTranslatableEntityActions(Actions $actions): void { if ($this->isInstanceOf(TranslatableInterface::class)) { $actions->update( Crud::PAGE_INDEX, Action::EDIT, function (Action $action) { $action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig'); return $action; } ); } } public function handleSortableEntityActions(Actions $actions): void { if ($this->isInstanceOf(SortableInterface::class)) { $sortAction = Action::new('sort', $this->get(TranslatorAdmin::class)->transAction('sort'), 'fa fa-sort') ->linkToCrudAction('sort') ->setCssClass('btn btn-sm btn-success') ->createAsGlobalAction(); $actions->add(Crud::PAGE_INDEX, $sortAction); } } public function handleTreeEntityActions(Actions $actions): void { if ($this->isInstanceOf(TreeInterface::class)) { $indexChildAction = Action::new( 'index_children', $this->get(TranslatorAdmin::class)->transAction('index_children'), 'fa fa-list' ) ->linkToCrudAction(Action::INDEX) ->setLabel('') ->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants')) ->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig') ->setCssClass('btn btn-sm btn-success'); $backParentAction = Action::new( 'index_parent', $this->get(TranslatorAdmin::class)->transAction('index_parent'), 'fa fa-chevron-left' ) ->linkToCrudAction(Action::INDEX) ->setCssClass('btn btn-sm btn-info') ->createAsGlobalAction(); $actions->add(Crud::PAGE_INDEX, $backParentAction); $actions->add(Crud::PAGE_INDEX, $indexChildAction); } } public function actionUpdate($actions, $crudActionName, $actionName, array $button): void { if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) { $actions->update( $crudActionName, $actionName, function (Action $action) use ($button) { if (isset($button['add_class'])) { $action->addCssClass($button['add_class']); } if (isset($button['class'])) { $action->setCssClass($button['class']); } if (isset($button['icon'])) { $action->setIcon('fa fa-' . $button['icon']); } if (isset($button['label'])) { $action->setLabel($button['label']); } if (isset($button['dropdown']) && $button['dropdown']) { $action->addCssClass('in-dropdown'); } if (isset($button['html_attributes']) && $button['html_attributes']) { $action->setHtmlAttributes($button['html_attributes']); } return $action; } ); } } public function autocompleteFilter(AdminContext $context): JsonResponse { $queryBuilder = $this->createIndexQueryBuilder( $context->getSearch(), $context->getEntity(), FieldCollection::new([]), FilterCollection::new() ); $autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT); /** @var CrudControllerInterface $controller */ $controller = $this->get(ControllerFactory::class)->getCrudControllerInstance( $autocompleteContext[EA::CRUD_CONTROLLER_FQCN], Action::INDEX, $context->getRequest() ); /** @var FieldDto $field */ $field = FieldCollection::new( $controller->configureFields($autocompleteContext['originatingPage']) )->getByProperty($autocompleteContext['propertyName']); $filterManager = $this->get(FilterManager::class); $filterManager->applyFilter($queryBuilder, $field, $context->getRequest()->query->get('q')); if ($filterManager->isRelationField($field->getProperty())) { $queryBuilder->select($autocompleteContext['propertyName']); } else { $queryBuilder->select('entity.' . $autocompleteContext['propertyName']); } $responses = array(); foreach ($queryBuilder->getQuery()->getArrayResult() as $result) { $responses[] = array_values($result)[0]; } return JsonResponse::fromJsonString(json_encode($responses)); } public function createCustomForm($class, $action, $controller, $entity, $dataInOption = true, $options = array()) { if ($dataInOption) { $options['data'] = $entity; } $options['action'] = $this->get(AdminUrlGenerator::class) ->setAction($action) ->setController($controller) ->setEntityId($entity->getId()) ->generateUrl(); return $this->createForm($class, null, $options); } }