Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Data Object Editor] Add normalizer for all field types #578

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/data_objects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ services:
Pimcore\Bundle\StudioBackendBundle\DataObject\Service\ReplaceServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataObject\Service\ReplaceService

Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataService

Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterService

Expand Down
3 changes: 0 additions & 3 deletions config/updater.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ services:
Pimcore\Bundle\StudioBackendBundle\Updater\Service\AdapterLoaderInterface:
class: Pimcore\Bundle\StudioBackendBundle\Updater\Service\Loader\TaggedIteratorAdapter

Pimcore\Bundle\StudioBackendBundle\Updater\Service\EditableAdapterLoaderInterface:
class: Pimcore\Bundle\StudioBackendBundle\Updater\Service\Loader\TaggedIteratorEditableAdapter

Pimcore\Bundle\StudioBackendBundle\Updater\Service\UpdateServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Updater\Service\UpdateService

Expand Down
2 changes: 1 addition & 1 deletion src/Asset/Service/AssetService.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public function getAsset(
$user = $this->securityService->getCurrentUser();
$asset = $this->assetSearchService->getAssetById($id, $user);
if ($getWorkflowAvailable) {
$asset->setHasWorkflowAvailable($this->workflowDetailsService->hasElementWorkflows(
$asset->setHasWorkflowAvailable($this->workflowDetailsService->hasElementWorkflowsById(
$id,
ElementTypes::TYPE_ASSET,
$user
Expand Down
39 changes: 38 additions & 1 deletion src/DataObject/Data/Adapter/BlockAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,30 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter;

use Exception;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\FieldContextData;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidDataTypeException;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\ClassDefinition\Data\Block;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\Data\BlockElement;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use function get_class;
use function is_array;

/**
* @internal
*/
#[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)]
final readonly class BlockAdapter implements SetterDataInterface
final readonly class BlockAdapter implements SetterDataInterface, DataNormalizerInterface
{
public function __construct(
private DataAdapterServiceInterface $dataAdapterService,
private DataServiceInterface $dataService
) {
}

Expand All @@ -57,6 +63,37 @@ public function getDataForSetter(
return $this->processBlockData($element, $fieldDefinition, $blockData, $contextData);
}

public function normalize(
mixed $value,
Data $fieldDefinition
): ?array {
if (!is_array($value)) {
return null;
}

$resultItems = [];
if (!$fieldDefinition instanceof Block) {
throw new InvalidDataTypeException(Block::class, get_class($fieldDefinition));
}
$fieldDefinitions = $fieldDefinition->getFieldDefinitions();
foreach ($value as $block) {
$resultItem = [];

/** @var BlockElement $fieldValue */
foreach ($block as $key => $fieldValue) {
$blockDefinition = $fieldDefinitions[$key];
$resultItems[$key] = $this->dataService->getNormalizedValue(
$fieldValue->getData(),
$blockDefinition,
);
}

$resultItems[] = $resultItem;
}

return $resultItems;
}

/**
* @throws Exception
*/
Expand Down
128 changes: 120 additions & 8 deletions src/DataObject/Data/Adapter/ClassificationStoreAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,25 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter;

use Exception;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\MappingProperty;
use Pimcore\Bundle\StaticResolverBundle\Lib\ToolResolverInterface;
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassificationStore\DefinitionCacheResolverInterface;
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassificationStore\GroupConfigResolverInterface;
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassificationStore\ServiceResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\FieldContextData;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\DatabaseException;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\ClassDefinition\Data\Classificationstore as ClassificationstoreDefinition;
use Pimcore\Model\DataObject\Classificationstore;
use Pimcore\Model\DataObject\Classificationstore as ClassificationstoreModel;
use Pimcore\Model\DataObject\Classificationstore\GroupConfig;
use Pimcore\Model\DataObject\Classificationstore\KeyGroupRelation;
use Pimcore\Model\DataObject\Classificationstore\KeyGroupRelation\Listing as KeyGroupRelationListing;
use Pimcore\Model\DataObject\Concrete;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use function in_array;
Expand All @@ -34,11 +45,15 @@
* @internal
*/
#[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)]
final readonly class ClassificationStoreAdapter implements SetterDataInterface
final readonly class ClassificationStoreAdapter implements SetterDataInterface, DataNormalizerInterface
{
public function __construct(
private DefinitionCacheResolverInterface $definitionCacheResolver,
private DataAdapterServiceInterface $dataAdapterService,
private ServiceResolverInterface $serviceResolver
private DataServiceInterface $dataService,
private GroupConfigResolverInterface $groupConfigResolver,
private ServiceResolverInterface $serviceResolver,
private ToolResolverInterface $toolResolver
) {
}

Expand Down Expand Up @@ -68,6 +83,36 @@ public function getDataForSetter(
return $container;
}

public function normalize(
mixed $value,
Data $fieldDefinition
): ?array {
if (!$value instanceof ClassificationstoreModel ||
!$fieldDefinition instanceof ClassificationstoreDefinition
) {
return null;
}

$validLanguages = $this->getValidLanguages($fieldDefinition);
$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;
}

/**
* @throws Exception
*/
Expand All @@ -89,13 +134,10 @@ private function setMapping(Classificationstore $container, array $data): void
{
$activeGroups = $data['activeGroups'];
$groupCollectionMapping = $data['groupCollectionMapping'];
$correctedMapping = [];

foreach ($groupCollectionMapping as $groupId => $collectionId) {
if (isset($activeGroups[$groupId]) && $activeGroups[$groupId]) {
$correctedMapping[$groupId] = $collectionId;
}
}
$correctedMapping = array_filter($groupCollectionMapping, static function ($groupId) use ($activeGroups) {
return isset($activeGroups[$groupId]) && $activeGroups[$groupId];
}, ARRAY_FILTER_USE_KEY);

$container->setGroupCollectionMappings($correctedMapping);
}
Expand Down Expand Up @@ -163,4 +205,74 @@ private function cleanupStoreGroups(Classificationstore $container): void
}
}
}

private function getValidLanguages(ClassificationstoreDefinition $classificationStore): array
{
$languages = [MappingProperty::NOT_LOCALIZED_KEY];
if ($classificationStore->isLocalized()) {
$languages = array_merge($languages, $this->toolResolver->getValidLanguages());
}

return $languages;
}

/**
* @return GroupConfig[]
*/
private function getActiveGroups(ClassificationstoreModel $value): array
{
$groups = [];
foreach ($value->getActiveGroups() as $groupId => $active) {
if ($active) {
$groupConfig = $this->groupConfigResolver->getById($groupId);
if ($groupConfig) {
$groups[$groupId] = $groupConfig;
}
}
}

return $groups;
}

/**
* @return KeyGroupRelation[]
*/
private function getClassificationStoreKeysFromGroup(GroupConfig $groupConfig): array
{
$listing = new KeyGroupRelationListing();
$listing->addConditionParam('groupId = ?', $groupConfig->getId());

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) {
throw new DatabaseException($exception->getMessage());
}

$keyConfig = $this->definitionCacheResolver->get($key->getKeyId());
if ($keyConfig === null) {
return null;
}

$fieldDefinition = $this->serviceResolver->getFieldDefinitionFromKeyConfig($keyConfig);
if ($fieldDefinition === null) {
return null;
}

return $this->dataService->getNormalizedValue($value, $fieldDefinition);
}
}
41 changes: 40 additions & 1 deletion src/DataObject/Data/Adapter/FieldCollectionsAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter;

use Exception;
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\FieldCollection\DefinitionResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\DataNormalizerInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\FieldContextData;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Data\SetterDataInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataServiceInterface;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\ClassDefinition\Data\Fieldcollections;
use Pimcore\Model\DataObject\Concrete;
Expand All @@ -33,10 +36,12 @@
* @internal
*/
#[AutoconfigureTag(DataAdapterLoaderInterface::ADAPTER_TAG)]
final readonly class FieldCollectionsAdapter implements SetterDataInterface
final readonly class FieldCollectionsAdapter implements SetterDataInterface, DataNormalizerInterface
{
public function __construct(
private DataAdapterServiceInterface $dataAdapterService,
private DataServiceInterface $dataService,
private DefinitionResolverInterface $fieldCollectionDefinition,
private Factory $modelFactory
) {
}
Expand Down Expand Up @@ -75,6 +80,40 @@ public function getDataForSetter(
return new Fieldcollection($values, $fieldDefinition->getName());
}

public function normalize(
mixed $value,
Data $fieldDefinition
): ?array {
if (!$value instanceof Fieldcollection) {
return null;
}

$resultItems = [];
$items = $value->getItems();

foreach ($items as $item) {
$type = $item->getType();
$fieldCollectionDefinition = $this->fieldCollectionDefinition->getByKey($item->getType());
if (!$fieldCollectionDefinition) {
continue;
}
$resultItem = ['type' => $type];

foreach ($fieldCollectionDefinition->getFieldDefinitions() as $collectionFieldDefinition) {
$getter = 'get' . ucfirst($collectionFieldDefinition->getName());
$value = $item->$getter();
$resultItem[$collectionFieldDefinition->getName()] = $this->dataService->getNormalizedValue(
$value,
$collectionFieldDefinition,
);
}

$resultItems[] = $resultItem;
}

return $resultItems;
}

/**
* @throws Exception
*/
Expand Down
Loading
Loading