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

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 && ($fd instanceof ClassSavedInterface || method_exists($fd'classSaved'))) {
  505.                 if (!$fd instanceof ClassSavedInterface) {
  506.                     trigger_deprecation('pimcore/pimcore''10.6',
  507.                         sprintf('Usage of method_exists is deprecated since version 10.6 and will be removed in Pimcore 11.' .
  508.                         'Implement the %s interface instead.'ClassSavedInterface::class));
  509.                 }
  510.                 $fd->classSaved($class$params);
  511.             }
  512.         }
  513.     }
  514.     /**
  515.      * { @inheritdoc }
  516.      */
  517.     public function preGetData(/** mixed */ $container/** array */ $params = []) // : mixed
  518.     {
  519.         if (
  520.             !$container instanceof DataObject\Concrete &&
  521.             !$container instanceof DataObject\Fieldcollection\Data\AbstractData &&
  522.             !$container instanceof DataObject\Objectbrick\Data\AbstractData
  523.         ) {
  524.             throw new \Exception('Localized Fields are only valid in Objects, Fieldcollections and Objectbricks');
  525.         }
  526.         $lf $container->getObjectVar('localizedfields');
  527.         if (!$lf instanceof DataObject\Localizedfield) {
  528.             $lf = new DataObject\Localizedfield();
  529.             $object $container;
  530.             if ($container instanceof DataObject\Objectbrick\Data\AbstractData) {
  531.                 $object $container->getObject();
  532.                 $context = [
  533.                     'containerType' => 'objectbrick',
  534.                     'containerKey' => $container->getType(),
  535.                     'fieldname' => $container->getFieldname(),
  536.                 ];
  537.                 $lf->setContext($context);
  538.             } elseif ($container instanceof DataObject\Fieldcollection\Data\AbstractData) {
  539.                 $object $container->getObject();
  540.                 $context = [
  541.                     'containerType' => 'fieldcollection',
  542.                     'containerKey' => $container->getType(),
  543.                     'fieldname' => $container->getFieldname(),
  544.                 ];
  545.                 $lf->setContext($context);
  546.             } elseif ($container instanceof DataObject\Concrete) {
  547.                 $context = ['object' => $container];
  548.                 $lf->setContext($context);
  549.             }
  550.             $lf->setObject($object);
  551.             $container->setObjectVar('localizedfields'$lf);
  552.         }
  553.         return $container->getObjectVar('localizedfields');
  554.     }
  555.     /**
  556.      * {@inheritdoc}
  557.      */
  558.     public function getGetterCode($class)
  559.     {
  560.         $code '';
  561.         if (!$class instanceof DataObject\Fieldcollection\Definition) {
  562.             $code .= parent::getGetterCode($class);
  563.         }
  564.         $fieldDefinitions $this->getFieldDefinitions();
  565.         foreach ($fieldDefinitions as $fd) {
  566.             $code .= $fd->getGetterCodeLocalizedfields($class);
  567.         }
  568.         return $code;
  569.     }
  570.     /**
  571.      * {@inheritdoc}
  572.      */
  573.     public function getSetterCode($class)
  574.     {
  575.         $code '';
  576.         if (!$class instanceof DataObject\Fieldcollection\Definition) {
  577.             $code .= parent::getSetterCode($class);
  578.         }
  579.         foreach ($this->getFieldDefinitions() as $fd) {
  580.             $code .= $fd->getSetterCodeLocalizedfields($class);
  581.         }
  582.         return $code;
  583.     }
  584.     /**
  585.      * @param string $name
  586.      * @param array $context additional contextual data
  587.      *
  588.      * @return DataObject\ClassDefinition\Data|null
  589.      */
  590.     public function getFieldDefinition($name$context = [])
  591.     {
  592.         $fds $this->getFieldDefinitions($context);
  593.         if (isset($fds[$name])) {
  594.             $fieldDefinition $fds[$name];
  595.             if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  596.                 return $fieldDefinition;
  597.             }
  598.             $fieldDefinition $this->doEnrichFieldDefinition($fieldDefinition$context);
  599.             return $fieldDefinition;
  600.         }
  601.         return null;
  602.     }
  603.     /**
  604.      * @param array $context additional contextual data
  605.      *
  606.      * @return Data[]
  607.      */
  608.     public function getFieldDefinitions($context = [])
  609.     {
  610.         if (empty($this->fieldDefinitionsCache)) {
  611.             $definitions $this->doGetFieldDefinitions();
  612.             foreach ($this->getReferencedFields() as $rf) {
  613.                 if ($rf instanceof DataObject\ClassDefinition\Data\Localizedfields) {
  614.                     $definitions array_merge($definitions$this->doGetFieldDefinitions($rf->getChildren()));
  615.                 }
  616.             }
  617.             $this->fieldDefinitionsCache $definitions;
  618.         }
  619.         if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  620.             return $this->fieldDefinitionsCache;
  621.         }
  622.         $enrichedFieldDefinitions = [];
  623.         foreach ($this->fieldDefinitionsCache ?? [] as $key => $fieldDefinition) {
  624.             $fieldDefinition $this->doEnrichFieldDefinition($fieldDefinition$context);
  625.             $enrichedFieldDefinitions[$key] = $fieldDefinition;
  626.         }
  627.         return $enrichedFieldDefinitions;
  628.     }
  629.     private function doEnrichFieldDefinition($fieldDefinition$context = [])
  630.     {
  631.         //TODO Pimcore 11: remove method_exists BC layer
  632.         if ($fieldDefinition instanceof FieldDefinitionEnrichmentInterface || method_exists($fieldDefinition'enrichFieldDefinition')) {
  633.             if (!$fieldDefinition instanceof FieldDefinitionEnrichmentInterface) {
  634.                 trigger_deprecation('pimcore/pimcore''10.1',
  635.                     sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  636.                     'Implement the %s interface instead.'FieldDefinitionEnrichmentInterface::class));
  637.             }
  638.             $context['class'] = $this;
  639.             $fieldDefinition $fieldDefinition->enrichFieldDefinition($context);
  640.         }
  641.         return $fieldDefinition;
  642.     }
  643.     /**
  644.      * @param mixed $def
  645.      * @param array $fields
  646.      *
  647.      * @return array
  648.      */
  649.     private function doGetFieldDefinitions($def null$fields = [])
  650.     {
  651.         if ($def === null) {
  652.             $def $this->getChildren();
  653.         }
  654.         if (is_array($def)) {
  655.             foreach ($def as $child) {
  656.                 $fields array_merge($fields$this->doGetFieldDefinitions($child$fields));
  657.             }
  658.         }
  659.         if ($def instanceof DataObject\ClassDefinition\Layout) {
  660.             if ($def->hasChildren()) {
  661.                 foreach ($def->getChildren() as $child) {
  662.                     $fields array_merge($fields$this->doGetFieldDefinitions($child$fields));
  663.                 }
  664.             }
  665.         }
  666.         if ($def instanceof DataObject\ClassDefinition\Data) {
  667.             $fields[$def->getName()] = $def;
  668.         }
  669.         return $fields;
  670.     }
  671.     /**
  672.      * {@inheritdoc}
  673.      */
  674.     public function getCacheTags($data, array $tags = [])
  675.     {
  676.         if (!$data instanceof DataObject\Localizedfield) {
  677.             return $tags;
  678.         }
  679.         foreach ($data->getInternalData(true) as $language => $values) {
  680.             foreach ($this->getFieldDefinitions() as $fd) {
  681.                 if (isset($values[$fd->getName()])) {
  682.                     $tags $fd->getCacheTags($values[$fd->getName()], $tags);
  683.                 }
  684.             }
  685.         }
  686.         return $tags;
  687.     }
  688.     /**
  689.      * @param DataObject\Localizedfield|null $data
  690.      *
  691.      * @return array
  692.      */
  693.     public function resolveDependencies($data)
  694.     {
  695.         $dependencies = [];
  696.         if (!$data instanceof DataObject\Localizedfield) {
  697.             return [];
  698.         }
  699.         foreach ($data->getInternalData(true) as $language => $values) {
  700.             foreach ($this->getFieldDefinitions() as $fd) {
  701.                 if (isset($values[$fd->getName()])) {
  702.                     $dependencies array_merge($dependencies$fd->resolveDependencies($values[$fd->getName()]));
  703.                 }
  704.             }
  705.         }
  706.         return $dependencies;
  707.     }
  708.     /**
  709.      * @param string|int $height
  710.      *
  711.      * @return $this
  712.      */
  713.     public function setHeight($height)
  714.     {
  715.         if (is_numeric($height)) {
  716.             $height = (int)$height;
  717.         }
  718.         $this->height $height;
  719.         return $this;
  720.     }
  721.     /**
  722.      * @return string|int
  723.      */
  724.     public function getHeight()
  725.     {
  726.         return $this->height;
  727.     }
  728.     /**
  729.      * @param mixed $layout
  730.      *
  731.      * @return $this
  732.      */
  733.     public function setLayout($layout)
  734.     {
  735.         $this->layout $layout;
  736.         return $this;
  737.     }
  738.     /**
  739.      * @return string
  740.      */
  741.     public function getLayout()
  742.     {
  743.         return $this->layout;
  744.     }
  745.     /**
  746.      * @return bool
  747.      */
  748.     public function getBorder(): bool
  749.     {
  750.         return $this->border;
  751.     }
  752.     /**
  753.      * @param bool $border
  754.      */
  755.     public function setBorder(bool $border): void
  756.     {
  757.         $this->border $border;
  758.     }
  759.     /**
  760.      * @param string $name
  761.      *
  762.      * @return $this
  763.      *
  764.      * @throws \Exception
  765.      */
  766.     public function setName($name)
  767.     {
  768.         if ($name !== 'localizedfields') {
  769.             throw new \Exception('Localizedfields can only be named `localizedfields`, no other names are allowed');
  770.         }
  771.         $this->name $name;
  772.         return $this;
  773.     }
  774.     /**
  775.      * @param string|null $region
  776.      *
  777.      * @return $this
  778.      */
  779.     public function setRegion($region)
  780.     {
  781.         $this->region $region;
  782.         return $this;
  783.     }
  784.     /**
  785.      * @return string
  786.      */
  787.     public function getRegion()
  788.     {
  789.         return $this->region;
  790.     }
  791.     /**
  792.      * @param int|string $width
  793.      *
  794.      * @return $this
  795.      */
  796.     public function setWidth($width)
  797.     {
  798.         if (is_numeric($width)) {
  799.             $width = (int)$width;
  800.         }
  801.         $this->width $width;
  802.         return $this;
  803.     }
  804.     /**
  805.      * @return int|string
  806.      */
  807.     public function getWidth()
  808.     {
  809.         return $this->width;
  810.     }
  811.     /**
  812.      * {@inheritdoc}
  813.      */
  814.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  815.     {
  816.         $config \Pimcore\Config::getSystemConfiguration('general');
  817.         $languages = [];
  818.         if (isset($config['valid_languages'])) {
  819.             $languages explode(','$config['valid_languages']);
  820.         }
  821.         $dataForValidityCheck $this->getDataForValidity($data$languages);
  822.         $validationExceptions = [];
  823.         if (!$omitMandatoryCheck) {
  824.             foreach ($languages as $language) {
  825.                 foreach ($this->getFieldDefinitions() as $fd) {
  826.                     try {
  827.                         try {
  828.                             if (!isset($dataForValidityCheck[$language][$fd->getName()])) {
  829.                                 $dataForValidityCheck[$language][$fd->getName()] = null;
  830.                             }
  831.                             $fd->checkValidity($dataForValidityCheck[$language][$fd->getName()], false$params);
  832.                         } catch (\Exception $e) {
  833.                             if ($data->getObject()->getClass()->getAllowInherit() && $fd->supportsInheritance() && $fd->isEmpty($dataForValidityCheck[$language][$fd->getName()])) {
  834.                                 //try again with parent data when inheritance is activated
  835.                                 try {
  836.                                     $getInheritedValues DataObject::doGetInheritedValues();
  837.                                     DataObject::setGetInheritedValues(true);
  838.                                     $value null;
  839.                                     $context $data->getContext();
  840.                                     $containerType $context['containerType'] ?? null;
  841.                                     if ($containerType === 'objectbrick') {
  842.                                         $brickContainer $data->getObject()->{'get' ucfirst($context['fieldname'])}();
  843.                                         $brick $brickContainer->{'get' ucfirst($context['containerKey'])}();
  844.                                         if ($brick) {
  845.                                             $value $brick->{'get' ucfirst($fd->getName())}($language);
  846.                                         }
  847.                                     } elseif ($containerType === null || $containerType === 'object') {
  848.                                         $getter 'get' ucfirst($fd->getName());
  849.                                         $value $data->getObject()->$getter($language);
  850.                                     }
  851.                                     $fd->checkValidity($value$omitMandatoryCheck$params);
  852.                                     DataObject::setGetInheritedValues($getInheritedValues);
  853.                                 } catch (\Exception $e) {
  854.                                     if (!$e instanceof Model\Element\ValidationException) {
  855.                                         throw $e;
  856.                                     }
  857.                                     $exceptionClass get_class($e);
  858.                                     throw new $exceptionClass($e->getMessage() . ' fieldname=' $fd->getName(), $e->getCode(), $e->getPrevious());
  859.                                 }
  860.                             } else {
  861.                                 if ($e instanceof Model\Element\ValidationException) {
  862.                                     throw $e;
  863.                                 }
  864.                                 $exceptionClass get_class($e);
  865.                                 throw new $exceptionClass($e->getMessage() . ' fieldname=' $fd->getName(), $e->getCode(), $e);
  866.                             }
  867.                         }
  868.                     } catch (Model\Element\ValidationException $ve) {
  869.                         $ve->addContext($this->getName() . '-' $language);
  870.                         $validationExceptions[] = $ve;
  871.                     }
  872.                 }
  873.             }
  874.         }
  875.         if (count($validationExceptions) > 0) {
  876.             $errors = [];
  877.             /** @var Element\ValidationException $e */
  878.             foreach ($validationExceptions as $e) {
  879.                 $errors[] = $e->getAggregatedMessage();
  880.             }
  881.             $message implode(' / '$errors);
  882.             throw new Model\Element\ValidationException($message);
  883.         }
  884.     }
  885.     /**
  886.      * @param DataObject\Localizedfield $localizedObject
  887.      * @param array $languages
  888.      *
  889.      * @return array
  890.      */
  891.     private function getDataForValidity($localizedObject, array $languages)
  892.     {
  893.         if (!$localizedObject->getObject()
  894.             || $localizedObject->getObject()->getType() != DataObject::OBJECT_TYPE_VARIANT
  895.             || !$localizedObject instanceof DataObject\Localizedfield) {
  896.             return $localizedObject->getInternalData(true);
  897.         }
  898.         //prepare data for variants
  899.         $data = [];
  900.         foreach ($languages as $language) {
  901.             $data[$language] = [];
  902.             foreach ($this->getFieldDefinitions() as $fd) {
  903.                 $data[$language][$fd->getName()] = $localizedObject->getLocalizedValue($fd->getName(), $language);
  904.             }
  905.         }
  906.         return $data;
  907.     }
  908.     /**
  909.      * @param mixed $data
  910.      * @param DataObject\Concrete|null $object
  911.      * @param mixed $params
  912.      *
  913.      * @return array|null
  914.      */
  915.     public function getDiffDataForEditmode($data$object null$params = [])
  916.     {
  917.         $return = [];
  918.         $myname $this->getName();
  919.         if (!$data instanceof DataObject\Localizedfield) {
  920.             return [];
  921.         }
  922.         foreach ($data->getInternalData(true) as $language => $values) {
  923.             foreach ($this->getFieldDefinitions() as $fd) {
  924.                 $fieldname $fd->getName();
  925.                 $subdata $fd->getDiffDataForEditmode($values[$fieldname], $object$params);
  926.                 foreach ($subdata as $item) {
  927.                     $diffdata['field'] = $this->getName();
  928.                     $diffdata['key'] = $this->getName().'~'.$fieldname.'~'.$item['key'].'~'.$language;
  929.                     $diffdata['type'] = $item['type'];
  930.                     $diffdata['value'] = $item['value'];
  931.                     // this is not needed anymoe
  932.                     unset($item['type']);
  933.                     unset($item['value']);
  934.                     $diffdata['title'] = $this->getName().' / '.$item['title'];
  935.                     $diffdata['lang'] = $language;
  936.                     $diffdata['data'] = $item;
  937.                     $diffdata['extData'] = [
  938.                         'fieldname' => $fieldname,
  939.                     ];
  940.                     $diffdata['disabled'] = $item['disabled'];
  941.                     $return[] = $diffdata;
  942.                 }
  943.             }
  944.         }
  945.         return $return;
  946.     }
  947.     /**
  948.      * @param array $data
  949.      * @param DataObject\Concrete|null $object
  950.      * @param mixed $params
  951.      *
  952.      * @return DataObject\Localizedfield
  953.      */
  954.     public function getDiffDataFromEditmode($data$object null$params = [])
  955.     {
  956.         $localFields $this->getDataFromObjectParam($object$params);
  957.         $localData = [];
  958.         // get existing data
  959.         if ($localFields instanceof DataObject\Localizedfield) {
  960.             $localData $localFields->getInternalData(true);
  961.         }
  962.         $mapping = [];
  963.         foreach ($data as $item) {
  964.             $extData $item['extData'];
  965.             $fieldname $extData['fieldname'];
  966.             $language $item['lang'];
  967.             $values $mapping[$fieldname] ?? [];
  968.             $itemdata $item['data'];
  969.             if ($itemdata) {
  970.                 $values[] = $itemdata;
  971.             }
  972.             $mapping[$language][$fieldname] = $values;
  973.         }
  974.         foreach ($mapping as $language => $fields) {
  975.             foreach ($fields as $key => $value) {
  976.                 $fd $this->getFieldDefinition($key);
  977.                 if ($fd && $fd->isDiffChangeAllowed($object)) {
  978.                     if ($value == null) {
  979.                         unset($localData[$language][$key]);
  980.                     } else {
  981.                         $localData[$language][$key] = $fd->getDiffDataFromEditmode($value);
  982.                     }
  983.                 }
  984.             }
  985.         }
  986.         $localizedFields = new DataObject\Localizedfield($localData);
  987.         $localizedFields->setObject($object);
  988.         return $localizedFields;
  989.     }
  990.     /**
  991.      * {@inheritdoc}
  992.      */
  993.     public function isDiffChangeAllowed($object$params = [])
  994.     {
  995.         return true;
  996.     }
  997.     /**
  998.      * @return array
  999.      */
  1000.     public function getBlockedVarsForExport(): array
  1001.     {
  1002.         return [
  1003.             'fieldDefinitionsCache',
  1004.             'referencedFields',
  1005.             'blockedVarsForExport',
  1006.             'permissionView',
  1007.             'permissionEdit',
  1008.             'childs',
  1009.         ];
  1010.     }
  1011.     /**
  1012.      * @return array
  1013.      */
  1014.     public function __sleep()
  1015.     {
  1016.         $vars get_object_vars($this);
  1017.         $blockedVars $this->getBlockedVarsForExport();
  1018.         foreach ($blockedVars as $blockedVar) {
  1019.             unset($vars[$blockedVar]);
  1020.         }
  1021.         return array_keys($vars);
  1022.     }
  1023.     /**
  1024.      * { @inheritdoc }
  1025.      */
  1026.     public function rewriteIds(/** mixed */ $container/** array */ $idMapping/** array */ $params = []) /** :mixed */
  1027.     {
  1028.         $data $this->getDataFromObjectParam($container$params);
  1029.         $validLanguages Tool::getValidLanguages();
  1030.         foreach ($validLanguages as $language) {
  1031.             foreach ($this->getFieldDefinitions() as $fd) {
  1032.                 //TODO Pimcore 11: remove method_exists BC layer
  1033.                 if ($fd instanceof IdRewriterInterface || method_exists($fd'rewriteIds')) {
  1034.                     if (!$fd instanceof IdRewriterInterface) {
  1035.                         trigger_deprecation('pimcore/pimcore''10.1',
  1036.                             sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  1037.                             'Implement the %s interface instead.'IdRewriterInterface::class));
  1038.                     }
  1039.                     $d $fd->rewriteIds($data$idMapping, ['language' => $language]);
  1040.                     $data->setLocalizedValue($fd->getName(), $d$language);
  1041.                 }
  1042.             }
  1043.         }
  1044.         return $data;
  1045.     }
  1046.     /**
  1047.      * @return int
  1048.      */
  1049.     public function getHideLabelsWhenTabsReached()
  1050.     {
  1051.         return $this->hideLabelsWhenTabsReached;
  1052.     }
  1053.     /**
  1054.      * @param int $hideLabelsWhenTabsReached
  1055.      *
  1056.      * @return $this
  1057.      */
  1058.     public function setHideLabelsWhenTabsReached($hideLabelsWhenTabsReached)
  1059.     {
  1060.         $this->hideLabelsWhenTabsReached $hideLabelsWhenTabsReached;
  1061.         return $this;
  1062.     }
  1063.     /**
  1064.      * @param int $maxTabs
  1065.      */
  1066.     public function setMaxTabs($maxTabs)
  1067.     {
  1068.         $this->maxTabs $maxTabs;
  1069.     }
  1070.     /**
  1071.      * @return int
  1072.      */
  1073.     public function getMaxTabs()
  1074.     {
  1075.         return $this->maxTabs;
  1076.     }
  1077.     /**
  1078.      * @param int $labelWidth
  1079.      */
  1080.     public function setLabelWidth($labelWidth)
  1081.     {
  1082.         $this->labelWidth = (int)$labelWidth;
  1083.     }
  1084.     /**
  1085.      * @return int
  1086.      */
  1087.     public function getLabelWidth()
  1088.     {
  1089.         return $this->labelWidth;
  1090.     }
  1091.     /**
  1092.      * @return array|null
  1093.      */
  1094.     public function getPermissionView(): ?array
  1095.     {
  1096.         return $this->permissionView;
  1097.     }
  1098.     /**
  1099.      * @param array|null $permissionView
  1100.      */
  1101.     public function setPermissionView($permissionView): void
  1102.     {
  1103.         $this->permissionView $permissionView;
  1104.     }
  1105.     /**
  1106.      * @return array|null
  1107.      */
  1108.     public function getPermissionEdit(): ?array
  1109.     {
  1110.         return $this->permissionEdit;
  1111.     }
  1112.     /**
  1113.      * @param array|null $permissionEdit
  1114.      */
  1115.     public function setPermissionEdit($permissionEdit): void
  1116.     {
  1117.         $this->permissionEdit $permissionEdit;
  1118.     }
  1119.     /**
  1120.      * @return bool
  1121.      */
  1122.     public function getProvideSplitView()
  1123.     {
  1124.         return $this->provideSplitView;
  1125.     }
  1126.     /**
  1127.      * @param bool $provideSplitView
  1128.      */
  1129.     public function setProvideSplitView($provideSplitView): void
  1130.     {
  1131.         $this->provideSplitView $provideSplitView;
  1132.     }
  1133.     /**
  1134.      * {@inheritdoc}
  1135.      */
  1136.     public function supportsDirtyDetection()
  1137.     {
  1138.         return true;
  1139.     }
  1140.     /**
  1141.      * {@inheritdoc}
  1142.      */
  1143.     public function isFilterable(): bool
  1144.     {
  1145.         return true;
  1146.     }
  1147.     /**
  1148.      * @return string
  1149.      */
  1150.     public function getTabPosition(): string
  1151.     {
  1152.         return $this->tabPosition ?? 'top';
  1153.     }
  1154.     /**
  1155.      * @param string|null $tabPosition
  1156.      */
  1157.     public function setTabPosition($tabPosition): void
  1158.     {
  1159.         $this->tabPosition $tabPosition;
  1160.     }
  1161.     /**
  1162.      * {@inheritdoc}
  1163.      */
  1164.     public function getParameterTypeDeclaration(): ?string
  1165.     {
  1166.         return '?\\' DataObject\Localizedfield::class;
  1167.     }
  1168.     /**
  1169.      * {@inheritdoc}
  1170.      */
  1171.     public function getReturnTypeDeclaration(): ?string
  1172.     {
  1173.         return '?\\' DataObject\Localizedfield::class;
  1174.     }
  1175.     /**
  1176.      * {@inheritdoc}
  1177.      */
  1178.     public function getPhpdocInputType(): ?string
  1179.     {
  1180.         return '\\'DataObject\Localizedfield::class . '|null';
  1181.     }
  1182.     /**
  1183.      * {@inheritdoc}
  1184.      */
  1185.     public function getPhpdocReturnType(): ?string
  1186.     {
  1187.         return '\\' DataObject\Localizedfield::class . '|null';
  1188.     }
  1189.     /**
  1190.      * {@inheritdoc}
  1191.      */
  1192.     public function normalize($value$params = [])
  1193.     {
  1194.         if ($value instanceof DataObject\Localizedfield) {
  1195.             $items $value->getInternalData();
  1196.             if (is_array($items)) {
  1197.                 $result = [];
  1198.                 foreach ($items as $language => $languageData) {
  1199.                     $languageResult = [];
  1200.                     foreach ($languageData as $elementName => $elementData) {
  1201.                         $fd $this->getFieldDefinition($elementName);
  1202.                         if (!$fd) {
  1203.                             // class definition seems to have changed
  1204.                             Logger::warn('class definition seems to have changed, element name: '.$elementName);
  1205.                             continue;
  1206.                         }
  1207.                         if ($fd instanceof NormalizerInterface) {
  1208.                             $dataForResource $fd->normalize($elementData$params);
  1209.                             $languageResult[$elementName] = $dataForResource;
  1210.                         }
  1211.                     }
  1212.                     $result[$language] = $languageResult;
  1213.                 }
  1214.                 return $result;
  1215.             }
  1216.         }
  1217.         return null;
  1218.     }
  1219.     /**
  1220.      * {@inheritdoc}
  1221.      */
  1222.     public function denormalize($value$params = [])
  1223.     {
  1224.         if (is_array($value)) {
  1225.             $lf = new DataObject\Localizedfield();
  1226.             $lf->setObject($params['object']);
  1227.             $items = [];
  1228.             foreach ($value as $language => $languageData) {
  1229.                 $languageResult = [];
  1230.                 foreach ($languageData as $elementName => $elementData) {
  1231.                     $fd $this->getFieldDefinition($elementName);
  1232.                     if (!$fd) {
  1233.                         // class definition seems to have changed
  1234.                         Logger::warn('class definition seems to have changed, element name: '.$elementName);
  1235.                         continue;
  1236.                     }
  1237.                     if ($fd instanceof NormalizerInterface) {
  1238.                         $dataFromResource $fd->denormalize($elementData$params);
  1239.                         $languageResult[$elementName] = $dataFromResource;
  1240.                     }
  1241.                 }
  1242.                 $items[$language] = $languageResult;
  1243.             }
  1244.             $lf->setItems($items);
  1245.             return $lf;
  1246.         }
  1247.         return null;
  1248.     }
  1249.     /**
  1250.      * @param array $data
  1251.      *
  1252.      * @return static
  1253.      */
  1254.     public static function __set_state($data)
  1255.     {
  1256.         $obj = new static();
  1257.         $obj->setValues($data);
  1258.         $obj->childs $obj->children;  // @phpstan-ignore-line
  1259.         return $obj;
  1260.     }
  1261. }