vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/Localizedfields.php line 1447

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\Logger;
  16. use Pimcore\Model;
  17. use Pimcore\Model\DataObject;
  18. use Pimcore\Model\DataObject\ClassDefinition\Data;
  19. use Pimcore\Model\DataObject\ClassDefinition\Layout;
  20. use Pimcore\Model\Element;
  21. use Pimcore\Normalizer\NormalizerInterface;
  22. use Pimcore\Tool;
  23. class Localizedfields extends Data implements CustomResourcePersistingInterfaceTypeDeclarationSupportInterfaceNormalizerInterfaceDataContainerAwareInterfaceIdRewriterInterfacePreGetDataInterfaceVarExporterInterface
  24. {
  25.     use Element\ChildsCompatibilityTrait;
  26.     use Layout\Traits\LabelTrait;
  27.     use DataObject\Traits\ClassSavedTrait;
  28.     /**
  29.      * Static type of this element
  30.      *
  31.      * @internal
  32.      *
  33.      * @var string
  34.      */
  35.     public $fieldtype 'localizedfields';
  36.     /**
  37.      * @internal
  38.      *
  39.      * @var array
  40.      */
  41.     public $children = [];
  42.     /**
  43.      * @internal
  44.      *
  45.      * @var string
  46.      */
  47.     public $name;
  48.     /**
  49.      * @internal
  50.      *
  51.      * @var string
  52.      */
  53.     public $region;
  54.     /**
  55.      * @internal
  56.      *
  57.      * @var string
  58.      */
  59.     public $layout;
  60.     /**
  61.      * @internal
  62.      *
  63.      * @var string
  64.      */
  65.     public $title;
  66.     /**
  67.      * @internal
  68.      *
  69.      * @var string|int
  70.      */
  71.     public $width 0;
  72.     /**
  73.      * @internal
  74.      *
  75.      * @var string|int
  76.      */
  77.     public $height 0;
  78.     /**
  79.      * @internal
  80.      *
  81.      * @var int
  82.      */
  83.     public $maxTabs;
  84.     /**
  85.      * @internal
  86.      *
  87.      * @var bool
  88.      */
  89.     public $border false;
  90.     /**
  91.      * @internal
  92.      *
  93.      * @var bool
  94.      */
  95.     public $provideSplitView;
  96.     /**
  97.      * @internal
  98.      *
  99.      * @var string|null
  100.      */
  101.     public $tabPosition 'top';
  102.     /**
  103.      * @internal
  104.      *
  105.      * @var int
  106.      */
  107.     public $hideLabelsWhenTabsReached;
  108.     /**
  109.      * contains further localized field definitions if there are more than one localized fields in on class
  110.      *
  111.      * @internal
  112.      *
  113.      * @var array
  114.      */
  115.     protected $referencedFields = [];
  116.     /**
  117.      * @internal
  118.      *
  119.      * @var array|null
  120.      */
  121.     public $fieldDefinitionsCache;
  122.     /**
  123.      * @internal
  124.      *
  125.      * @var array|null
  126.      */
  127.     public $permissionView;
  128.     /**
  129.      * @internal
  130.      *
  131.      * @var array|null
  132.      */
  133.     public $permissionEdit;
  134.     /**
  135.      * @see Data::getDataForEditmode
  136.      *
  137.      * @param DataObject\Localizedfield $localizedField
  138.      * @param null|DataObject\Concrete $object
  139.      * @param mixed $params
  140.      *
  141.      * @return array
  142.      */
  143.     public function getDataForEditmode($localizedField$object null$params = [])
  144.     {
  145.         $fieldData = [];
  146.         $metaData = [];
  147.         if (!$localizedField instanceof DataObject\Localizedfield) {
  148.             return [];
  149.         }
  150.         $result $this->doGetDataForEditMode($localizedField$object$fieldData$metaData1$params);
  151.         // replace the real data with the data for the editmode
  152.         foreach ($result['data'] as $language => &$data) {
  153.             foreach ($data as $key => &$value) {
  154.                 $fieldDefinition $this->getFieldDefinition($key);
  155.                 if ($fieldDefinition instanceof CalculatedValue) {
  156.                     $childData = new DataObject\Data\CalculatedValue($fieldDefinition->getName());
  157.                     $ownerType $params['context']['containerType'] ?? 'localizedfield';
  158.                     $ownerName $params['fieldname'] ?? $this->getName();
  159.                     $index $params['context']['containerKey'] ?? null;
  160.                     $childData->setContextualData($ownerType$ownerName$index$languagenullnull$fieldDefinition);
  161.                     $value $fieldDefinition->getDataForEditmode($childData$object$params);
  162.                 } else {
  163.                     $value $fieldDefinition->getDataForEditmode($value$objectarray_merge($params$localizedField->getDao()->getFieldDefinitionParams($fieldDefinition->getName(), $language)));
  164.                 }
  165.             }
  166.         }
  167.         return $result;
  168.     }
  169.     /**
  170.      * @param DataObject\Localizedfield $data
  171.      * @param DataObject\Concrete $object
  172.      * @param array $fieldData
  173.      * @param array $metaData
  174.      * @param int $level
  175.      * @param array $params
  176.      *
  177.      * @return array
  178.      */
  179.     private function doGetDataForEditMode($data$object, &$fieldData, &$metaData$level 1$params = [])
  180.     {
  181.         $class $object->getClass();
  182.         $inheritanceAllowed $class->getAllowInherit();
  183.         $inherited false;
  184.         $loadLazy = !($params['objectFromVersion'] ?? false);
  185.         $dataItems $data->getInternalData($loadLazy);
  186.         foreach ($dataItems as $language => $values) {
  187.             foreach ($this->getFieldDefinitions() as $fd) {
  188.                 if ($fd instanceof LazyLoadingSupportInterface && $fd->getLazyLoading() && $loadLazy) {
  189.                     $lazyKey $data->buildLazyKey($fd->getName(), $language);
  190.                     if (!$data->isLazyKeyLoaded($lazyKey) && $fd instanceof CustomResourcePersistingInterface) {
  191.                         $params['language'] = $language;
  192.                         $params['object'] = $object;
  193.                         if (!isset($params['context'])) {
  194.                             $params['context'] = [];
  195.                         }
  196.                         $params['context']['object'] = $object;
  197.                         $value $fd->load($data$params);
  198.                         if ($value === || !empty($value)) {
  199.                             $data->setLocalizedValue($fd->getName(), $value$languagefalse);
  200.                             $values[$fd->getName()] = $value;
  201.                         }
  202.                         $data->markLazyKeyAsLoaded($lazyKey);
  203.                     }
  204.                 }
  205.                 $key $fd->getName();
  206.                 $fdata = isset($values[$fd->getName()]) ? $values[$fd->getName()] : null;
  207.                 if (!isset($fieldData[$language][$key]) || $fd->isEmpty($fieldData[$language][$key])) {
  208.                     // never override existing data
  209.                     $fieldData[$language][$key] = $fdata;
  210.                     if (!$fd->isEmpty($fdata)) {
  211.                         $inherited $level 1;
  212.                         if (isset($params['context']['containerType']) && $params['context']['containerType'] === 'block') {
  213.                             $inherited false;
  214.                         }
  215.                         $metaData[$language][$key] = ['inherited' => $inherited'objectid' => $object->getId()];
  216.                     }
  217.                 }
  218.             }
  219.         }
  220.         if (isset($params['context']['containerType']) && $params['context']['containerType'] === 'block') {
  221.             $inheritanceAllowed false;
  222.         }
  223.         if ($inheritanceAllowed) {
  224.             // check if there is a parent with the same type
  225.             $parent DataObject\Service::hasInheritableParentObject($object);
  226.             if ($parent) {
  227.                 // same type, iterate over all language and all fields and check if there is something missing
  228.                 $validLanguages Tool::getValidLanguages();
  229.                 $foundEmptyValue false;
  230.                 foreach ($validLanguages as $language) {
  231.                     $fieldDefinitions $this->getFieldDefinitions();
  232.                     foreach ($fieldDefinitions as $fd) {
  233.                         $key $fd->getName();
  234.                         if ($fd->isEmpty($fieldData[$language][$key] ?? null)) {
  235.                             $foundEmptyValue true;
  236.                             $inherited true;
  237.                             $metaData[$language][$key] = ['inherited' => true'objectid' => $parent->getId()];
  238.                         }
  239.                     }
  240.                 }
  241.                 if ($foundEmptyValue) {
  242.                     $parentData null;
  243.                     // still some values are passing, ask the parent
  244.                     if (isset($params['context']['containerType']) && $params['context']['containerType'] === 'objectbrick') {
  245.                         $brickContainerGetter 'get' ucfirst($params['fieldname']);
  246.                         $brickContainer $parent->$brickContainerGetter();
  247.                         $brickGetter 'get' ucfirst($params['context']['containerKey']);
  248.                         $brickData $brickContainer->$brickGetter();
  249.                         if ($brickData) {
  250.                             $parentData $brickData->getLocalizedFields();
  251.                         }
  252.                     } else {
  253.                         if (method_exists($parent'getLocalizedFields')) {
  254.                             $parentData $parent->getLocalizedFields();
  255.                         }
  256.                     }
  257.                     if ($parentData) {
  258.                         $parentResult $this->doGetDataForEditMode(
  259.                             $parentData,
  260.                             $parent,
  261.                             $fieldData,
  262.                             $metaData,
  263.                             $level 1,
  264.                             $params
  265.                         );
  266.                     }
  267.                 }
  268.             }
  269.         }
  270.         $result = [
  271.             'data' => $fieldData,
  272.             'metaData' => $metaData,
  273.             'inherited' => $inherited,
  274.         ];
  275.         return $result;
  276.     }
  277.     /**
  278.      * @see Data::getDataFromEditmode
  279.      *
  280.      * @param array $data
  281.      * @param null|DataObject\Concrete $object
  282.      * @param mixed $params
  283.      *
  284.      * @return DataObject\Localizedfield
  285.      */
  286.     public function getDataFromEditmode($data$object null$params = [])
  287.     {
  288.         $localizedFields $this->getDataFromObjectParam($object$params);
  289.         if (!$localizedFields instanceof DataObject\Localizedfield) {
  290.             $localizedFields = new DataObject\Localizedfield();
  291.             $context = isset($params['context']) ? $params['context'] : null;
  292.             $localizedFields->setContext($context);
  293.         }
  294.         if ($object) {
  295.             $localizedFields->setObject($object);
  296.         }
  297.         if (is_array($data)) {
  298.             foreach ($data as $language => $fields) {
  299.                 foreach ($fields as $name => $fdata) {
  300.                     $fd $this->getFieldDefinition($name);
  301.                     $params['language'] = $language;
  302.                     $localizedFields->setLocalizedValue(
  303.                         $name,
  304.                         $fd->getDataFromEditmode($fdata$object$params),
  305.                         $language
  306.                     );
  307.                 }
  308.             }
  309.         }
  310.         return $localizedFields;
  311.     }
  312.     /**
  313.      * @param DataObject\Localizedfield|null $data
  314.      * @param DataObject\Concrete|null $object
  315.      * @param mixed $params
  316.      *
  317.      * @return \stdClass
  318.      */
  319.     public function getDataForGrid($data$object null$params = [])
  320.     {
  321.         $result = new \stdClass();
  322.         foreach ($this->getFieldDefinitions() as $fd) {
  323.             $key $fd->getName();
  324.             $context $params['context'] ?? null;
  325.             if (isset($context['containerType']) && $context['containerType'] === 'objectbrick') {
  326.                 $result->$key 'NOT SUPPORTED';
  327.             } else {
  328.                 $result->$key $object->{'get' ucfirst($fd->getName())}();
  329.             }
  330.             if (method_exists($fd'getDataForGrid')) {
  331.                 $result->$key $fd->getDataForGrid($result->$key$object$params);
  332.             }
  333.         }
  334.         return $result;
  335.     }
  336.     /**
  337.      * @see Data::getVersionPreview
  338.      *
  339.      * @param DataObject\Localizedfield|null $data
  340.      * @param null|DataObject\Concrete $object
  341.      * @param mixed $params
  342.      *
  343.      * @return string
  344.      */
  345.     public function getVersionPreview($data$object null$params = [])
  346.     {
  347.         // this is handled directly in the template
  348.         // /bundles/AdminBundle/Resources/views/Admin/DataObject/DataObject/previewVersion.html.twig
  349.         return 'LOCALIZED FIELDS';
  350.     }
  351.     /**
  352.      * {@inheritdoc}
  353.      */
  354.     public function getForCsvExport($object$params = [])
  355.     {
  356.         return 'NOT SUPPORTED';
  357.     }
  358.     /**
  359.      * {@inheritdoc}
  360.      */
  361.     public function getDataForSearchIndex($object$params = [])
  362.     {
  363.         $dataString '';
  364.         $lfData $this->getDataFromObjectParam($object);
  365.         if ($lfData instanceof DataObject\Localizedfield) {
  366.             foreach ($lfData->getInternalData(true) as $language => $values) {
  367.                 foreach ($values as $fieldname => $lData) {
  368.                     $fd $this->getFieldDefinition($fieldname);
  369.                     if ($fd) {
  370.                         $forSearchIndex $fd->getDataForSearchIndex($lfData, [
  371.                             'injectedData' => $lData,
  372.                         ]);
  373.                         if ($forSearchIndex) {
  374.                             $dataString .= $forSearchIndex ' ';
  375.                         }
  376.                     }
  377.                 }
  378.             }
  379.         }
  380.         return $dataString;
  381.     }
  382.     /**
  383.      * @return array
  384.      */
  385.     public function getChildren()
  386.     {
  387.         return $this->children;
  388.     }
  389.     /**
  390.      * @param array $children
  391.      *
  392.      * @return $this
  393.      */
  394.     public function setChildren($children)
  395.     {
  396.         $this->children $children;
  397.         $this->fieldDefinitionsCache null;
  398.         return $this;
  399.     }
  400.     /**
  401.      * @return bool
  402.      */
  403.     public function hasChildren()
  404.     {
  405.         return is_array($this->children) && count($this->children) > 0;
  406.     }
  407.     /**
  408.      * @param Data|Layout $child
  409.      */
  410.     public function addChild($child)
  411.     {
  412.         $this->children[] = $child;
  413.         $this->fieldDefinitionsCache null;
  414.     }
  415.     /**
  416.      * @param Data[] $referencedFields
  417.      */
  418.     public function setReferencedFields($referencedFields)
  419.     {
  420.         $this->referencedFields $referencedFields;
  421.         $this->fieldDefinitionsCache null;
  422.     }
  423.     /**
  424.      * @return Data[]
  425.      */
  426.     public function getReferencedFields()
  427.     {
  428.         return $this->referencedFields;
  429.     }
  430.     /**
  431.      * @param Data $field
  432.      */
  433.     public function addReferencedField($field)
  434.     {
  435.         $this->referencedFields[] = $field;
  436.         $this->fieldDefinitionsCache null;
  437.     }
  438.     /**
  439.      * {@inheritdoc}
  440.      */
  441.     public function save($object$params = [])
  442.     {
  443.         $localizedFields $this->getDataFromObjectParam($object$params);
  444.         if ($localizedFields instanceof DataObject\Localizedfield) {
  445.             if ((!isset($params['newParent']) || !$params['newParent']) && isset($params['isUpdate']) && $params['isUpdate'] && !$localizedFields->hasDirtyLanguages()) {
  446.                 return;
  447.             }
  448.             if ($object instanceof DataObject\Fieldcollection\Data\AbstractData || $object instanceof DataObject\Objectbrick\Data\AbstractData) {
  449.                 $object $object->getObject();
  450.             }
  451.             $localizedFields->setObject($objectfalse);
  452.             $context = isset($params['context']) ? $params['context'] : null;
  453.             $localizedFields->setContext($context);
  454.             $localizedFields->loadLazyData();
  455.             $localizedFields->save($params);
  456.         }
  457.     }
  458.     /**
  459.      * {@inheritdoc}
  460.      */
  461.     public function load($object$params = [])
  462.     {
  463.         if ($object instanceof DataObject\Fieldcollection\Data\AbstractData || $object instanceof DataObject\Objectbrick\Data\AbstractData) {
  464.             $object $object->getObject();
  465.         }
  466.         $localizedFields = new DataObject\Localizedfield();
  467.         $localizedFields->setObject($object);
  468.         $context = isset($params['context']) ? $params['context'] : null;
  469.         $localizedFields->setContext($context);
  470.         $localizedFields->load($object$params);
  471.         $localizedFields->resetDirtyMap();
  472.         $localizedFields->resetLanguageDirtyMap();
  473.         return $localizedFields;
  474.     }
  475.     /**
  476.      * {@inheritdoc}
  477.      */
  478.     public function delete($object$params = [])
  479.     {
  480.         $localizedFields $this->getDataFromObjectParam($object$params);
  481.         if ($localizedFields instanceof DataObject\Localizedfield) {
  482.             $localizedFields->setObject($object);
  483.             $context $params['context'] ?? [];
  484.             $localizedFields->setContext($context);
  485.             $localizedFields->delete(truefalse);
  486.         }
  487.     }
  488.     /**
  489.      * This method is called in DataObject\ClassDefinition::save() and is used to create the database table for the localized data
  490.      *
  491.      * @param DataObject\ClassDefinition $class
  492.      * @param array $params
  493.      */
  494.     public function classSaved($class$params = [])
  495.     {
  496.         // create a dummy instance just for updating the tables
  497.         $localizedFields = new DataObject\Localizedfield();
  498.         $localizedFields->setClass($class);
  499.         $context $params['context'] ?? [];
  500.         $localizedFields->setContext($context);
  501.         $localizedFields->createUpdateTable($params);
  502.         foreach ($this->getFieldDefinitions() as $fd) {
  503.             //TODO Pimcore 11 remove method_exists call
  504.             if (!$fd instanceof DataContainerAwareInterface && method_exists($fd'classSaved')) {
  505.                 $fd->classSaved($class$params);
  506.             }
  507.         }
  508.     }
  509.     /**
  510.      * { @inheritdoc }
  511.      */
  512.     public function preGetData(/** mixed */ $container/** array */ $params = []) // : mixed
  513.     {
  514.         if (
  515.             !$container instanceof DataObject\Concrete &&
  516.             !$container instanceof DataObject\Fieldcollection\Data\AbstractData &&
  517.             !$container instanceof DataObject\Objectbrick\Data\AbstractData
  518.         ) {
  519.             throw new \Exception('Localized Fields are only valid in Objects, Fieldcollections and Objectbricks');
  520.         }
  521.         $lf $container->getObjectVar('localizedfields');
  522.         if (!$lf instanceof DataObject\Localizedfield) {
  523.             $lf = new DataObject\Localizedfield();
  524.             $object $container;
  525.             if ($container instanceof DataObject\Objectbrick\Data\AbstractData) {
  526.                 $object $container->getObject();
  527.                 $context = [
  528.                     'containerType' => 'objectbrick',
  529.                     'containerKey' => $container->getType(),
  530.                     'fieldname' => $container->getFieldname(),
  531.                 ];
  532.                 $lf->setContext($context);
  533.             } elseif ($container instanceof DataObject\Fieldcollection\Data\AbstractData) {
  534.                 $object $container->getObject();
  535.                 $context = [
  536.                     'containerType' => 'fieldcollection',
  537.                     'containerKey' => $container->getType(),
  538.                     'fieldname' => $container->getFieldname(),
  539.                 ];
  540.                 $lf->setContext($context);
  541.             } elseif ($container instanceof DataObject\Concrete) {
  542.                 $context = ['object' => $container];
  543.                 $lf->setContext($context);
  544.             }
  545.             $lf->setObject($object);
  546.             $container->setObjectVar('localizedfields'$lf);
  547.         }
  548.         return $container->getObjectVar('localizedfields');
  549.     }
  550.     /**
  551.      * {@inheritdoc}
  552.      */
  553.     public function getGetterCode($class)
  554.     {
  555.         $code '';
  556.         if (!$class instanceof DataObject\Fieldcollection\Definition) {
  557.             $code .= parent::getGetterCode($class);
  558.         }
  559.         $fieldDefinitions $this->getFieldDefinitions();
  560.         foreach ($fieldDefinitions as $fd) {
  561.             $code .= $fd->getGetterCodeLocalizedfields($class);
  562.         }
  563.         return $code;
  564.     }
  565.     /**
  566.      * {@inheritdoc}
  567.      */
  568.     public function getSetterCode($class)
  569.     {
  570.         $code '';
  571.         if (!$class instanceof DataObject\Fieldcollection\Definition) {
  572.             $code .= parent::getSetterCode($class);
  573.         }
  574.         foreach ($this->getFieldDefinitions() as $fd) {
  575.             $code .= $fd->getSetterCodeLocalizedfields($class);
  576.         }
  577.         return $code;
  578.     }
  579.     /**
  580.      * @param string $name
  581.      * @param array $context additional contextual data
  582.      *
  583.      * @return DataObject\ClassDefinition\Data|null
  584.      */
  585.     public function getFieldDefinition($name$context = [])
  586.     {
  587.         $fds $this->getFieldDefinitions($context);
  588.         if (isset($fds[$name])) {
  589.             $fieldDefinition $fds[$name];
  590.             if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  591.                 return $fieldDefinition;
  592.             }
  593.             $fieldDefinition $this->doEnrichFieldDefinition($fieldDefinition$context);
  594.             return $fieldDefinition;
  595.         }
  596.         return null;
  597.     }
  598.     /**
  599.      * @param array $context additional contextual data
  600.      *
  601.      * @return Data[]
  602.      */
  603.     public function getFieldDefinitions($context = [])
  604.     {
  605.         if (empty($this->fieldDefinitionsCache)) {
  606.             $definitions $this->doGetFieldDefinitions();
  607.             foreach ($this->getReferencedFields() as $rf) {
  608.                 if ($rf instanceof DataObject\ClassDefinition\Data\Localizedfields) {
  609.                     $definitions array_merge($definitions$this->doGetFieldDefinitions($rf->getChildren()));
  610.                 }
  611.             }
  612.             $this->fieldDefinitionsCache $definitions;
  613.         }
  614.         if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  615.             return $this->fieldDefinitionsCache;
  616.         }
  617.         $enrichedFieldDefinitions = [];
  618.         foreach ($this->fieldDefinitionsCache ?? [] as $key => $fieldDefinition) {
  619.             $fieldDefinition $this->doEnrichFieldDefinition($fieldDefinition$context);
  620.             $enrichedFieldDefinitions[$key] = $fieldDefinition;
  621.         }
  622.         return $enrichedFieldDefinitions;
  623.     }
  624.     private function doEnrichFieldDefinition($fieldDefinition$context = [])
  625.     {
  626.         //TODO Pimcore 11: remove method_exists BC layer
  627.         if ($fieldDefinition instanceof FieldDefinitionEnrichmentInterface || method_exists($fieldDefinition'enrichFieldDefinition')) {
  628.             if (!$fieldDefinition instanceof FieldDefinitionEnrichmentInterface) {
  629.                 trigger_deprecation('pimcore/pimcore''10.1',
  630.                     sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  631.                     'Implement the %s interface instead.'FieldDefinitionEnrichmentInterface::class));
  632.             }
  633.             $context['class'] = $this;
  634.             $fieldDefinition $fieldDefinition->enrichFieldDefinition($context);
  635.         }
  636.         return $fieldDefinition;
  637.     }
  638.     /**
  639.      * @param mixed $def
  640.      * @param array $fields
  641.      *
  642.      * @return array
  643.      */
  644.     private function doGetFieldDefinitions($def null$fields = [])
  645.     {
  646.         if ($def === null) {
  647.             $def $this->getChildren();
  648.         }
  649.         if (is_array($def)) {
  650.             foreach ($def as $child) {
  651.                 $fields array_merge($fields$this->doGetFieldDefinitions($child$fields));
  652.             }
  653.         }
  654.         if ($def instanceof DataObject\ClassDefinition\Layout) {
  655.             if ($def->hasChildren()) {
  656.                 foreach ($def->getChildren() as $child) {
  657.                     $fields array_merge($fields$this->doGetFieldDefinitions($child$fields));
  658.                 }
  659.             }
  660.         }
  661.         if ($def instanceof DataObject\ClassDefinition\Data) {
  662.             $fields[$def->getName()] = $def;
  663.         }
  664.         return $fields;
  665.     }
  666.     /**
  667.      * {@inheritdoc}
  668.      */
  669.     public function getCacheTags($data, array $tags = [])
  670.     {
  671.         if (!$data instanceof DataObject\Localizedfield) {
  672.             return $tags;
  673.         }
  674.         foreach ($data->getInternalData(true) as $language => $values) {
  675.             foreach ($this->getFieldDefinitions() as $fd) {
  676.                 if (isset($values[$fd->getName()])) {
  677.                     $tags $fd->getCacheTags($values[$fd->getName()], $tags);
  678.                 }
  679.             }
  680.         }
  681.         return $tags;
  682.     }
  683.     /**
  684.      * @param DataObject\Localizedfield|null $data
  685.      *
  686.      * @return array
  687.      */
  688.     public function resolveDependencies($data)
  689.     {
  690.         $dependencies = [];
  691.         if (!$data instanceof DataObject\Localizedfield) {
  692.             return [];
  693.         }
  694.         foreach ($data->getInternalData(true) as $language => $values) {
  695.             foreach ($this->getFieldDefinitions() as $fd) {
  696.                 if (isset($values[$fd->getName()])) {
  697.                     $dependencies array_merge($dependencies$fd->resolveDependencies($values[$fd->getName()]));
  698.                 }
  699.             }
  700.         }
  701.         return $dependencies;
  702.     }
  703.     /**
  704.      * @param string|int $height
  705.      *
  706.      * @return $this
  707.      */
  708.     public function setHeight($height)
  709.     {
  710.         if (is_numeric($height)) {
  711.             $height = (int)$height;
  712.         }
  713.         $this->height $height;
  714.         return $this;
  715.     }
  716.     /**
  717.      * @return string|int
  718.      */
  719.     public function getHeight()
  720.     {
  721.         return $this->height;
  722.     }
  723.     /**
  724.      * @param mixed $layout
  725.      *
  726.      * @return $this
  727.      */
  728.     public function setLayout($layout)
  729.     {
  730.         $this->layout $layout;
  731.         return $this;
  732.     }
  733.     /**
  734.      * @return string
  735.      */
  736.     public function getLayout()
  737.     {
  738.         return $this->layout;
  739.     }
  740.     /**
  741.      * @return bool
  742.      */
  743.     public function getBorder(): bool
  744.     {
  745.         return $this->border;
  746.     }
  747.     /**
  748.      * @param bool $border
  749.      */
  750.     public function setBorder(bool $border): void
  751.     {
  752.         $this->border $border;
  753.     }
  754.     /**
  755.      * @param string $name
  756.      *
  757.      * @return $this
  758.      *
  759.      * @throws \Exception
  760.      */
  761.     public function setName($name)
  762.     {
  763.         if ($name !== 'localizedfields') {
  764.             throw new \Exception('Localizedfields can only be named `localizedfields`, no other names are allowed');
  765.         }
  766.         $this->name $name;
  767.         return $this;
  768.     }
  769.     /**
  770.      * @param string|null $region
  771.      *
  772.      * @return $this
  773.      */
  774.     public function setRegion($region)
  775.     {
  776.         $this->region $region;
  777.         return $this;
  778.     }
  779.     /**
  780.      * @return string
  781.      */
  782.     public function getRegion()
  783.     {
  784.         return $this->region;
  785.     }
  786.     /**
  787.      * @param int|string $width
  788.      *
  789.      * @return $this
  790.      */
  791.     public function setWidth($width)
  792.     {
  793.         if (is_numeric($width)) {
  794.             $width = (int)$width;
  795.         }
  796.         $this->width $width;
  797.         return $this;
  798.     }
  799.     /**
  800.      * @return int|string
  801.      */
  802.     public function getWidth()
  803.     {
  804.         return $this->width;
  805.     }
  806.     /**
  807.      * {@inheritdoc}
  808.      */
  809.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  810.     {
  811.         $config \Pimcore\Config::getSystemConfiguration('general');
  812.         $languages = [];
  813.         if (isset($config['valid_languages'])) {
  814.             $languages explode(','$config['valid_languages']);
  815.         }
  816.         $dataForValidityCheck $this->getDataForValidity($data$languages);
  817.         $validationExceptions = [];
  818.         if (!$omitMandatoryCheck) {
  819.             foreach ($languages as $language) {
  820.                 foreach ($this->getFieldDefinitions() as $fd) {
  821.                     try {
  822.                         try {
  823.                             if (!isset($dataForValidityCheck[$language][$fd->getName()])) {
  824.                                 $dataForValidityCheck[$language][$fd->getName()] = null;
  825.                             }
  826.                             $fd->checkValidity($dataForValidityCheck[$language][$fd->getName()], false$params);
  827.                         } catch (\Exception $e) {
  828.                             if ($data->getObject()->getClass()->getAllowInherit() && $fd->supportsInheritance() && $fd->isEmpty($dataForValidityCheck[$language][$fd->getName()])) {
  829.                                 //try again with parent data when inheritance is activated
  830.                                 try {
  831.                                     $getInheritedValues DataObject::doGetInheritedValues();
  832.                                     DataObject::setGetInheritedValues(true);
  833.                                     $value null;
  834.                                     $context $data->getContext();
  835.                                     $containerType $context['containerType'] ?? null;
  836.                                     if ($containerType === 'objectbrick') {
  837.                                         $brickContainer $data->getObject()->{'get' ucfirst($context['fieldname'])}();
  838.                                         $brick $brickContainer->{'get' ucfirst($context['containerKey'])}();
  839.                                         if ($brick) {
  840.                                             $value $brick->{'get' ucfirst($fd->getName())}($language);
  841.                                         }
  842.                                     } elseif ($containerType === null || $containerType === 'object') {
  843.                                         $getter 'get' ucfirst($fd->getName());
  844.                                         $value $data->getObject()->$getter($language);
  845.                                     }
  846.                                     $fd->checkValidity($value$omitMandatoryCheck$params);
  847.                                     DataObject::setGetInheritedValues($getInheritedValues);
  848.                                 } catch (\Exception $e) {
  849.                                     if (!$e instanceof Model\Element\ValidationException) {
  850.                                         throw $e;
  851.                                     }
  852.                                     $exceptionClass get_class($e);
  853.                                     throw new $exceptionClass($e->getMessage() . ' fieldname=' $fd->getName(), $e->getCode(), $e->getPrevious());
  854.                                 }
  855.                             } else {
  856.                                 if ($e instanceof Model\Element\ValidationException) {
  857.                                     throw $e;
  858.                                 }
  859.                                 $exceptionClass get_class($e);
  860.                                 throw new $exceptionClass($e->getMessage() . ' fieldname=' $fd->getName(), $e->getCode(), $e);
  861.                             }
  862.                         }
  863.                     } catch (Model\Element\ValidationException $ve) {
  864.                         $ve->addContext($this->getName() . '-' $language);
  865.                         $validationExceptions[] = $ve;
  866.                     }
  867.                 }
  868.             }
  869.         }
  870.         if (count($validationExceptions) > 0) {
  871.             $errors = [];
  872.             /** @var Element\ValidationException $e */
  873.             foreach ($validationExceptions as $e) {
  874.                 $errors[] = $e->getAggregatedMessage();
  875.             }
  876.             $message implode(' / '$errors);
  877.             throw new Model\Element\ValidationException($message);
  878.         }
  879.     }
  880.     /**
  881.      * @param DataObject\Localizedfield $localizedObject
  882.      * @param array $languages
  883.      *
  884.      * @return array
  885.      */
  886.     private function getDataForValidity($localizedObject, array $languages)
  887.     {
  888.         if (!$localizedObject->getObject()
  889.             || $localizedObject->getObject()->getType() != DataObject::OBJECT_TYPE_VARIANT
  890.             || !$localizedObject instanceof DataObject\Localizedfield) {
  891.             return $localizedObject->getInternalData(true);
  892.         }
  893.         //prepare data for variants
  894.         $data = [];
  895.         foreach ($languages as $language) {
  896.             $data[$language] = [];
  897.             foreach ($this->getFieldDefinitions() as $fd) {
  898.                 $data[$language][$fd->getName()] = $localizedObject->getLocalizedValue($fd->getName(), $language);
  899.             }
  900.         }
  901.         return $data;
  902.     }
  903.     /**
  904.      * @param mixed $data
  905.      * @param DataObject\Concrete|null $object
  906.      * @param mixed $params
  907.      *
  908.      * @return array|null
  909.      */
  910.     public function getDiffDataForEditmode($data$object null$params = [])
  911.     {
  912.         $return = [];
  913.         $myname $this->getName();
  914.         if (!$data instanceof DataObject\Localizedfield) {
  915.             return [];
  916.         }
  917.         foreach ($data->getInternalData(true) as $language => $values) {
  918.             foreach ($this->getFieldDefinitions() as $fd) {
  919.                 $fieldname $fd->getName();
  920.                 $subdata $fd->getDiffDataForEditmode($values[$fieldname], $object$params);
  921.                 foreach ($subdata as $item) {
  922.                     $diffdata['field'] = $this->getName();
  923.                     $diffdata['key'] = $this->getName().'~'.$fieldname.'~'.$item['key'].'~'.$language;
  924.                     $diffdata['type'] = $item['type'];
  925.                     $diffdata['value'] = $item['value'];
  926.                     // this is not needed anymoe
  927.                     unset($item['type']);
  928.                     unset($item['value']);
  929.                     $diffdata['title'] = $this->getName().' / '.$item['title'];
  930.                     $diffdata['lang'] = $language;
  931.                     $diffdata['data'] = $item;
  932.                     $diffdata['extData'] = [
  933.                         'fieldname' => $fieldname,
  934.                     ];
  935.                     $diffdata['disabled'] = $item['disabled'];
  936.                     $return[] = $diffdata;
  937.                 }
  938.             }
  939.         }
  940.         return $return;
  941.     }
  942.     /**
  943.      * @param array $data
  944.      * @param DataObject\Concrete|null $object
  945.      * @param mixed $params
  946.      *
  947.      * @return DataObject\Localizedfield
  948.      */
  949.     public function getDiffDataFromEditmode($data$object null$params = [])
  950.     {
  951.         $localFields $this->getDataFromObjectParam($object$params);
  952.         $localData = [];
  953.         // get existing data
  954.         if ($localFields instanceof DataObject\Localizedfield) {
  955.             $localData $localFields->getInternalData(true);
  956.         }
  957.         $mapping = [];
  958.         foreach ($data as $item) {
  959.             $extData $item['extData'];
  960.             $fieldname $extData['fieldname'];
  961.             $language $item['lang'];
  962.             $values $mapping[$fieldname] ?? [];
  963.             $itemdata $item['data'];
  964.             if ($itemdata) {
  965.                 $values[] = $itemdata;
  966.             }
  967.             $mapping[$language][$fieldname] = $values;
  968.         }
  969.         foreach ($mapping as $language => $fields) {
  970.             foreach ($fields as $key => $value) {
  971.                 $fd $this->getFieldDefinition($key);
  972.                 if ($fd && $fd->isDiffChangeAllowed($object)) {
  973.                     if ($value == null) {
  974.                         unset($localData[$language][$key]);
  975.                     } else {
  976.                         $localData[$language][$key] = $fd->getDiffDataFromEditmode($value);
  977.                     }
  978.                 }
  979.             }
  980.         }
  981.         $localizedFields = new DataObject\Localizedfield($localData);
  982.         $localizedFields->setObject($object);
  983.         return $localizedFields;
  984.     }
  985.     /**
  986.      * {@inheritdoc}
  987.      */
  988.     public function isDiffChangeAllowed($object$params = [])
  989.     {
  990.         return true;
  991.     }
  992.     /**
  993.      * @return array
  994.      */
  995.     public function getBlockedVarsForExport(): array
  996.     {
  997.         return [
  998.             'fieldDefinitionsCache',
  999.             'referencedFields',
  1000.             'blockedVarsForExport',
  1001.             'permissionView',
  1002.             'permissionEdit',
  1003.             'childs',
  1004.         ];
  1005.     }
  1006.     /**
  1007.      * @return array
  1008.      */
  1009.     public function __sleep()
  1010.     {
  1011.         $vars get_object_vars($this);
  1012.         $blockedVars $this->getBlockedVarsForExport();
  1013.         foreach ($blockedVars as $blockedVar) {
  1014.             unset($vars[$blockedVar]);
  1015.         }
  1016.         return array_keys($vars);
  1017.     }
  1018.     /**
  1019.      * { @inheritdoc }
  1020.      */
  1021.     public function rewriteIds(/** mixed */ $container/** array */ $idMapping/** array */ $params = []) /** :mixed */
  1022.     {
  1023.         $data $this->getDataFromObjectParam($container$params);
  1024.         $validLanguages Tool::getValidLanguages();
  1025.         foreach ($validLanguages as $language) {
  1026.             foreach ($this->getFieldDefinitions() as $fd) {
  1027.                 //TODO Pimcore 11: remove method_exists BC layer
  1028.                 if ($fd instanceof IdRewriterInterface || method_exists($fd'rewriteIds')) {
  1029.                     if (!$fd instanceof IdRewriterInterface) {
  1030.                         trigger_deprecation('pimcore/pimcore''10.1',
  1031.                             sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  1032.                             'Implement the %s interface instead.'IdRewriterInterface::class));
  1033.                     }
  1034.                     $d $fd->rewriteIds($data$idMapping, ['language' => $language]);
  1035.                     $data->setLocalizedValue($fd->getName(), $d$language);
  1036.                 }
  1037.             }
  1038.         }
  1039.         return $data;
  1040.     }
  1041.     /**
  1042.      * @return int
  1043.      */
  1044.     public function getHideLabelsWhenTabsReached()
  1045.     {
  1046.         return $this->hideLabelsWhenTabsReached;
  1047.     }
  1048.     /**
  1049.      * @param int $hideLabelsWhenTabsReached
  1050.      *
  1051.      * @return $this
  1052.      */
  1053.     public function setHideLabelsWhenTabsReached($hideLabelsWhenTabsReached)
  1054.     {
  1055.         $this->hideLabelsWhenTabsReached $hideLabelsWhenTabsReached;
  1056.         return $this;
  1057.     }
  1058.     /**
  1059.      * @param int $maxTabs
  1060.      */
  1061.     public function setMaxTabs($maxTabs)
  1062.     {
  1063.         $this->maxTabs $maxTabs;
  1064.     }
  1065.     /**
  1066.      * @return int
  1067.      */
  1068.     public function getMaxTabs()
  1069.     {
  1070.         return $this->maxTabs;
  1071.     }
  1072.     /**
  1073.      * @param int $labelWidth
  1074.      */
  1075.     public function setLabelWidth($labelWidth)
  1076.     {
  1077.         $this->labelWidth = (int)$labelWidth;
  1078.     }
  1079.     /**
  1080.      * @return int
  1081.      */
  1082.     public function getLabelWidth()
  1083.     {
  1084.         return $this->labelWidth;
  1085.     }
  1086.     /**
  1087.      * @return array|null
  1088.      */
  1089.     public function getPermissionView(): ?array
  1090.     {
  1091.         return $this->permissionView;
  1092.     }
  1093.     /**
  1094.      * @param array|null $permissionView
  1095.      */
  1096.     public function setPermissionView($permissionView): void
  1097.     {
  1098.         $this->permissionView $permissionView;
  1099.     }
  1100.     /**
  1101.      * @return array|null
  1102.      */
  1103.     public function getPermissionEdit(): ?array
  1104.     {
  1105.         return $this->permissionEdit;
  1106.     }
  1107.     /**
  1108.      * @param array|null $permissionEdit
  1109.      */
  1110.     public function setPermissionEdit($permissionEdit): void
  1111.     {
  1112.         $this->permissionEdit $permissionEdit;
  1113.     }
  1114.     /**
  1115.      * @return bool
  1116.      */
  1117.     public function getProvideSplitView()
  1118.     {
  1119.         return $this->provideSplitView;
  1120.     }
  1121.     /**
  1122.      * @param bool $provideSplitView
  1123.      */
  1124.     public function setProvideSplitView($provideSplitView): void
  1125.     {
  1126.         $this->provideSplitView $provideSplitView;
  1127.     }
  1128.     /**
  1129.      * {@inheritdoc}
  1130.      */
  1131.     public function supportsDirtyDetection()
  1132.     {
  1133.         return true;
  1134.     }
  1135.     /**
  1136.      * {@inheritdoc}
  1137.      */
  1138.     public function isFilterable(): bool
  1139.     {
  1140.         return true;
  1141.     }
  1142.     /**
  1143.      * @return string
  1144.      */
  1145.     public function getTabPosition(): string
  1146.     {
  1147.         return $this->tabPosition ?? 'top';
  1148.     }
  1149.     /**
  1150.      * @param string|null $tabPosition
  1151.      */
  1152.     public function setTabPosition($tabPosition): void
  1153.     {
  1154.         $this->tabPosition $tabPosition;
  1155.     }
  1156.     /**
  1157.      * {@inheritdoc}
  1158.      */
  1159.     public function getParameterTypeDeclaration(): ?string
  1160.     {
  1161.         return '?\\' DataObject\Localizedfield::class;
  1162.     }
  1163.     /**
  1164.      * {@inheritdoc}
  1165.      */
  1166.     public function getReturnTypeDeclaration(): ?string
  1167.     {
  1168.         return '?\\' DataObject\Localizedfield::class;
  1169.     }
  1170.     /**
  1171.      * {@inheritdoc}
  1172.      */
  1173.     public function getPhpdocInputType(): ?string
  1174.     {
  1175.         return '\\'DataObject\Localizedfield::class . '|null';
  1176.     }
  1177.     /**
  1178.      * {@inheritdoc}
  1179.      */
  1180.     public function getPhpdocReturnType(): ?string
  1181.     {
  1182.         return '\\' DataObject\Localizedfield::class . '|null';
  1183.     }
  1184.     /**
  1185.      * {@inheritdoc}
  1186.      */
  1187.     public function normalize($value$params = [])
  1188.     {
  1189.         if ($value instanceof DataObject\Localizedfield) {
  1190.             $items $value->getInternalData();
  1191.             if (is_array($items)) {
  1192.                 $result = [];
  1193.                 foreach ($items as $language => $languageData) {
  1194.                     $languageResult = [];
  1195.                     foreach ($languageData as $elementName => $elementData) {
  1196.                         $fd $this->getFieldDefinition($elementName);
  1197.                         if (!$fd) {
  1198.                             // class definition seems to have changed
  1199.                             Logger::warn('class definition seems to have changed, element name: '.$elementName);
  1200.                             continue;
  1201.                         }
  1202.                         if ($fd instanceof NormalizerInterface) {
  1203.                             $dataForResource $fd->normalize($elementData$params);
  1204.                             $languageResult[$elementName] = $dataForResource;
  1205.                         }
  1206.                     }
  1207.                     $result[$language] = $languageResult;
  1208.                 }
  1209.                 return $result;
  1210.             }
  1211.         }
  1212.         return null;
  1213.     }
  1214.     /**
  1215.      * {@inheritdoc}
  1216.      */
  1217.     public function denormalize($value$params = [])
  1218.     {
  1219.         if (is_array($value)) {
  1220.             $lf = new DataObject\Localizedfield();
  1221.             $lf->setObject($params['object']);
  1222.             $items = [];
  1223.             foreach ($value as $language => $languageData) {
  1224.                 $languageResult = [];
  1225.                 foreach ($languageData as $elementName => $elementData) {
  1226.                     $fd $this->getFieldDefinition($elementName);
  1227.                     if (!$fd) {
  1228.                         // class definition seems to have changed
  1229.                         Logger::warn('class definition seems to have changed, element name: '.$elementName);
  1230.                         continue;
  1231.                     }
  1232.                     if ($fd instanceof NormalizerInterface) {
  1233.                         $dataFromResource $fd->denormalize($elementData$params);
  1234.                         $languageResult[$elementName] = $dataFromResource;
  1235.                     }
  1236.                 }
  1237.                 $items[$language] = $languageResult;
  1238.             }
  1239.             $lf->setItems($items);
  1240.             return $lf;
  1241.         }
  1242.         return null;
  1243.     }
  1244.     public static function __set_state($data)
  1245.     {
  1246.         $obj = new static();
  1247.         $obj->setValues($data);
  1248.         $obj->childs $obj->children;  // @phpstan-ignore-line
  1249.         return $obj;
  1250.     }
  1251. }