From 1d4bd63b9de6750f0641cd73a6e5fb9c566ad326 Mon Sep 17 00:00:00 2001 From: lukmzig <30526586+lukmzig@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:03:31 +0100 Subject: [PATCH] [Data Object Editor] Use same format for relation normalizers like for manyToManyRelation (#710) * adapt relation adapters * Apply php-cs-fixer changes --- ...dvancedManyToManyObjectRelationAdapter.php | 69 +++++++------- .../AdvancedManyToManyRelationAdapter.php | 72 +++++++-------- .../ManyToManyObjectRelationAdapter.php | 21 ++++- .../Adapter/ManyToManyRelationAdapter.php | 39 +------- .../Adapter/ReverseObjectRelationAdapter.php | 21 ++++- .../Util/Trait/RelationDataTrait.php | 89 +++++++++++++++++++ .../Util/Trait/RelationMetadataTrait.php | 44 +++++++++ src/Util/Trait/ElementProviderTrait.php | 5 +- 8 files changed, 255 insertions(+), 105 deletions(-) create mode 100644 src/DataObject/Util/Trait/RelationDataTrait.php create mode 100644 src/DataObject/Util/Trait/RelationMetadataTrait.php diff --git a/src/DataObject/Data/Adapter/AdvancedManyToManyObjectRelationAdapter.php b/src/DataObject/Data/Adapter/AdvancedManyToManyObjectRelationAdapter.php index ae5ca460c..967907712 100644 --- a/src/DataObject/Data/Adapter/AdvancedManyToManyObjectRelationAdapter.php +++ b/src/DataObject/Data/Adapter/AdvancedManyToManyObjectRelationAdapter.php @@ -17,9 +17,13 @@ namespace Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ConcreteObjectResolverInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\FieldContextData; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationDataTrait; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationMetadataTrait; +use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\ClassDefinition\Data\AdvancedManyToManyObjectRelation; use Pimcore\Model\DataObject\Concrete; @@ -31,8 +35,11 @@ * @internal */ #[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)] -final readonly class AdvancedManyToManyObjectRelationAdapter implements SetterDataInterface +final readonly class AdvancedManyToManyObjectRelationAdapter implements SetterDataInterface, DataNormalizerInterface { + use RelationDataTrait; + use RelationMetadataTrait; + public function __construct( private ConcreteObjectResolverInterface $concreteObjectResolver ) { @@ -54,6 +61,26 @@ public function getDataForSetter( return $this->buildRelationsMetadata($relationData, $fieldDefinition); } + public function normalize( + mixed $value, + Data $fieldDefinition + ): ?array { + if (!is_array($value)) { + return null; + } + + $normalizedData = []; + foreach ($value as $relation) { + if (!$relation instanceof ObjectMetadata) { + continue; + } + + $normalizedData[] = $this->getAdvancedRelationElementData($relation); + } + + return $normalizedData; + } + private function buildRelationsMetadata(array $relationData, Data $fieldDefinition): array { if (!$fieldDefinition instanceof AdvancedManyToManyObjectRelation) { @@ -62,39 +89,21 @@ private function buildRelationsMetadata(array $relationData, Data $fieldDefiniti $relationsMetadata = []; foreach ($relationData as $relation) { - $object = $this->concreteObjectResolver->getById($relation['id']); - if ($object && $object->getClassName() === $fieldDefinition->getAllowedClassId()) { - $relationsMetadata[] = $this->createObjectMetadata($object, $fieldDefinition, $relation); + if (empty($relation['element']['id']) || $relation['element']['type'] !== ElementTypes::TYPE_OBJECT) { + continue; } - } - return $relationsMetadata; - } - - private function createObjectMetadata( - Concrete $object, - AdvancedManyToManyObjectRelation $fieldDefinition, - array $relation, - ): ObjectMetadata { - $metaData = new ObjectMetadata( - $fieldDefinition->getName(), - $fieldDefinition->getColumnKeys(), - $object - ); - $metaData->_setOwner($object); - $metaData->_setOwnerFieldname($fieldDefinition->getName()); - - foreach ($fieldDefinition->getColumns() as $column) { - $setter = 'set' . ucfirst($column['key']); - $value = $relation[$column['key']] ?? null; - - if ($column['type'] === 'multiselect' && is_array($value)) { - $value = implode(',', $value); + $object = $this->concreteObjectResolver->getById($relation['element']['id']); + if ($object && $object->getClassName() === $fieldDefinition->getAllowedClassId()) { + $fieldName = $fieldDefinition->getName(); + $relationsMetadata[] = $this->addRelationMetadata( + $object, + $relation['data'], + new ObjectMetadata($fieldName, $fieldDefinition->getColumnKeys(), $object) + ); } - - $metaData->$setter($value); } - return $metaData; + return $relationsMetadata; } } diff --git a/src/DataObject/Data/Adapter/AdvancedManyToManyRelationAdapter.php b/src/DataObject/Data/Adapter/AdvancedManyToManyRelationAdapter.php index 9764a3b7b..75c3f31ee 100644 --- a/src/DataObject/Data/Adapter/AdvancedManyToManyRelationAdapter.php +++ b/src/DataObject/Data/Adapter/AdvancedManyToManyRelationAdapter.php @@ -18,15 +18,16 @@ use Exception; use Pimcore\Bundle\StaticResolverBundle\Models\Element\ServiceResolverInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\FieldContextData; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface; -use Pimcore\Bundle\StudioBackendBundle\Util\Trait\ElementProviderTrait; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationDataTrait; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationMetadataTrait; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\ClassDefinition\Data\AdvancedManyToManyRelation; use Pimcore\Model\DataObject\Concrete; use Pimcore\Model\DataObject\Data\ElementMetadata; -use Pimcore\Model\Element\ElementInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; use function is_array; @@ -34,9 +35,10 @@ * @internal */ #[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)] -final readonly class AdvancedManyToManyRelationAdapter implements SetterDataInterface +final readonly class AdvancedManyToManyRelationAdapter implements SetterDataInterface, DataNormalizerInterface { - use ElementProviderTrait; + use RelationDataTrait; + use RelationMetadataTrait; public function __construct( private ServiceResolverInterface $serviceResolver @@ -61,6 +63,26 @@ public function getDataForSetter( return $this->buildRelationsMetadata($relationData, $fieldDefinition); } + public function normalize( + mixed $value, + Data $fieldDefinition + ): ?array { + if (!is_array($value)) { + return null; + } + + $normalizedData = []; + foreach ($value as $relation) { + if (!$relation instanceof ElementMetadata) { + continue; + } + + $normalizedData[] = $this->getAdvancedRelationElementData($relation); + } + + return $normalizedData; + } + /** * @throws Exception */ @@ -72,40 +94,20 @@ private function buildRelationsMetadata(array $relationData, Data $fieldDefiniti $relationsMetadata = []; foreach ($relationData as $relation) { - $element = $this->getElement($this->serviceResolver, $relation['type'], $relation['id']); - $relationsMetadata[] = $this->createObjectMetadata($element, $fieldDefinition, $relation); - } - - return $relationsMetadata; - } - - /** - * @throws Exception - */ - private function createObjectMetadata( - ElementInterface $element, - AdvancedManyToManyRelation $fieldDefinition, - array $relation, - ): ElementMetadata { - $metaData = new ElementMetadata( - $fieldDefinition->getName(), - $fieldDefinition->getColumnKeys(), - $element - ); - $metaData->_setOwner($element); - $metaData->_setOwnerFieldname($fieldDefinition->getName()); - - foreach ($fieldDefinition->getColumns() as $column) { - $setter = 'set' . ucfirst($column['key']); - $value = $relation[$column['key']] ?? null; - - if ($column['type'] === 'multiselect' && is_array($value)) { - $value = implode(',', $value); + $elementData = $relation['element']; + if (empty($elementData['id']) || empty($elementData['type'])) { + continue; } - $metaData->$setter($value); + $element = $this->getElement($this->serviceResolver, $elementData['type'], $elementData['id']); + $fieldName = $fieldDefinition->getName(); + $relationsMetadata[] = $this->addRelationMetadata( + $element, + $relation['data'], + new ElementMetadata($fieldName, $fieldDefinition->getColumnKeys(), $element) + ); } - return $metaData; + return $relationsMetadata; } } diff --git a/src/DataObject/Data/Adapter/ManyToManyObjectRelationAdapter.php b/src/DataObject/Data/Adapter/ManyToManyObjectRelationAdapter.php index d65622a10..480adf0ca 100644 --- a/src/DataObject/Data/Adapter/ManyToManyObjectRelationAdapter.php +++ b/src/DataObject/Data/Adapter/ManyToManyObjectRelationAdapter.php @@ -17,9 +17,12 @@ namespace Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ConcreteObjectResolverInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\FieldContextData; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\RelationData; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationDataTrait; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\Concrete; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; @@ -29,8 +32,10 @@ * @internal */ #[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)] -final readonly class ManyToManyObjectRelationAdapter implements SetterDataInterface +final readonly class ManyToManyObjectRelationAdapter implements SetterDataInterface, DataNormalizerInterface { + use RelationDataTrait; + public function __construct( private ConcreteObjectResolverInterface $concreteObjectResolver ) { @@ -51,6 +56,20 @@ public function getDataForSetter( return $this->getRelationObjects($relationData); } + /** + * @return RelationData[]|null + */ + public function normalize( + mixed $value, + Data $fieldDefinition + ): ?array { + if (!is_array($value)) { + return null; + } + + return $this->getRelationElementsData($value); + } + private function getRelationObjects(array $relationData): array { $objects = []; diff --git a/src/DataObject/Data/Adapter/ManyToManyRelationAdapter.php b/src/DataObject/Data/Adapter/ManyToManyRelationAdapter.php index 8c679f8fe..5a5c8dc6e 100644 --- a/src/DataObject/Data/Adapter/ManyToManyRelationAdapter.php +++ b/src/DataObject/Data/Adapter/ManyToManyRelationAdapter.php @@ -22,12 +22,10 @@ use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\RelationData; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationDataTrait; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException; -use Pimcore\Bundle\StudioBackendBundle\Util\Trait\ElementProviderTrait; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\Concrete; -use Pimcore\Model\Document; -use Pimcore\Model\Element\ElementInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; use function is_array; @@ -37,7 +35,7 @@ #[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)] final readonly class ManyToManyRelationAdapter implements SetterDataInterface, DataNormalizerInterface { - use ElementProviderTrait; + use RelationDataTrait; public function __construct( private ServiceResolverInterface $serviceResolver @@ -70,20 +68,7 @@ public function normalize( return null; } - $data = []; - /** @var ElementInterface[] $value */ - foreach ($value as $relation) { - $elementType = $this->getElementType($relation); - $data[] = new RelationData( - $relation->getId(), - $elementType, - $this->getSubType($relation), - $relation->getRealFullPath(), - $this->getPublished($relation) - ); - } - - return $data; + return $this->getRelationElementsData($value); } private function getRelationElements(array $relationData): array @@ -101,22 +86,4 @@ private function getRelationElements(array $relationData): array return $relations; } - - private function getSubType(ElementInterface $element): string - { - if ($element instanceof Concrete) { - return $element->getClassName(); - } - - return $element->getType(); - } - - private function getPublished(ElementInterface $element): ?bool - { - if ($element instanceof Concrete || $element instanceof Document) { - return $element->getPublished(); - } - - return null; - } } diff --git a/src/DataObject/Data/Adapter/ReverseObjectRelationAdapter.php b/src/DataObject/Data/Adapter/ReverseObjectRelationAdapter.php index 53d9c60d1..b74db48c0 100644 --- a/src/DataObject/Data/Adapter/ReverseObjectRelationAdapter.php +++ b/src/DataObject/Data/Adapter/ReverseObjectRelationAdapter.php @@ -19,9 +19,12 @@ use Exception; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassDefinitionResolverInterface; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ConcreteObjectResolverInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\FieldContextData; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Model\RelationData; use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface; use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface; +use Pimcore\Bundle\StudioBackendBundle\DataObject\Util\Trait\RelationDataTrait; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\ClassDefinition\Data\ReverseObjectRelation; @@ -35,8 +38,10 @@ * @internal */ #[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)] -final readonly class ReverseObjectRelationAdapter implements SetterDataInterface +final readonly class ReverseObjectRelationAdapter implements SetterDataInterface, DataNormalizerInterface { + use RelationDataTrait; + public function __construct( private ClassDefinitionResolverInterface $classDefinitionResolver, private ConcreteObjectResolverInterface $concreteObjectResolver, @@ -72,6 +77,20 @@ public function getDataForSetter( return null; } + /** + * @return RelationData[]|null + */ + public function normalize( + mixed $value, + Data $fieldDefinition + ): ?array { + if (!is_array($value)) { + return null; + } + + return $this->getRelationElementsData($value); + } + private function processRemoteOwnerRelations( Concrete $element, array $relations, diff --git a/src/DataObject/Util/Trait/RelationDataTrait.php b/src/DataObject/Util/Trait/RelationDataTrait.php new file mode 100644 index 000000000..d66740542 --- /dev/null +++ b/src/DataObject/Util/Trait/RelationDataTrait.php @@ -0,0 +1,89 @@ +getRelationElementData($relation); + } + + return $data; + } + + private function getAdvancedRelationElementData(ElementMetadata|ObjectMetadata $relation): array + { + + return [ + 'element' => $this->getRelationElementData($relation->getElement()), + 'fieldName' => $relation->getFieldname(), + 'columns' => $relation->getColumns(), + 'data' => $relation->getData(), + ]; + } + + private function getRelationElementData(ElementInterface $relation): RelationData + { + return new RelationData( + $relation->getId(), + $this->getElementType($relation, true), + $this->getSubType($relation), + $relation->getRealFullPath(), + $this->getPublished($relation) + ); + } + + private function getSubType(ElementInterface $element): string + { + if ($element instanceof Concrete) { + return $element->getClassName(); + } + + return $element->getType(); + } + + private function getPublished(ElementInterface $element): ?bool + { + if ($element instanceof Concrete || $element instanceof Document) { + return $element->getPublished(); + } + + return null; + } +} diff --git a/src/DataObject/Util/Trait/RelationMetadataTrait.php b/src/DataObject/Util/Trait/RelationMetadataTrait.php new file mode 100644 index 000000000..0e184b462 --- /dev/null +++ b/src/DataObject/Util/Trait/RelationMetadataTrait.php @@ -0,0 +1,44 @@ +_setOwner($object); + $metadata->_setOwnerFieldname($metadata->getFieldname()); + + foreach ($metadata->getColumns() as $column) { + $setter = 'set' . ucfirst($column); + $value = $relationData[$column] ?? null; + $metadata->$setter($value); + } + + return $metadata; + } +} diff --git a/src/Util/Trait/ElementProviderTrait.php b/src/Util/Trait/ElementProviderTrait.php index a105d85a6..f5235a844 100644 --- a/src/Util/Trait/ElementProviderTrait.php +++ b/src/Util/Trait/ElementProviderTrait.php @@ -101,12 +101,13 @@ private function getElementClass(ElementInterface $element): string /** * @throws InvalidElementTypeException */ - private function getElementType(ElementInterface $element): string + private function getElementType(ElementInterface $element, bool $getCoreType = false): string { return match (true) { $element instanceof Asset => ElementTypes::TYPE_ASSET, $element instanceof Document => ElementTypes::TYPE_DOCUMENT, - $element instanceof DataObject => ElementTypes::TYPE_DATA_OBJECT, + $element instanceof DataObject => + $getCoreType ? ElementTypes::TYPE_OBJECT : ElementTypes::TYPE_DATA_OBJECT, default => throw new InvalidElementTypeException($element->getType()) }; }