From b8627f4171c302378b0150ca0c053d6c55c298a1 Mon Sep 17 00:00:00 2001 From: Jan Adams <56639925+jan888adams@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:21:56 +0100 Subject: [PATCH] [Improvement]: Define default value on Multiselect Object Type (#15871) * Add default value for Multiselect object type * Adjust readme for select types * Remove multi select provider interface where possible * Make multi select interface optional * trigger deprecation if multi select provide interface is given * Update models/DataObject/ClassDefinition/Helper/OptionsProviderResolver.php Change version 12.0 to 11.1 Co-authored-by: Jacob Dreesen * Remove getDefaultValue method from MultiSelectOptionsProviderInterface * Add trigger for deprecation Co-authored-by: Jacob Dreesen * Revert removed Multiselect condition * Resolve multiple default values * Update release version Co-authored-by: Jacob Dreesen * Update release version Co-authored-by: Jacob Dreesen * Refactor getDataForResource() Co-authored-by: Jacob Dreesen * Fix typo Co-authored-by: Jacob Dreesen * Use multiple return types instead of 'mixed' type Co-authored-by: Jacob Dreesen * Update docs Co-authored-by: Jacob Dreesen * apply suggestions to doc * add changelog * limit the deprecation trigger to multiselectoption * remove not neccessary null coalesce * fix service only covering multiselect --------- Co-authored-by: Jacob Dreesen Co-authored-by: JiaJia Ji --- .../01_Data_Types/30_Dynamic_Select_Types.md | 7 +-- .../09_Upgrade_Notes/README.md | 2 +- .../ClassDefinition/Data/Multiselect.php | 53 +++++++++++++++++-- .../MultiSelectOptionsProviderInterface.php | 5 ++ .../SelectOptionsProviderInterface.php | 19 ++++++- .../Helper/OptionsProviderResolver.php | 14 ++++- models/DataObject/Service.php | 3 +- 7 files changed, 90 insertions(+), 13 deletions(-) diff --git a/doc/05_Objects/01_Object_Classes/01_Data_Types/30_Dynamic_Select_Types.md b/doc/05_Objects/01_Object_Classes/01_Data_Types/30_Dynamic_Select_Types.md index 2509ec625da..f6b33f5d283 100644 --- a/doc/05_Objects/01_Object_Classes/01_Data_Types/30_Dynamic_Select_Types.md +++ b/doc/05_Objects/01_Object_Classes/01_Data_Types/30_Dynamic_Select_Types.md @@ -24,14 +24,11 @@ services: public: true ``` -Depending on your datatype you have to implement the appropriate interface. - - * `Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\SelectOptionsProviderInterface` for the `Select` data type options, - * `Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface` for the Multiselect options +You have to implement the `Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\SelectOptionsProviderInterface` Implement the following methods: * `getOptions` should return a list of valid options in the format indicated below - * `getDefaultValue` (Select data type only) returning the default value + * `getDefaultValue` returning the default value * `hasStaticOptions` should return whether your options are depending on the object context (i.e. different options for different objects) or not. This is especially important for the object grid. For object-context depending option there will be no batch assignment mode. Also, filtering can only be done through a text field instead of the options list. diff --git a/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md b/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md index 2aaa497ddae..6f4a7aba1fb 100644 --- a/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md +++ b/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md @@ -7,7 +7,7 @@ - Service `Pimcore\Document\Renderer\DocumentRenderer` is deprecated, use `Pimcore\Document\Renderer\DocumentRendererInterface` instead. #### [Data Objects]: - Methods `getAsIntegerCast()` and `getAsFloatCast()` of the `Pimcore\Model\DataObject\Data` class are deprecated now. - +- `MultiSelectOptionsProviderInterface` is deprecated, please use `SelectOptionsProviderInterface` instead. ----------------- ### General #### [Localization] diff --git a/models/DataObject/ClassDefinition/Data/Multiselect.php b/models/DataObject/ClassDefinition/Data/Multiselect.php index 26e13fc37e6..a6c66b131d0 100644 --- a/models/DataObject/ClassDefinition/Data/Multiselect.php +++ b/models/DataObject/ClassDefinition/Data/Multiselect.php @@ -20,6 +20,8 @@ use Pimcore\Model; use Pimcore\Model\DataObject; use Pimcore\Model\DataObject\ClassDefinition\Data; +use Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface; +use Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\SelectOptionsProviderInterface; use Pimcore\Model\DataObject\ClassDefinition\Service; use Pimcore\Model\DataObject\Concrete; use Pimcore\Normalizer\NormalizerInterface; @@ -42,6 +44,7 @@ class Multiselect extends Data implements use DataObject\ClassDefinition\DynamicOptionsProvider\SelectionProviderTrait; use DataObject\Traits\DataHeightTrait; use DataObject\Traits\DataWidthTrait; + use DataObject\Traits\DefaultValueTrait; use OptionsProviderTrait; /** @@ -69,6 +72,11 @@ class Multiselect extends Data implements */ public bool $dynamicOptions = false; + /** + * @internal + */ + public ?array $defaultValue = null; + public function getOptions(): ?array { return $this->options; @@ -114,6 +122,18 @@ public function getRenderType(): ?string return $this->renderType; } + public function setDefaultValue(array $defaultValue): static + { + $this->defaultValue = $defaultValue; + + return $this; + } + + public function getDefaultValue(): ?array + { + return $this->defaultValue; + } + /** * @see ResourcePersistenceAwareInterface::getDataForResource * @@ -121,11 +141,17 @@ public function getRenderType(): ?string */ public function getDataForResource(mixed $data, DataObject\Concrete $object = null, array $params = []): ?string { - if (is_array($data)) { + if (!$this->isEmpty($data) && is_array($data)) { return implode(',', $data); } - return null; + $defaultValue = $this->handleDefaultValue($data, $object, $params); + + if (is_array($defaultValue)) { + return implode(',', array_map(fn ($v) => $v['value'] ?? $v, $defaultValue)); + } + + return $defaultValue; } /** @@ -447,7 +473,6 @@ public function getPhpdocReturnType(): ?string */ public function preSave(mixed $containerDefinition, array $params = []): void { - /** @var DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface|null $optionsProvider */ $optionsProvider = DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider( $this->getOptionsProviderClass(), DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT @@ -510,4 +535,26 @@ public function getFieldType(): string { return 'multiselect'; } + + protected function doGetDefaultValue(Concrete $object, array $context = []): mixed + { + /** @var SelectOptionsProviderInterface|MultiSelectOptionsProviderInterface|null $optionsProvider */ + $optionsProvider = DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider( + $this->getOptionsProviderClass(), + DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT + ); + if ($optionsProvider instanceof SelectOptionsProviderInterface) { + $context['object'] = $object; + $context['class'] = $object->getClass(); + + $context['fieldname'] = $this->getName(); + if (!isset($context['purpose'])) { + $context['purpose'] = 'layout'; + } + + return $optionsProvider->getDefaultValue($context, $this); + } + + return $this->getDefaultValue(); + } } diff --git a/models/DataObject/ClassDefinition/DynamicOptionsProvider/MultiSelectOptionsProviderInterface.php b/models/DataObject/ClassDefinition/DynamicOptionsProvider/MultiSelectOptionsProviderInterface.php index f980620b805..94c76a0763e 100644 --- a/models/DataObject/ClassDefinition/DynamicOptionsProvider/MultiSelectOptionsProviderInterface.php +++ b/models/DataObject/ClassDefinition/DynamicOptionsProvider/MultiSelectOptionsProviderInterface.php @@ -18,6 +18,11 @@ use Pimcore\Model\DataObject\ClassDefinition\Data; +trigger_deprecation('pimcore/pimcore', '11.2', '%s is deprecated. Use %s instead.', MultiSelectOptionsProviderInterface::class, SelectOptionsProviderInterface::class); + +/** + * @deprecated use SelectOptionsProviderInterface instead + */ interface MultiSelectOptionsProviderInterface { public function getOptions(array $context, Data $fieldDefinition): array; diff --git a/models/DataObject/ClassDefinition/DynamicOptionsProvider/SelectOptionsProviderInterface.php b/models/DataObject/ClassDefinition/DynamicOptionsProvider/SelectOptionsProviderInterface.php index a91ae72befe..347684e1698 100644 --- a/models/DataObject/ClassDefinition/DynamicOptionsProvider/SelectOptionsProviderInterface.php +++ b/models/DataObject/ClassDefinition/DynamicOptionsProvider/SelectOptionsProviderInterface.php @@ -18,7 +18,22 @@ use Pimcore\Model\DataObject\ClassDefinition\Data; -interface SelectOptionsProviderInterface extends MultiSelectOptionsProviderInterface +interface SelectOptionsProviderInterface { - public function getDefaultValue(array $context, Data $fieldDefinition): ?string; + public function getOptions(array $context, Data $fieldDefinition): array; + + /** + * Whether options are depending on the object context (i.e. different options for different objects) or not. + * This is especially important for exposing options in the object grid. For options depending on object-context + * there will be no batch assignment mode, and filtering can only be done through a text field instead of the + * options list. + * + * + */ + public function hasStaticOptions(array $context, Data $fieldDefinition): bool; + + /** + * @return string|array|null + */ + public function getDefaultValue(array $context, Data $fieldDefinition): string|array|null; } diff --git a/models/DataObject/ClassDefinition/Helper/OptionsProviderResolver.php b/models/DataObject/ClassDefinition/Helper/OptionsProviderResolver.php index 6f07f907b63..a14c9fce7cc 100644 --- a/models/DataObject/ClassDefinition/Helper/OptionsProviderResolver.php +++ b/models/DataObject/ClassDefinition/Helper/OptionsProviderResolver.php @@ -33,8 +33,20 @@ class OptionsProviderResolver extends ClassResolver public static function resolveProvider(?string $providerClass, int $mode): ?object { return self::resolve($providerClass, function ($provider) use ($mode) { + + if ($provider instanceof MultiSelectOptionsProviderInterface){ + trigger_deprecation( + 'pimcore/pimcore', + '11.2', + 'Implementing %s is deprecated, use %s instead', + MultiSelectOptionsProviderInterface::class, + SelectOptionsProviderInterface::class, + ); + } + return ($mode == self::MODE_SELECT && ($provider instanceof SelectOptionsProviderInterface)) - || ($mode == self::MODE_MULTISELECT && ($provider instanceof MultiSelectOptionsProviderInterface)); + || ($mode == self::MODE_MULTISELECT && ($provider instanceof MultiSelectOptionsProviderInterface)) + || ($mode == self::MODE_MULTISELECT && ($provider instanceof SelectOptionsProviderInterface)); }); } } diff --git a/models/DataObject/Service.php b/models/DataObject/Service.php index 839ced8225f..82ca64f514c 100644 --- a/models/DataObject/Service.php +++ b/models/DataObject/Service.php @@ -32,6 +32,7 @@ use Pimcore\Model\DataObject; use Pimcore\Model\DataObject\ClassDefinition\Data\IdRewriterInterface; use Pimcore\Model\DataObject\ClassDefinition\Data\LayoutDefinitionEnrichmentInterface; +use Pimcore\Model\DataObject\ClassDefinition\DynamicOptionsProvider\SelectOptionsProviderInterface; use Pimcore\Model\Element; use Pimcore\Model\Element\DirtyIndicatorInterface; use Pimcore\Model\Element\ElementInterface; @@ -799,7 +800,7 @@ public static function getOptionsForSelectField(string|Concrete $object, ClassDe DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT ); - if (!$definition->useConfiguredOptions() && $optionsProvider instanceof DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface) { + if (!$definition->useConfiguredOptions() && $optionsProvider instanceof SelectOptionsProviderInterface) { $_options = $optionsProvider->getOptions(['fieldname' => $definition->getName()], $definition); } else { $_options = $definition->getOptions();