diff --git a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/BlockAdapter.php b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/BlockAdapter.php index 4ae71854..4e8bda82 100644 --- a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/BlockAdapter.php +++ b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/BlockAdapter.php @@ -18,6 +18,7 @@ use InvalidArgumentException; use Pimcore\Model\DataObject\ClassDefinition\Data\Block; +use Pimcore\Model\DataObject\Data\BlockElement; /** * @internal @@ -45,4 +46,34 @@ public function getIndexMapping(): array 'properties' => $properties, ]; } + + public function normalize(mixed $value): ?array + { + if (!is_array($value)) { + return null; + } + + $resultItems = []; + $fieldDefinition = $this->getFieldDefinition(); + if (!$fieldDefinition instanceof Block) { + throw new InvalidArgumentException('FieldDefinition must be an instance of ' . Block::class); + } + $fieldDefinitions = $fieldDefinition->getFieldDefinitions(); + foreach ($value as $block) { + $resultItem = []; + + /** @var BlockElement $fieldValue */ + foreach ($block as $key => $fieldValue) { + $blockDefinition = $fieldDefinitions[$key]; + $resultItems[$key] = $this->fieldDefinitionService->normalizeValue( + $blockDefinition, + $fieldValue->getData() + ); + } + + $resultItems[] = $resultItem; + } + + return $resultItems; + } } diff --git a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ClassificationStoreAdapter.php b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ClassificationStoreAdapter.php index 7105b457..634039c9 100644 --- a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ClassificationStoreAdapter.php +++ b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ClassificationStoreAdapter.php @@ -19,10 +19,14 @@ use Exception; use InvalidArgumentException; use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\OpenSearch\AttributeType; +use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\MappingProperty; +use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\LanguageServiceInterface; use Pimcore\Bundle\GenericDataIndexBundle\Traits\LoggerAwareTrait; use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassificationStore\ServiceResolverInterface; use Pimcore\Model\DataObject\ClassDefinition\Data; use Pimcore\Model\DataObject\ClassDefinition\Data\Classificationstore; +use Pimcore\Model\DataObject\Classificationstore as ClassificationstoreModel; +use Pimcore\Model\DataObject\Classificationstore\DefinitionCache; use Pimcore\Model\DataObject\Classificationstore\GroupConfig; use Pimcore\Model\DataObject\Classificationstore\GroupConfig\Listing as GroupListing; use Pimcore\Model\DataObject\Classificationstore\KeyGroupRelation; @@ -38,6 +42,8 @@ final class ClassificationStoreAdapter extends AbstractAdapter private ServiceResolverInterface $classificationService; + private LanguageServiceInterface $languageService; + #[Required] public function setClassificationService(ServiceResolverInterface $serviceResolver): void { @@ -66,6 +72,50 @@ public function getIndexMapping(): array ]; } + public function normalize(mixed $value): ?array + { + if (!$value instanceof ClassificationstoreModel) { + return null; + } + + $validLanguages = $this->getValidLanguages(); + $resultItems = []; + + foreach ($this->getActiveGroups($value) as $groupId => $groupConfig) { + $resultItems[$groupConfig->getName()] = []; + $keys = $this->getClassificationStoreKeysFromGroup($groupConfig); + foreach ($validLanguages as $validLanguage) { + foreach ($keys as $key) { + $normalizedValue = $this->getNormalizedValue($value, $groupId, $key, $validLanguage); + + if ($normalizedValue !== null) { + $resultItems[$groupConfig->getName()][$validLanguage][$key->getName()] = $normalizedValue; + } + } + } + } + + return $resultItems; + } + + /** + * @return GroupConfig[] + */ + private function getActiveGroups(ClassificationstoreModel $value): array + { + $groups = []; + foreach ($value->getActiveGroups() as $groupId => $active) { + if ($active) { + $groupConfig = GroupConfig::getById($groupId); + if ($groupConfig) { + $groups[$groupId] = $groupConfig; + } + } + } + + return $groups; + } + /** * @param KeyGroupRelation[] $groupConfigs */ @@ -116,4 +166,50 @@ private function getClassificationStoreKeysFromGroup(GroupConfig $groupConfig): return $listing->getList(); } + + private function getNormalizedValue( + ClassificationstoreModel $classificationstore, + int $groupId, + KeyGroupRelation $key, + string $language + ): mixed { + try { + $value = $classificationstore->getLocalizedKeyValue( + $groupId, + $key->getKeyId(), + $language, + true, + true + ); + } catch (Exception $exception) { + $this->logger->warning(sprintf( + 'Could not get localized value for key %s in group %s: %s', + $key->getKeyId(), + $groupId, + $exception->getMessage() + )); + + return null; + } + + $keyConfig = DefinitionCache::get($key->getKeyId()); + if ($keyConfig === null) { + return null; + } + + $fieldDefinition = $this->classificationService->getFieldDefinitionFromKeyConfig($keyConfig); + + return $this->fieldDefinitionService->normalizeValue($fieldDefinition, $value); + } + + private function getValidLanguages(): array + { + return array_merge([MappingProperty::NOT_LOCALIZED_KEY], $this->languageService->getValidLanguages()); + } + + #[Required] + public function setLanguageService(LanguageServiceInterface $languageService): void + { + $this->languageService = $languageService; + } } diff --git a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ObjectBrickAdapter.php b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ObjectBrickAdapter.php index 20cc7011..d08ec68b 100644 --- a/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ObjectBrickAdapter.php +++ b/src/SearchIndexAdapter/OpenSearch/DataObject/FieldDefinitionAdapter/ObjectBrickAdapter.php @@ -17,14 +17,19 @@ namespace Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\OpenSearch\DataObject\FieldDefinitionAdapter; use InvalidArgumentException; +use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\Objectbrick\DefinitionResolverInterface; use Pimcore\Model\DataObject\ClassDefinition\Data\Objectbricks; use Pimcore\Model\DataObject\Objectbrick; +use Pimcore\Model\DataObject\Objectbrick\Data\AbstractData; +use Symfony\Contracts\Service\Attribute\Required; /** * @internal */ final class ObjectBrickAdapter extends AbstractAdapter { + private DefinitionResolverInterface $objectBrickDefinition; + public function getIndexMapping(): array { $objectBricks = $this->getFieldDefinition(); @@ -44,9 +49,43 @@ public function getIndexMapping(): array ]; } + public function normalize(mixed $value): ?array + { + if (!$value instanceof Objectbrick) { + return null; + } + + $resultItems = []; + $items = $value->getObjectVars(); + foreach ($items as $item) { + if (!$item instanceof AbstractData) { + continue; + } + + $type = $item->getType(); + $resultItems[$type] = []; + $definition = $this->objectBrickDefinition->getByKey($type); + if ($definition === null) { + continue; + } + + $resultItems[$type] = []; + foreach ($definition->getFieldDefinitions() as $fieldDefinition) { + $getter = 'get' . ucfirst($fieldDefinition->getName()); + $value = $item->$getter(); + $resultItems[$fieldDefinition->getName()] = $this->fieldDefinitionService->normalizeValue( + $fieldDefinition, + $value + ); + } + } + + return $resultItems; + } + private function getMappingForObjectBrick(string $objectBrickType): array { - $fieldDefinitions = Objectbrick\Definition::getByKey($objectBrickType)?->getFieldDefinitions(); + $fieldDefinitions = $this->objectBrickDefinition->getByKey($objectBrickType)?->getFieldDefinitions(); $mapping = []; foreach ($fieldDefinitions as $fieldDefinition) { $adapter = $this->getFieldDefinitionService()->getFieldDefinitionAdapter($fieldDefinition); @@ -57,4 +96,10 @@ private function getMappingForObjectBrick(string $objectBrickType): array return $mapping; } + + #[Required] + public function setObjectBrickDefinition(DefinitionResolverInterface $definitionResolver): void + { + $this->objectBrickDefinition = $definitionResolver; + } }