From 542819f30b175ef0e176e7d92dc447673abad068 Mon Sep 17 00:00:00 2001 From: psihius Date: Thu, 25 Jul 2024 12:46:43 +0300 Subject: [PATCH] Embedded crud --- src/Controller/AbstractCrudController.php | 37 +++++- src/Field/EmbedField.php | 23 ++++ src/Form/Type/EmbedType.php | 19 +++ src/Registry/TemplateRegistry.php | 2 + src/Resources/views/crud/embedded.html.twig | 10 ++ .../views/crud/field/embed.html.twig | 122 ++++++++++++++++++ src/Resources/views/crud/form_theme.html.twig | 4 + src/Resources/views/crud/index.html.twig | 1 - 8 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 src/Field/EmbedField.php create mode 100644 src/Form/Type/EmbedType.php create mode 100644 src/Resources/views/crud/embedded.html.twig create mode 100644 src/Resources/views/crud/field/embed.html.twig diff --git a/src/Controller/AbstractCrudController.php b/src/Controller/AbstractCrudController.php index 336c1d7a08..2c3017afd9 100644 --- a/src/Controller/AbstractCrudController.php +++ b/src/Controller/AbstractCrudController.php @@ -3,7 +3,9 @@ namespace EasyCorp\Bundle\EasyAdminBundle\Controller; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; +use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection; @@ -129,6 +131,39 @@ public function index(AdminContext $context) $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); $filters = $this->container->get(FilterFactory::class)->create($context->getCrud()->getFiltersConfig(), $fields, $context->getEntity()); $queryBuilder = $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters); + + /** @var array|null $embedContext */ + $embedContext = $context->getRequest()->query->all('embedContext'); + if (\array_key_exists('mappedBy', $embedContext)) { + $filterProperty = $embedContext['mappedBy']; + $filterValue = $embedContext['embeddedIn'] ?? null; + if (null !== $filterValue) { + // Use the parameter conversion capabilities of Doctrine + $metadata = $queryBuilder->getEntityManager()->getClassMetadata($context->getEntity()->getFqcn()); + $relatedEntityFqcn = $metadata->getAssociationTargetClass($filterProperty); + $relatedEntityMetadata = $queryBuilder->getEntityManager()->getClassMetadata($relatedEntityFqcn); + $type = $relatedEntityMetadata->getTypeOfField($metadata->getSingleIdentifierFieldName()); + if (Type::hasType($type)) { + $doctrineType = Type::getType($type); + $platform = $queryBuilder->getEntityManager()->getConnection()->getDatabasePlatform(); + $filterValue = $doctrineType->convertToDatabaseValue($filterValue, $platform); + } + $rootAlias = current($queryBuilder->getRootAliases()); + $associationMapping = $metadata->getAssociationMapping($filterProperty); + if (in_array($associationMapping['type'], [ClassMetadata::ONE_TO_MANY, ClassMetadata::MANY_TO_MANY], true)) { + $queryBuilder->andWhere(':filterValue MEMBER OF '.sprintf('%s.%s', $rootAlias, $filterProperty)) + ->setParameter('filterValue', $filterValue); + } else { + $queryBuilder->andWhere(sprintf('%s.%s', $rootAlias, $filterProperty) . ' = :filterValue') + ->setParameter('filterValue', $filterValue); + } + } + $field = $fields->getByProperty($filterProperty); + if ($field instanceof FieldDto) { + $fields->unset($field); + } + } + $paginator = $this->container->get(PaginatorFactory::class)->create($queryBuilder); // this can happen after deleting some items and trying to return @@ -147,7 +182,7 @@ public function index(AdminContext $context) $responseParameters = $this->configureResponseParameters(KeyValueStore::new([ 'pageName' => Crud::PAGE_INDEX, - 'templateName' => 'crud/index', + 'templateName' => null !== $embedContext ? 'crud/embedded' : 'crud/index', 'entities' => $entities, 'paginator' => $paginator, 'global_actions' => $actions->getGlobalActions(), diff --git a/src/Field/EmbedField.php b/src/Field/EmbedField.php new file mode 100644 index 0000000000..3ab934e4af --- /dev/null +++ b/src/Field/EmbedField.php @@ -0,0 +1,23 @@ +setProperty($propertyName) + ->setLabel($label) + ->setTemplateName('crud/field/embed') + ->setFormType(EmbedType::class) + ->setFormTypeOption('mapped', false) + ->onlyWhenUpdating() + ; + } +} diff --git a/src/Form/Type/EmbedType.php b/src/Form/Type/EmbedType.php new file mode 100644 index 0000000000..85dc4894f1 --- /dev/null +++ b/src/Form/Type/EmbedType.php @@ -0,0 +1,19 @@ + '@EasyAdmin/flash_messages.html.twig', 'crud/paginator' => '@EasyAdmin/crud/paginator.html.twig', 'crud/index' => '@EasyAdmin/crud/index.html.twig', + 'crud/embedded' => '@EasyAdmin/crud/embedded.html.twig', 'crud/detail' => '@EasyAdmin/crud/detail.html.twig', 'crud/new' => '@EasyAdmin/crud/new.html.twig', 'crud/edit' => '@EasyAdmin/crud/edit.html.twig', @@ -35,6 +36,7 @@ final class TemplateRegistry 'crud/field/datetimetz' => '@EasyAdmin/crud/field/datetimetz.html.twig', 'crud/field/decimal' => '@EasyAdmin/crud/field/decimal.html.twig', 'crud/field/email' => '@EasyAdmin/crud/field/email.html.twig', + 'crud/field/embed' => '@EasyAdmin/crud/field/embed.html.twig', 'crud/field/float' => '@EasyAdmin/crud/field/float.html.twig', 'crud/field/generic' => '@EasyAdmin/crud/field/generic.html.twig', 'crud/field/hidden' => '@EasyAdmin/crud/field/hidden.html.twig', diff --git a/src/Resources/views/crud/embedded.html.twig b/src/Resources/views/crud/embedded.html.twig new file mode 100644 index 0000000000..e3cf549f89 --- /dev/null +++ b/src/Resources/views/crud/embedded.html.twig @@ -0,0 +1,10 @@ +{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} +{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} +{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} +{% set has_footer = entities|length != 0 %} +{% set has_batch_actions = false %} +{% set some_results_are_hidden = false %} +{% set sort_field_name = app.request.get('sort')|keys|first %} +{% set sort_order = app.request.get('sort')|first %} + +{{ block("content", "@EasyAdmin/crud/index.html.twig") }} diff --git a/src/Resources/views/crud/field/embed.html.twig b/src/Resources/views/crud/field/embed.html.twig new file mode 100644 index 0000000000..3934d35b19 --- /dev/null +++ b/src/Resources/views/crud/field/embed.html.twig @@ -0,0 +1,122 @@ +{# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} +{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} +{# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} +{% set current_url = ea_url() %} +{% set field = form.vars.ea_vars.field %} +{% set entity = form.vars.ea_vars.entity %} +{% set target_entity = field.doctrineMetadata.get('targetEntity') %} +{% set crudControllers = ea.crudControllers %} +{% set target_entity_crud_fqcn = crudControllers.findCrudFqcnByEntityFqcn(target_entity) %} + +{% set url = ea_url().unset('entityId').setController(target_entity_crud_fqcn).setAction('index').set('embedContext', { + mappedBy: field.doctrineMetadata.get('mappedBy'), + embeddedIn: entity.primaryKeyValue +}) %} + +{% set id_suffix = '-'~field.property %} + +
+
+
+
+
+
+ + + + diff --git a/src/Resources/views/crud/form_theme.html.twig b/src/Resources/views/crud/form_theme.html.twig index 8232eefefd..65e552b6a2 100644 --- a/src/Resources/views/crud/form_theme.html.twig +++ b/src/Resources/views/crud/form_theme.html.twig @@ -879,3 +879,7 @@ {% endblock %} + +{% block ea_embedded_collection_row %} + {{ include(ea.templatePath('crud/field/embed')) }} +{% endblock %} diff --git a/src/Resources/views/crud/index.html.twig b/src/Resources/views/crud/index.html.twig index 1cdfd53f5a..f3d61f9d5e 100644 --- a/src/Resources/views/crud/index.html.twig +++ b/src/Resources/views/crud/index.html.twig @@ -2,7 +2,6 @@ {# @var entities \EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection #} {# @var paginator \EasyCorp\Bundle\EasyAdminBundle\Orm\EntityPaginator #} {% extends ea.templatePath('layout') %} -{% trans_default_domain ea.i18n.translationDomain %} {% block body_id entities|length > 0 ? 'ea-index-' ~ entities|first.name : '' %} {% block body_class 'ea-index' ~ (entities|length > 0 ? ' ea-index-' ~ entities|first.name : '') %}