get('global_actions')) { $this->overrideGlobalActions($responseParameters->get('global_actions')); } if ($responseParameters->get('entities')) { $this->overrideEntitiesActions($responseParameters->get('entities'), $responseParameters->get('pageName')); } if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) { $responseParameters->set('fields', $this->configureFields('index')); if (isset($this->filtersForm)) { $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, string $pageName): 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); } } if ($action->getName() == ActionDefinition::WRITE_TO_USER) { $entity = $context->getEntity()->getInstance(); if ($entity !== null) { if (method_exists($entity, 'getUser')) { $url = $this->generateEaUrl(UserA)->setController($context->getCrud()->getControllerFqcn()) ->set('entityId', $entity->getParent()->getId()) ->generateUrl(); $action->setLinkUrl($url); } } else { unset($actions[$i]); } } } } } protected function getRequestCrudAction(): string { return $this->getRequestStack()->getCurrentRequest()->get('crudAction'); } public function configureCrud(Crud $crud): Crud { $crud = parent::configureCrud($crud); if ($this->getRequestCrudAction() === ActionDefinition::SORT) { $crud->setPaginatorPageSize(9999); } else { $this->setMaxResults($crud); } $crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]); if ($this->isInstanceOf(SortableInterface::class)) { $crud->setDefaultSort(['position' => 'ASC']); } else { $crud->setDefaultSort(['id' => 'DESC']); } return $crud; } 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->createSortQueryBuilder($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 BeforeEntityUpdatedEvent($entityInstance); $this->get('event_dispatcher')->dispatch($event); $entityInstance = $event->getEntityInstance(); $entityInstance->setPosition($elm['position']); $this->updateEntity($entityManager, $entityInstance); // @TODO : ce dispatch déclenche UpdateProductfamilyAfterFlushEventSubscriber dans Caracole et on tombe sur une erreur "Maximum execution time" //$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance)); } $url = $this->get(AdminUrlGenerator::class) ->setAction(ActionDefinition::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' => ActionDefinition::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, false); $em->flush(); $url = $this->get(AdminUrlGenerator::class) ->setAction(ActionDefinition::EDIT) ->setEntityId($newEntity->getId()) ->generateUrl(); $this->addFlashTranslator('success', ActionDefinition::DUPLICATE); return $this->redirect($url); } public function isRepositoryQueryFiltered(): bool { if (($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered) { return true; } else { return false; } } public function createIndexRepositoryQuery( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): RepositoryQueryInterface { $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery( $this->getRepositoryQuery(), $searchDto, $entityDto, $fields, $filters ); // TODO : déplacer dans EntotyRepository if ($this->isInstanceOf(TreeInterface::class)) { if ($entityDto->getInstance()) { $repositoryQuery->filterByParent($entityDto->getInstance()); } else { $repositoryQuery->filterIsParent(); } } if ($this->isInstanceOf(StatusInterface::class)) { $repositoryQuery->filterIsOnlineAndOffline(); } $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()); $this->isRepositoryQueryFiltered = $filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto); return $repositoryQuery; } public function createSortRepositoryQuery( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): RepositoryQueryInterface { $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters); if ($this->isInstanceOf(StatusInterface::class)) { $repositoryQuery->filterIsOnline(); } $repositoryQuery->orderBy('position', 'asc'); return $repositoryQuery; } public function createIndexQueryBuilder( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): QueryBuilder { $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters); return $repositoryQuery->getQueryBuilder(); } public function createSortQueryBuilder( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters ): QueryBuilder { $repositoryQuery = $this->createSortRepositoryQuery($searchDto, $entityDto, $fields, $filters); return $repositoryQuery->getQueryBuilder(); } 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 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 { if ($this->isInstanceOf(StatusInterface::class)) { $entityInstance->setStatus(-1); $entityManager->update($entityInstance); } else { $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, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_CONTINUE, ActionDefinition::DELETE]); $actions->reorder(Crud::PAGE_NEW, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_ADD_ANOTHER]);*/ return $actions; } public function getDuplicateAction(): Action { $duplicateAction = Action::new( ActionDefinition::DUPLICATE, $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE), 'fa fa-fw fa-copy' ) ->linkToCrudAction(ActionDefinition::DUPLICATE) ->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::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, ActionDefinition::NEW, [ 'icon' => 'plus', 'label' => $this->get(TranslatorAdmin::class)->transAction('create'), 'add_class' => 'btn-sm', ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, ActionDefinition::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, ActionDefinition::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, ActionDefinition::DELETE, [ 'icon' => 'trash', 'dropdown' => true, 'label' => $this->get(TranslatorAdmin::class)->transAction('delete'), 'class' => 'dropdown-item text-danger in-dropdown action-delete', ] ); $this->actionUpdate( $actions, Crud::PAGE_INDEX, ActionDefinition::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, ActionDefinition::INDEX); $actions->add(Crud::PAGE_EDIT, ActionDefinition::DELETE); $this->actionUpdate( $actions, Crud::PAGE_EDIT, ActionDefinition::SAVE_AND_RETURN, [ 'add_class' => 'float-right ', 'icon' => 'check', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, ActionDefinition::INDEX, [ 'icon' => 'chevron-left', 'class' => 'btn btn-link', 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), ] ); $this->actionUpdate( $actions, Crud::PAGE_EDIT, ActionDefinition::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, ActionDefinition::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, ActionDefinition::INDEX); $this->actionUpdate( $actions, Crud::PAGE_NEW, ActionDefinition::SAVE_AND_RETURN, [ 'add_class' => 'float-right', 'icon' => 'check', 'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'), ] ); $this->actionUpdate( $actions, Crud::PAGE_NEW, ActionDefinition::INDEX, [ 'icon' => 'chevron-left', 'class' => 'btn btn-link', 'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'), ] ); $this->actionUpdate( $actions, Crud::PAGE_NEW, ActionDefinition::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, ActionDefinition::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( ActionDefinition::SORT, $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SORT), 'fa fa-sort' ) ->linkToCrudAction(ActionDefinition::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( ActionDefinition::INDEX_CHILDREN, $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_CHILDREN), 'fa fa-list' ) ->linkToCrudAction(ActionDefinition::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( ActionDefinition::INDEX_PARENT, $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_PARENT), 'fa fa-chevron-left' ) ->linkToCrudAction(ActionDefinition::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 { $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery( $this->getRepositoryQuery(), $context->getSearch(), $context->getEntity(), FieldCollection::new([]), FilterCollection::new() ); if ($this->isInstanceOf(StatusInterface::class)) { $repositoryQuery->filterIsOnlineAndOffline(); } $autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT); /** @var CrudControllerInterface $controller */ $controller = $this->get(ControllerFactory::class)->getCrudControllerInstance( $autocompleteContext[EA::CRUD_CONTROLLER_FQCN], ActionDefinition::INDEX, $context->getRequest() ); /** @var FieldDto $field */ $field = FieldCollection::new( $controller->configureFields($autocompleteContext['originatingPage']) )->getByProperty($autocompleteContext['propertyName']); $filterManager = $this->get(FilterManager::class); $filteredValue = ['value' => $context->getRequest()->query->get('q')]; $filterManager->applyFilter($repositoryQuery, $field, $filteredValue); $repositoryQuery->select('.' . $autocompleteContext['propertyName']); $responses = array(); foreach ($repositoryQuery->find() 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) { $data = $entity; } else { $data = null; } $options['action'] = $this->get(AdminUrlGenerator::class) ->setAction($action) ->setController($controller) ->setEntityId($entity->getId()) ->generateUrl(); return $this->createForm($class, $data, $options); } public function eaBeforeCrudActionEventDelete(AdminContext $context): ?Response { $event = new BeforeCrudActionEvent($context); $this->container->get('event_dispatcher')->dispatch($event); if ($event->isPropagationStopped()) { return $event->getResponse(); } if (!$this->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => Action::DELETE, 'entity' => $context->getEntity()])) { throw new ForbiddenActionException($context); } if (!$context->getEntity()->isAccessible()) { throw new InsufficientEntityPermissionException($context); } $csrfToken = $context->getRequest()->request->get('token'); if (!$this->isCsrfTokenValid('ea-delete', $csrfToken)) { return $this->redirectToRoute($context->getDashboardRouteName()); } return null; } }