vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/Classificationstore.php line 1435

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\DataObject\ClassDefinition\Data;
  15. use Pimcore\Model;
  16. use Pimcore\Model\DataObject;
  17. use Pimcore\Model\DataObject\ClassDefinition\Data;
  18. use Pimcore\Model\DataObject\Concrete;
  19. use Pimcore\Model\Element;
  20. use Pimcore\Normalizer\NormalizerInterface;
  21. use Pimcore\Tool;
  22. class Classificationstore extends Data implements CustomResourcePersistingInterfaceTypeDeclarationSupportInterfaceNormalizerInterfacePreGetDataInterfaceLayoutDefinitionEnrichmentInterfaceVarExporterInterfaceClassSavedInterface
  23. {
  24.     use Element\ChildsCompatibilityTrait;
  25.     /**
  26.      * Static type of this element
  27.      *
  28.      * @internal
  29.      *
  30.      * @var string
  31.      */
  32.     public $fieldtype 'classificationstore';
  33.     /**
  34.      * @internal
  35.      *
  36.      * @var array
  37.      */
  38.     public $children = [];
  39.     /**
  40.      * @internal
  41.      *
  42.      * @var string|null
  43.      */
  44.     public $name;
  45.     /**
  46.      * @internal
  47.      *
  48.      * @var string
  49.      */
  50.     public $region;
  51.     /**
  52.      * @internal
  53.      *
  54.      * @var string
  55.      */
  56.     public $layout;
  57.     /**
  58.      * @internal
  59.      *
  60.      * @var string|null
  61.      */
  62.     public $title;
  63.     /**
  64.      * @internal
  65.      *
  66.      * @var string|int
  67.      */
  68.     public $width 0;
  69.     /**
  70.      * @internal
  71.      *
  72.      * @var string|int
  73.      */
  74.     public $height 0;
  75.     /**
  76.      * @internal
  77.      *
  78.      * @var int
  79.      */
  80.     public $maxTabs;
  81.     /**
  82.      * @internal
  83.      *
  84.      * @var int
  85.      */
  86.     public $labelWidth 0;
  87.     /**
  88.      * @internal
  89.      *
  90.      * @var bool
  91.      */
  92.     public $localized;
  93.     /**
  94.      * @internal
  95.      *
  96.      * @var int
  97.      */
  98.     public $storeId;
  99.     /**
  100.      * @internal
  101.      *
  102.      * @var bool
  103.      */
  104.     public $hideEmptyData;
  105.     /**
  106.      * @internal
  107.      *
  108.      * @var bool
  109.      */
  110.     public $disallowAddRemove;
  111.     /**
  112.      * contains further localized field definitions if there are more than one localized fields in on class
  113.      *
  114.      * @internal
  115.      *
  116.      * @var array
  117.      */
  118.     protected $referencedFields = [];
  119.     /**
  120.      * @internal
  121.      *
  122.      * @var array|null
  123.      */
  124.     public $fieldDefinitionsCache;
  125.     /**
  126.      * @internal
  127.      *
  128.      * @var array
  129.      */
  130.     public $allowedGroupIds;
  131.     /**
  132.      * @internal
  133.      *
  134.      * @var array
  135.      */
  136.     public $activeGroupDefinitions = [];
  137.     /**
  138.      * @internal
  139.      *
  140.      * @var int|null
  141.      */
  142.     public $maxItems;
  143.     /**
  144.      * @internal
  145.      *
  146.      * @var array
  147.      */
  148.     public $permissionView;
  149.     /**
  150.      * @internal
  151.      *
  152.      * @var array
  153.      */
  154.     public $permissionEdit;
  155.     /**
  156.      * @see Data::getDataForEditmode
  157.      *
  158.      * @param mixed $data
  159.      * @param null|DataObject\Concrete $object
  160.      * @param array $params
  161.      *
  162.      * @return array
  163.      */
  164.     public function getDataForEditmode($data$object null$params = [])
  165.     {
  166.         if (!$data instanceof DataObject\Classificationstore) {
  167.             return [];
  168.         }
  169.         $fieldData = [];
  170.         $metaData = [];
  171.         $result $this->doGetDataForEditMode($data$object$fieldData$metaData1);
  172.         // replace the real data with the data for the editmode
  173.         foreach ($result['data'] as $language => &$groups) {
  174.             foreach ($groups as $groupId => &$keys) {
  175.                 foreach ($keys as $keyId => &$keyValue) {
  176.                     $keyConfig DataObject\Classificationstore\DefinitionCache::get($keyId);
  177.                     if ($keyConfig->getEnabled()) {
  178.                         $fd DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  179.                         $keyValue $fd->getDataForEditmode($keyValue$object$params);
  180.                     }
  181.                 }
  182.             }
  183.         }
  184.         $activeGroupIds $this->recursiveGetActiveGroupsIds($object);
  185.         $validLanguages $this->getValidLanguages();
  186.         foreach ($validLanguages as $language) {
  187.             foreach ($activeGroupIds as $groupId => $enabled) {
  188.                 if (!$enabled) {
  189.                     continue;
  190.                 }
  191.                 $relation = new DataObject\Classificationstore\KeyGroupRelation\Listing();
  192.                 $relation->setCondition("type = 'calculatedValue' and groupId = " $relation->quote($groupId));
  193.                 $relation $relation->load();
  194.                 foreach ($relation as $key) {
  195.                     $keyId $key->getKeyId();
  196.                     $childDef DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($key);
  197.                     $childData = new DataObject\Data\CalculatedValue($this->getName());
  198.                     $childData->setContextualData('classificationstore'$this->getName(), null$language$groupId$keyId$childDef);
  199.                     $childData $childDef->getDataForEditmode($childData$object$params);
  200.                     $result['data'][$language][$groupId][$keyId] = $childData;
  201.                 }
  202.             }
  203.         }
  204.         $result['activeGroups'] = $data->getActiveGroups();
  205.         $result['groupCollectionMapping'] = $data->getGroupCollectionMappings();
  206.         return $result;
  207.     }
  208.     /**
  209.      * @param DataObject\Classificationstore $data
  210.      * @param DataObject\Concrete $object
  211.      * @param array $fieldData structure: [language][groupId][keyId] = field data
  212.      * @param array $metaData structure: [language][groupId][keyId] = array with meta info
  213.      * @param int $level
  214.      *
  215.      * @return array
  216.      */
  217.     private function doGetDataForEditMode($data$object, &$fieldData, &$metaData$level 1)
  218.     {
  219.         $class $object->getClass();
  220.         $inheritanceAllowed $class->getAllowInherit();
  221.         $inherited false;
  222.         $items $data->getItems();
  223.         foreach ($items as $groupId => $keys) {
  224.             if (!isset($data->getActiveGroups()[$groupId])) {
  225.                 continue;
  226.             }
  227.             foreach ($keys as $keyId => $languages) {
  228.                 $keyConfig DataObject\Classificationstore\DefinitionCache::get($keyId);
  229.                 if ($keyConfig->getEnabled()) {
  230.                     $fd DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  231.                     foreach ($languages as $language => $value) {
  232.                         $fdata $value;
  233.                         if (!isset($fieldData[$language][$groupId][$keyId]) || $fd->isEmpty($fieldData[$language][$groupId][$keyId])) {
  234.                             // never override existing data
  235.                             $fieldData[$language][$groupId][$keyId] = $fdata;
  236.                             if (!$fd->isEmpty($fdata)) {
  237.                                 $metaData[$language][$groupId][$keyId] = ['inherited' => $level 1'objectid' => $object->getId()];
  238.                             }
  239.                         }
  240.                     }
  241.                 }
  242.             }
  243.         }
  244.         // TODO
  245.         if ($inheritanceAllowed) {
  246.             // check if there is a parent with the same type
  247.             $parent DataObject\Service::hasInheritableParentObject($object);
  248.             if ($parent) {
  249.                 // same type, iterate over all language and all fields and check if there is something missing
  250.                 if ($this->localized) {
  251.                     $validLanguages Tool::getValidLanguages();
  252.                 } else {
  253.                     $validLanguages = [];
  254.                 }
  255.                 array_unshift($validLanguages'default');
  256.                 $foundEmptyValue false;
  257.                 $activeGroupIds $this->recursiveGetActiveGroupsIds($object);
  258.                 foreach ($validLanguages as $language) {
  259.                     foreach ($activeGroupIds as $groupId => $enabled) {
  260.                         if (!$enabled) {
  261.                             continue;
  262.                         }
  263.                         $relation = new DataObject\Classificationstore\KeyGroupRelation\Listing();
  264.                         $relation->setCondition('groupId = ' $relation->quote($groupId));
  265.                         $relation $relation->load();
  266.                         foreach ($relation as $key) {
  267.                             $keyId $key->getKeyId();
  268.                             $fd DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($key);
  269.                             if ($fd->isEmpty($fieldData[$language][$groupId][$keyId] ?? null)) {
  270.                                 $foundEmptyValue true;
  271.                                 $inherited true;
  272.                                 $metaData[$language][$groupId][$keyId] = ['inherited' => true'objectid' => $parent->getId()];
  273.                             }
  274.                         }
  275.                     }
  276.                 }
  277.                 if ($foundEmptyValue) {
  278.                     // still some values are missing, ask the parent
  279.                     $getter 'get' ucfirst($this->getName());
  280.                     $parentData $parent->$getter();
  281.                     $parentResult $this->doGetDataForEditMode($parentData$parent$fieldData$metaData$level 1);
  282.                 }
  283.             }
  284.         }
  285.         $result = [
  286.             'data' => $fieldData,
  287.             'metaData' => $metaData,
  288.             'inherited' => $inherited,
  289.         ];
  290.         return $result;
  291.     }
  292.     /**
  293.      * @see Data::getDataFromEditmode
  294.      *
  295.      * @param mixed $containerData
  296.      * @param null|DataObject\Concrete $object
  297.      * @param array $params
  298.      *
  299.      * @return DataObject\Classificationstore
  300.      */
  301.     public function getDataFromEditmode($containerData$object null$params = [])
  302.     {
  303.         $classificationStore $this->getDataFromObjectParam($object);
  304.         if (!$classificationStore instanceof DataObject\Classificationstore) {
  305.             $classificationStore = new DataObject\Classificationstore();
  306.         }
  307.         $data $containerData['data'];
  308.         $activeGroups $containerData['activeGroups'];
  309.         $groupCollectionMapping $containerData['groupCollectionMapping'];
  310.         $correctedMapping = [];
  311.         foreach ($groupCollectionMapping as $groupId => $collectionId) {
  312.             if (isset($activeGroups[$groupId]) && $activeGroups[$groupId]) {
  313.                 $correctedMapping[$groupId] = $collectionId;
  314.             }
  315.         }
  316.         $classificationStore->setGroupCollectionMappings($correctedMapping);
  317.         if (is_array($data)) {
  318.             foreach ($data as $language => $groups) {
  319.                 foreach ($groups as $groupId => $keys) {
  320.                     foreach ($keys as $keyId => $value) {
  321.                         $keyConfig $this->getKeyConfiguration($keyId);
  322.                         $dataDefinition DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  323.                         $dataFromEditMode $dataDefinition->getDataFromEditmode($value);
  324.                         $activeGroups[$groupId] = true;
  325.                         $classificationStore->setLocalizedKeyValue($groupId$keyId$dataFromEditMode$language);
  326.                     }
  327.                 }
  328.             }
  329.         }
  330.         $activeGroupIds array_keys($activeGroups);
  331.         $classificationStore->setActiveGroups($activeGroups);
  332.         // cleanup
  333.         $existingGroupIds $classificationStore->getGroupIdsWithData();
  334.         if (is_array($existingGroupIds)) {
  335.             foreach ($existingGroupIds as $existingGroupId) {
  336.                 if (!in_array($existingGroupId$activeGroupIds)) {
  337.                     $classificationStore->removeGroupData($existingGroupId);
  338.                 }
  339.             }
  340.         }
  341.         return $classificationStore;
  342.     }
  343.     /**
  344.      * @param mixed $data
  345.      * @param DataObject\Concrete|null $object
  346.      * @param mixed $params
  347.      *
  348.      * @return string
  349.      */
  350.     public function getDataForGrid($data$object null$params = [])
  351.     {
  352.         return 'not supported';
  353.     }
  354.     /**
  355.      * @see Data::getVersionPreview
  356.      *
  357.      * @param mixed $data
  358.      * @param null|DataObject\Concrete $object
  359.      * @param array $params
  360.      *
  361.      * @return string
  362.      */
  363.     public function getVersionPreview($data$object null$params = [])
  364.     {
  365.         // this is handled directly in the template
  366.         // /bundles/AdminBundle/Resources/views/Admin/DataObject/DataObject/previewVersion.html.twig
  367.         return 'CLASSIFICATIONSTORE';
  368.     }
  369.     /**
  370.      * {@inheritdoc}
  371.      */
  372.     public function getForCsvExport($object$params = [])
  373.     {
  374.         return 'not supported';
  375.     }
  376.     /**
  377.      * {@inheritdoc}
  378.      */
  379.     public function getDataForSearchIndex($object$params = [])
  380.     {
  381.         $dataString '';
  382.         $getter 'get' ucfirst($this->getName());
  383.         $classificationStore $object->$getter();
  384.         $items $classificationStore->getItems();
  385.         $activeGroups $classificationStore->getActiveGroups();
  386.         $params['owner'] = $classificationStore;
  387.         if ($items) {
  388.             foreach ($items as $groupId => $keys) {
  389.                 if (!isset($activeGroups[$groupId])) {
  390.                     continue;
  391.                 }
  392.                 foreach ($keys as $keyId => $values) {
  393.                     $keyConfig $this->getKeyConfiguration($keyId);
  394.                     /** @var ResourcePersistenceAwareInterface $fieldDefinition */
  395.                     $fieldDefinition DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  396.                     foreach ($values as $language => $value) {
  397.                         $value $fieldDefinition->getDataForResource($value$object$params);
  398.                         if (is_array($value)) {
  399.                             $value implode(','$value);
  400.                         }
  401.                         $dataString .= $value ' ';
  402.                     }
  403.                 }
  404.             }
  405.         }
  406.         return $dataString;
  407.     }
  408.     /**
  409.      * @param mixed $data
  410.      *
  411.      * @return bool
  412.      */
  413.     public function isEmpty($data)
  414.     {
  415.         if ($data instanceof DataObject\Classificationstore) {
  416.             return empty($data->getItems());
  417.         }
  418.         return is_null($data);
  419.     }
  420.     /**
  421.      * @return array
  422.      */
  423.     public function getChildren()
  424.     {
  425.         return $this->children;
  426.     }
  427.     /**
  428.      * @param array $children
  429.      *
  430.      * @return $this
  431.      */
  432.     public function setChildren($children)
  433.     {
  434.         $this->children $children;
  435.         $this->fieldDefinitionsCache null;
  436.         return $this;
  437.     }
  438.     /**
  439.      * @return bool
  440.      */
  441.     public function hasChildren()
  442.     {
  443.         if (is_array($this->children) && count($this->children) > 0) {
  444.             return true;
  445.         }
  446.         return false;
  447.     }
  448.     /**
  449.      * @param mixed $child
  450.      */
  451.     public function addChild($child)
  452.     {
  453.         $this->children[] = $child;
  454.         $this->fieldDefinitionsCache null;
  455.     }
  456.     /**
  457.      * @param array $referencedFields
  458.      */
  459.     public function setReferencedFields($referencedFields)
  460.     {
  461.         $this->referencedFields $referencedFields;
  462.         $this->fieldDefinitionsCache null;
  463.     }
  464.     /**
  465.      * @return array
  466.      */
  467.     public function getReferencedFields()
  468.     {
  469.         return $this->referencedFields;
  470.     }
  471.     /**
  472.      * @param Data $field
  473.      */
  474.     public function addReferencedField($field)
  475.     {
  476.         $this->referencedFields[] = $field;
  477.         $this->fieldDefinitionsCache null;
  478.     }
  479.     /**
  480.      * {@inheritdoc}
  481.      */
  482.     public function save($object$params = [])
  483.     {
  484.         $classificationStore $this->getDataFromObjectParam($object);
  485.         if ($classificationStore instanceof DataObject\Classificationstore) {
  486.             $classificationStore->setObject($object);
  487.             $classificationStore->save();
  488.         }
  489.     }
  490.     /**
  491.      * {@inheritdoc}
  492.      */
  493.     public function load($object$params = [])
  494.     {
  495.         $classificationStore = new DataObject\Classificationstore();
  496.         $classificationStore->setObject($object);
  497.         $classificationStore->setFieldname($this->getName());
  498.         $classificationStore->load();
  499.         return $classificationStore;
  500.     }
  501.     /**
  502.      * {@inheritdoc}
  503.      */
  504.     public function delete($object$params = [])
  505.     {
  506.         $classificationStore $this->getDataFromObjectParam($object);
  507.         if ($classificationStore instanceof DataObject\Classificationstore) {
  508.             $classificationStore->setObject($object);
  509.             $classificationStore->setFieldname($this->getName());
  510.             $classificationStore->delete();
  511.         }
  512.     }
  513.     /**
  514.      * This method is called in DataObject\ClassDefinition::save() and is used to create the database table for the classification data
  515.      *
  516.      * @param DataObject\ClassDefinition $class
  517.      * @param array $params
  518.      */
  519.     public function classSaved($class/**, $params = []**/)
  520.     {
  521.         $classificationStore = new DataObject\Classificationstore();
  522.         $classificationStore->setClass($class);
  523.         $classificationStore->createUpdateTable();
  524.     }
  525.     /**
  526.      * {@inheritdoc}
  527.      */
  528.     public function preGetData(/** mixed */ $container/** array */ $params = []) // : mixed
  529.     {
  530.         if (!$container instanceof DataObject\Concrete) {
  531.             throw new \Exception('Classification store fields are only valid in Objects');
  532.         }
  533.         if (!$container->getObjectVar($this->getName()) instanceof DataObject\Classificationstore) {
  534.             $store = new DataObject\Classificationstore();
  535.             $store->setObject($container);
  536.             $store->setFieldname($this->getName());
  537.             $container->{'set' $this->getName()}($store);
  538.         }
  539.         return $container->getObjectVar($this->getName());
  540.     }
  541.     /**
  542.      * @param int $keyId
  543.      *
  544.      * @return DataObject\Classificationstore\KeyConfig
  545.      */
  546.     public function getKeyConfiguration($keyId)
  547.     {
  548.         /** @var DataObject\Classificationstore\KeyConfig $keyConfig */
  549.         $keyConfig DataObject\Classificationstore\DefinitionCache::get($keyId);
  550.         return $keyConfig;
  551.     }
  552.     /**
  553.      * @param string|int $height
  554.      *
  555.      * @return $this
  556.      */
  557.     public function setHeight($height)
  558.     {
  559.         if (is_numeric($height)) {
  560.             $height = (int)$height;
  561.         }
  562.         $this->height $height;
  563.         return $this;
  564.     }
  565.     /**
  566.      * @return string|int
  567.      */
  568.     public function getHeight()
  569.     {
  570.         return $this->height;
  571.     }
  572.     /**
  573.      * @param mixed $layout
  574.      *
  575.      * @return $this
  576.      */
  577.     public function setLayout($layout)
  578.     {
  579.         $this->layout $layout;
  580.         return $this;
  581.     }
  582.     /**
  583.      * @return string
  584.      */
  585.     public function getLayout()
  586.     {
  587.         return $this->layout;
  588.     }
  589.     /**
  590.      * @param string $name
  591.      *
  592.      * @return $this
  593.      */
  594.     public function setName($name)
  595.     {
  596.         $this->name $name;
  597.         return $this;
  598.     }
  599.     /**
  600.      * @return string
  601.      */
  602.     public function getName()
  603.     {
  604.         return $this->name;
  605.     }
  606.     /**
  607.      * @param string|null $region
  608.      *
  609.      * @return $this
  610.      */
  611.     public function setRegion($region)
  612.     {
  613.         $this->region $region;
  614.         return $this;
  615.     }
  616.     /**
  617.      * @return string
  618.      */
  619.     public function getRegion()
  620.     {
  621.         return $this->region;
  622.     }
  623.     /**
  624.      * @param string $title
  625.      *
  626.      * @return $this
  627.      */
  628.     public function setTitle($title)
  629.     {
  630.         $this->title $title;
  631.         return $this;
  632.     }
  633.     /**
  634.      * @return string
  635.      */
  636.     public function getTitle()
  637.     {
  638.         return $this->title;
  639.     }
  640.     /**
  641.      * @param string|int $width
  642.      *
  643.      * @return $this
  644.      */
  645.     public function setWidth($width)
  646.     {
  647.         if (is_numeric($width)) {
  648.             $width = (int)$width;
  649.         }
  650.         $this->width $width;
  651.         return $this;
  652.     }
  653.     /**
  654.      * @return string|int
  655.      */
  656.     public function getWidth()
  657.     {
  658.         return $this->width;
  659.     }
  660.     /**
  661.      * {@inheritdoc}
  662.      */
  663.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  664.     {
  665.         $activeGroups $data->getActiveGroups();
  666.         if (!$activeGroups) {
  667.             return;
  668.         }
  669.         $items $data->getItems();
  670.         $validLanguages $this->getValidLanguages();
  671.         $subItems = [];
  672.         $getInheritedValues DataObject::doGetInheritedValues();
  673.         if (!$omitMandatoryCheck) {
  674.             if ($this->maxItems && count($activeGroups) > $this->maxItems) {
  675.                 throw new Model\Element\ValidationException(
  676.                     'Groups in field [' $this->getName() . '] is bigger than ' $this->getMaxItems()
  677.                 );
  678.             }
  679.             foreach ($activeGroups as $activeGroupId => $enabled) {
  680.                 if ($enabled) {
  681.                     $groupDefinition DataObject\Classificationstore\GroupConfig::getById($activeGroupId);
  682.                     if (!$groupDefinition) {
  683.                         continue;
  684.                     }
  685.                     $keyGroupRelations $groupDefinition->getRelations();
  686.                     foreach ($keyGroupRelations as $keyGroupRelation) {
  687.                         foreach ($validLanguages as $validLanguage) {
  688.                             $keyId $keyGroupRelation->getKeyId();
  689.                             $object $data->getObject();
  690.                             if ($object->getClass()->getAllowInherit()) {
  691.                                 DataObject::setGetInheritedValues(true);
  692.                                 $value $data->getLocalizedKeyValue($activeGroupId$keyId$validLanguagetrue);
  693.                                 DataObject::setGetInheritedValues($getInheritedValues);
  694.                             } else {
  695.                                 $value $items[$activeGroupId][$keyId][$validLanguage] ?? null;
  696.                             }
  697.                             $keyDef DataObject\Classificationstore\Service::getFieldDefinitionFromJson(json_decode($keyGroupRelation->getDefinition()), $keyGroupRelation->getType());
  698.                             if ($keyGroupRelation->isMandatory()) {
  699.                                 $keyDef->setMandatory(true);
  700.                             }
  701.                             try {
  702.                                 $keyDef->checkValidity($valuefalse$params);
  703.                             } catch (\Exception $exception) {
  704.                                 $subItems[] = new Model\Element\ValidationException(
  705.                                     $exception->getMessage() . ' (' $validLanguage ')',
  706.                                     $exception->getCode(),
  707.                                     $exception->getPrevious()
  708.                                 );
  709.                             }
  710.                         }
  711.                     }
  712.                 }
  713.             }
  714.         }
  715.         if ($subItems) {
  716.             $messages array_map(function (Model\Element\ValidationException $validationException) {
  717.                 $validationException->addContext($this->getName());
  718.                 return $validationException->getMessage();
  719.             }, $subItems);
  720.             $validationException = new Model\Element\ValidationException(implode(', '$messages));
  721.             $validationException->setSubItems($subItems);
  722.             throw $validationException;
  723.         }
  724.     }
  725.     /**
  726.      * @param mixed $data
  727.      * @param DataObject\Concrete|null $object
  728.      * @param array $params
  729.      *
  730.      * @throws \Exception
  731.      */
  732.     public function getDiffDataForEditmode($data$object null$params = [])
  733.     {
  734.         throw new \Exception('not supported');
  735.     }
  736.     /**
  737.      * @param array $data
  738.      * @param DataObject\Concrete|null $object
  739.      * @param array $params
  740.      *
  741.      * @throws \Exception
  742.      */
  743.     public function getDiffDataFromEditmode($data$object null$params = [])
  744.     {
  745.         throw new \Exception('not supported');
  746.     }
  747.     /**
  748.      * {@inheritdoc}
  749.      */
  750.     public function isDiffChangeAllowed($object$params = [])
  751.     {
  752.         return false;
  753.     }
  754.     /**
  755.      * @return array
  756.      */
  757.     public function getBlockedVarsForExport(): array
  758.     {
  759.         return [
  760.             'fieldDefinitionsCache',
  761.             'referencedFields',
  762.             'blockedVarsForExport',
  763.             'childs',
  764.         ];
  765.     }
  766.     /**
  767.      * @return array
  768.      */
  769.     public function __sleep()
  770.     {
  771.         $vars get_object_vars($this);
  772.         $blockedVars $this->getBlockedVarsForExport();
  773.         foreach ($blockedVars as $blockedVar) {
  774.             unset($vars[$blockedVar]);
  775.         }
  776.         return array_keys($vars);
  777.     }
  778.     /**
  779.      * @param int $maxTabs
  780.      */
  781.     public function setMaxTabs($maxTabs)
  782.     {
  783.         $this->maxTabs $maxTabs;
  784.     }
  785.     /**
  786.      * @return int
  787.      */
  788.     public function getMaxTabs()
  789.     {
  790.         return $this->maxTabs;
  791.     }
  792.     /**
  793.      * @param int $labelWidth
  794.      */
  795.     public function setLabelWidth($labelWidth)
  796.     {
  797.         $this->labelWidth = (int)$labelWidth;
  798.     }
  799.     /**
  800.      * @return int
  801.      */
  802.     public function getLabelWidth()
  803.     {
  804.         return $this->labelWidth;
  805.     }
  806.     /**
  807.      * @param int|null $maxItems
  808.      */
  809.     public function setMaxItems($maxItems)
  810.     {
  811.         $this->maxItems $this->getAsIntegerCast($maxItems);
  812.     }
  813.     /**
  814.      * @return int|null
  815.      */
  816.     public function getMaxItems()
  817.     {
  818.         return $this->maxItems;
  819.     }
  820.     /**
  821.      * @return bool
  822.      */
  823.     public function isLocalized()
  824.     {
  825.         return $this->localized;
  826.     }
  827.     /**
  828.      * @param bool $localized
  829.      */
  830.     public function setLocalized($localized)
  831.     {
  832.         $this->localized $localized;
  833.     }
  834.     /**
  835.      * @return array|null
  836.      */
  837.     public function getPermissionView(): ?array
  838.     {
  839.         return $this->permissionView;
  840.     }
  841.     /**
  842.      * @param string|array|null $permissionView
  843.      */
  844.     public function setPermissionView($permissionView): void
  845.     {
  846.         $this->permissionView $permissionView;
  847.     }
  848.     /**
  849.      * @return array|null
  850.      */
  851.     public function getPermissionEdit(): ?array
  852.     {
  853.         return $this->permissionEdit;
  854.     }
  855.     /**
  856.      * @param string|array|null $permissionEdit
  857.      */
  858.     public function setPermissionEdit($permissionEdit): void
  859.     {
  860.         $this->permissionEdit $permissionEdit;
  861.     }
  862.     /**
  863.      * @param DataObject\Concrete|null $object
  864.      * @param array $mergedMapping
  865.      *
  866.      * @return array|null
  867.      *
  868.      * @todo: Method returns void/null, should be boolean or null
  869.      */
  870.     private function recursiveGetActiveGroupCollectionMapping($object$mergedMapping = [])
  871.     {
  872.         if (!$object) {
  873.             return null;
  874.         }
  875.         $getter 'get' ucfirst($this->getName());
  876.         /** @var DataObject\Classificationstore $classificationStore */
  877.         $classificationStore $object->$getter();
  878.         $mapping $classificationStore->getGroupCollectionMappings();
  879.         if (is_array($mapping)) {
  880.             foreach ($mapping as $groupId => $collectionId) {
  881.                 if (!isset($mergedMapping[$groupId]) && $collectionId) {
  882.                     $mergedMapping[$groupId] = $collectionId;
  883.                 }
  884.             }
  885.         }
  886.         $class $object->getClass();
  887.         $inheritanceAllowed $class->getAllowInherit();
  888.         if ($inheritanceAllowed) {
  889.             $parent DataObject\Service::hasInheritableParentObject($object);
  890.             if ($parent) {
  891.                 $mergedMapping $this->recursiveGetActiveGroupCollectionMapping($parent$mergedMapping);
  892.             }
  893.         }
  894.         return $mergedMapping;
  895.     }
  896.     /**
  897.      * @internal
  898.      *
  899.      * @param DataObject\Concrete|null $object
  900.      * @param array $activeGroups
  901.      *
  902.      * @return array|null
  903.      */
  904.     public function recursiveGetActiveGroupsIds($object$activeGroups = [])
  905.     {
  906.         if (!$object) {
  907.             return null;
  908.         }
  909.         $getter 'get' ucfirst($this->getName());
  910.         /** @var DataObject\Classificationstore $classificationStore */
  911.         $classificationStore $object->$getter();
  912.         $activeGroupIds $classificationStore->getActiveGroups();
  913.         if ($activeGroupIds) {
  914.             $activeGroups array_filter($activeGroupIds);
  915.         }
  916.         $class $object->getClass();
  917.         $inheritanceAllowed $class->getAllowInherit();
  918.         if ($inheritanceAllowed) {
  919.             $parent DataObject\Service::hasInheritableParentObject($object);
  920.             if ($parent) {
  921.                 $activeGroups += $this->recursiveGetActiveGroupsIds($parent$activeGroups);
  922.             }
  923.         }
  924.         return $activeGroups;
  925.     }
  926.     /**
  927.      * {@inheritdoc}
  928.      */
  929.     public function enrichLayoutDefinition(/* ?Concrete */ $object/* array */ $context = []) // : static
  930.     {
  931.         $this->activeGroupDefinitions = [];
  932.         $activeGroupIds $this->recursiveGetActiveGroupsIds($object);
  933.         if (!$activeGroupIds) {
  934.             return $this;
  935.         }
  936.         $filteredGroupIds array_keys($activeGroupIdstruetrue);
  937.         $groupList = new DataObject\Classificationstore\GroupConfig\Listing();
  938.         $groupList->setCondition('`id` in (' implode(','array_fill(0count($filteredGroupIds), '?')) . ')'$filteredGroupIds);
  939.         $groupList->setOrderKey(['id']);
  940.         $groupList->setOrder(['ASC']);
  941.         foreach ($groupList->load() as $group) {
  942.             $keyList = [];
  943.             $relation = new DataObject\Classificationstore\KeyGroupRelation\Listing();
  944.             $relation->setCondition('`groupId` = ?'$group->getId());
  945.             $relation->setOrderKey(['sorter''id']);
  946.             $relation->setOrder(['ASC''ASC']);
  947.             $relation $relation->load();
  948.             /** @var DataObject\Classificationstore\KeyGroupRelation $keyGroupRelation */
  949.             foreach ($relation as $keyGroupRelation) {
  950.                 if (!$keyGroupRelation->isEnabled()) {
  951.                     continue;
  952.                 }
  953.                 $definition DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyGroupRelation);
  954.                 // changes here also have an effect here: "bundles/AdminBundle/Resources/public/js/pimcore/object/tags/classificationstore.js"
  955.                 $fallbackTooltip $definition->getName();
  956.                 if (!empty($keyGroupRelation->getDescription())) {
  957.                     $fallbackTooltip .= ' - ' $keyGroupRelation->getDescription();
  958.                 }
  959.                 $definition->setTooltip($definition->getTooltip() ?: $fallbackTooltip);
  960.                 if (method_exists($definition'__wakeup')) {
  961.                     $definition->__wakeup();
  962.                 }
  963.                 $definition->setMandatory($definition->getMandatory() || $keyGroupRelation->isMandatory());
  964.                 //TODO Pimcore 11: remove method_exists BC layer
  965.                 if ($definition instanceof LayoutDefinitionEnrichmentInterface || method_exists($definition'enrichLayoutDefinition')) {
  966.                     if (!$definition instanceof LayoutDefinitionEnrichmentInterface) {
  967.                         trigger_deprecation('pimcore/pimcore''10.1',
  968.                             sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  969.                             'Implement the %s interface instead.'LayoutDefinitionEnrichmentInterface::class));
  970.                     }
  971.                     $context['object'] = $object;
  972.                     $context['class'] = $object->getClass();
  973.                     $context['ownerType'] = 'classificationstore';
  974.                     $context['ownerName'] = $this->getName();
  975.                     $context['keyId'] = $keyGroupRelation->getKeyId();
  976.                     $context['groupId'] = $keyGroupRelation->getGroupId();
  977.                     $context['keyDefinition'] = $definition;
  978.                     $definition $definition->enrichLayoutDefinition($object$context);
  979.                 }
  980.                 $keyList[] = [
  981.                     'name' => $keyGroupRelation->getName(),
  982.                     'id' => $keyGroupRelation->getKeyId(),
  983.                     'description' => $keyGroupRelation->getDescription(),
  984.                     'definition' => $definition,
  985.                 ];
  986.             }
  987.             $this->activeGroupDefinitions[$group->getId()] = [
  988.                 'name' => $group->getName(),
  989.                 'id' => $group->getId(),
  990.                 'description' => $group->getDescription(),
  991.                 'keys' => $keyList,
  992.             ];
  993.         }
  994.         $groupCollectionMapping $this->recursiveGetActiveGroupCollectionMapping($object);
  995.         if (!empty($groupCollectionMapping)) {
  996.             $collectionIds array_values($groupCollectionMapping);
  997.             $relation = new DataObject\Classificationstore\CollectionGroupRelation\Listing();
  998.             $relation->setCondition('`colId` in (' implode(','array_fill(0count($collectionIds), '?')) . ')'$collectionIds);
  999.             $sorting = [];
  1000.             foreach ($relation->load() as $item) {
  1001.                 $sorting[$item->getGroupId()] = $item->getSorter();
  1002.             }
  1003.             usort($this->activeGroupDefinitions, static function ($a$b) use ($sorting) {
  1004.                 $s1 $sorting[$a['id']] ?? 0;
  1005.                 $s2 $sorting[$b['id']] ?? 0;
  1006.                 return $s1 <=> $s2;
  1007.             });
  1008.         }
  1009.         return $this;
  1010.     }
  1011.     /**
  1012.      * @return array
  1013.      */
  1014.     public function getAllowedGroupIds()
  1015.     {
  1016.         return $this->allowedGroupIds;
  1017.     }
  1018.     /**
  1019.      * @param array|string $allowedGroupIds
  1020.      */
  1021.     public function setAllowedGroupIds($allowedGroupIds)
  1022.     {
  1023.         $parts = [];
  1024.         if (is_string($allowedGroupIds) && !empty($allowedGroupIds)) {
  1025.             $allowedGroupIds str_replace([' '"\n"], ''$allowedGroupIds);
  1026.             $parts explode(','$allowedGroupIds);
  1027.         } elseif (is_array($allowedGroupIds)) {
  1028.             $parts $allowedGroupIds;
  1029.         }
  1030.         $this->allowedGroupIds $parts;
  1031.     }
  1032.     /**
  1033.      * @return int
  1034.      */
  1035.     public function getStoreId()
  1036.     {
  1037.         return $this->storeId $this->storeId 1;
  1038.     }
  1039.     /**
  1040.      * @param int $storeId
  1041.      *
  1042.      * @return $this
  1043.      */
  1044.     public function setStoreId($storeId)
  1045.     {
  1046.         $this->storeId $storeId $storeId 1;
  1047.         return $this;
  1048.     }
  1049.     /**
  1050.      * @return string[]
  1051.      */
  1052.     private function getValidLanguages()
  1053.     {
  1054.         if ($this->localized) {
  1055.             $validLanguages Tool::getValidLanguages();
  1056.         } else {
  1057.             $validLanguages = [];
  1058.         }
  1059.         array_unshift($validLanguages'default');
  1060.         return $validLanguages;
  1061.     }
  1062.     /**
  1063.      * @return bool
  1064.      */
  1065.     public function getHideEmptyData()
  1066.     {
  1067.         return $this->hideEmptyData;
  1068.     }
  1069.     /**
  1070.      * @param bool $hideEmptyData
  1071.      *
  1072.      * @return $this
  1073.      */
  1074.     public function setHideEmptyData($hideEmptyData)
  1075.     {
  1076.         $this->hideEmptyData = (bool) $hideEmptyData;
  1077.         return $this;
  1078.     }
  1079.     /**
  1080.      * @return bool
  1081.      */
  1082.     public function isDisallowAddRemove()
  1083.     {
  1084.         return $this->disallowAddRemove;
  1085.     }
  1086.     /**
  1087.      * @param bool $disallowAddRemove
  1088.      *
  1089.      * @return $this
  1090.      */
  1091.     public function setDisallowAddRemove($disallowAddRemove)
  1092.     {
  1093.         $this->disallowAddRemove $disallowAddRemove;
  1094.         return $this;
  1095.     }
  1096.     /**
  1097.      * {@inheritdoc}
  1098.      */
  1099.     public function getParameterTypeDeclaration(): ?string
  1100.     {
  1101.         return '?\\' DataObject\Classificationstore::class;
  1102.     }
  1103.     /**
  1104.      * {@inheritdoc}
  1105.      */
  1106.     public function getReturnTypeDeclaration(): ?string
  1107.     {
  1108.         return '?\\' DataObject\Classificationstore::class;
  1109.     }
  1110.     /**
  1111.      * {@inheritdoc}
  1112.      */
  1113.     public function getPhpdocInputType(): ?string
  1114.     {
  1115.         return '\\' DataObject\Classificationstore::class . '|null';
  1116.     }
  1117.     /**
  1118.      * {@inheritdoc}
  1119.      */
  1120.     public function getPhpdocReturnType(): ?string
  1121.     {
  1122.         return '\\' DataObject\Classificationstore::class . '|null';
  1123.     }
  1124.     /**
  1125.      * {@inheritdoc}
  1126.      */
  1127.     public function normalize($value$params = [])
  1128.     {
  1129.         if ($value instanceof DataObject\Classificationstore) {
  1130.             $validLanguages array_merge(['default'], Tool::getValidLanguages());
  1131.             $result = [];
  1132.             $activeGroups $value->getActiveGroups();
  1133.             if ($activeGroups) {
  1134.                 foreach ($activeGroups as $groupId => $active) {
  1135.                     if (!$active) {
  1136.                         continue;
  1137.                     }
  1138.                     $groupConfig DataObject\Classificationstore\GroupConfig::getById($groupId);
  1139.                     $result[$groupConfig->getName()] = [];
  1140.                     $relation = new DataObject\Classificationstore\KeyGroupRelation\Listing();
  1141.                     $relation->setCondition('groupId = ' $relation->quote($groupId));
  1142.                     $relation $relation->load();
  1143.                     foreach ($validLanguages as $validLanguage) {
  1144.                         foreach ($relation as $key) {
  1145.                             $keyId $key->getKeyId();
  1146.                             $csValue $value->getLocalizedKeyValue($groupId$keyId$validLanguagetruetrue);
  1147.                             $keyConfig DataObject\Classificationstore\DefinitionCache::get($keyId);
  1148.                             $fd DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  1149.                             if ($fd instanceof NormalizerInterface) {
  1150.                                 $csValue $fd->normalize($csValue$params);
  1151.                             }
  1152.                             if ($csValue !== null) {
  1153.                                 $result[$groupConfig->getName()][$validLanguage][$key->getName()] = $csValue;
  1154.                             }
  1155.                         }
  1156.                     }
  1157.                 }
  1158.             }
  1159.             return $result;
  1160.         }
  1161.         return null;
  1162.     }
  1163.     /**
  1164.      * {@inheritdoc}
  1165.      */
  1166.     public function denormalize($value$params = [])
  1167.     {
  1168.         if (is_array($value)) {
  1169.             $activeGroups = [];
  1170.             $resultData = [];
  1171.             foreach ($value as $groupName => $groupData) {
  1172.                 $groupConfig DataObject\Classificationstore\GroupConfig::getByName($groupName);
  1173.                 $activeGroups[$groupConfig->getId()] = true;
  1174.                 $resultData[$groupConfig->getId()] = [];
  1175.                 foreach ($groupData as $language => $languageData) {
  1176.                     foreach ($languageData as $fieldKey => $fieldData) {
  1177.                         $keyConfig DataObject\Classificationstore\KeyConfig::getByName($fieldKey);
  1178.                         $fd DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  1179.                         if ($fd instanceof NormalizerInterface) {
  1180.                             $fieldData $fd->denormalize($fieldData$params);
  1181.                         }
  1182.                         $resultData[$groupConfig->getId()][$keyConfig->getId()][$language] = $fieldData;
  1183.                     }
  1184.                 }
  1185.             }
  1186.             $result = new DataObject\Classificationstore();
  1187.             $result->setActiveGroups($activeGroups);
  1188.             $result->setItems($resultData);
  1189.             return $result;
  1190.         }
  1191.         return null;
  1192.     }
  1193.     /**
  1194.      * Creates getter code which is used for generation of php file for object classes using this data type
  1195.      *
  1196.      * @param DataObject\ClassDefinition|DataObject\Objectbrick\Definition|DataObject\Fieldcollection\Definition $class
  1197.      *
  1198.      * @return string
  1199.      */
  1200.     public function getGetterCode($class)
  1201.     {
  1202.         $key $this->getName();
  1203.         $typeDeclaration '';
  1204.         if ($class->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getReturnTypeDeclaration()) {
  1205.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  1206.         }
  1207.         $code '/**' "\n";
  1208.         $code .= '* Get ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  1209.         $code .= '* @return ' $this->getPhpdocReturnType() . "\n";
  1210.         $code .= '*/' "\n";
  1211.         $code .= 'public function get' ucfirst($key) . '()' $typeDeclaration "\n";
  1212.         $code .= '{' "\n";
  1213.         $code .= $this->getPreGetValueHookCode($key);
  1214.         $code .= "\t" '$data = $this->getClass()->getFieldDefinition("' $key '")->preGetData($this);' "\n\n";
  1215.         $code .= "\t" 'return $data;' "\n";
  1216.         $code .= "}\n\n";
  1217.         return $code;
  1218.     }
  1219.     /**
  1220.      * @param array $data
  1221.      *
  1222.      * @return static
  1223.      */
  1224.     public static function __set_state($data)
  1225.     {
  1226.         $obj = new static();
  1227.         $obj->setValues($data);
  1228.         $obj->childs $obj->children;  // @phpstan-ignore-line
  1229.         return $obj;
  1230.     }
  1231. }