vendor/pimcore/pimcore/models/DataObject/Service.php line 1683

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;
  15. use DeepCopy\Filter\SetNullFilter;
  16. use DeepCopy\Matcher\PropertyNameMatcher;
  17. use Pimcore\Cache\Runtime;
  18. use Pimcore\DataObject\GridColumnConfig\ConfigElementInterface;
  19. use Pimcore\DataObject\GridColumnConfig\Operator\AbstractOperator;
  20. use Pimcore\DataObject\GridColumnConfig\Service as GridColumnConfigService;
  21. use Pimcore\Db;
  22. use Pimcore\Event\DataObjectEvents;
  23. use Pimcore\Event\Model\DataObjectEvent;
  24. use Pimcore\Localization\LocaleServiceInterface;
  25. use Pimcore\Logger;
  26. use Pimcore\Model;
  27. use Pimcore\Model\DataObject;
  28. use Pimcore\Model\DataObject\ClassDefinition\Data\IdRewriterInterface;
  29. use Pimcore\Model\DataObject\ClassDefinition\Data\LayoutDefinitionEnrichmentInterface;
  30. use Pimcore\Model\Element;
  31. use Pimcore\Model\Element\DirtyIndicatorInterface;
  32. use Pimcore\Tool\Admin as AdminTool;
  33. use Pimcore\Tool\Session;
  34. use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  35. use Symfony\Component\ExpressionLanguage\SyntaxError;
  36. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  37. /**
  38.  * @method \Pimcore\Model\Element\Dao getDao()
  39.  */
  40. class Service extends Model\Element\Service
  41. {
  42.     /**
  43.      * @var array
  44.      */
  45.     protected $_copyRecursiveIds;
  46.     /**
  47.      * @var Model\User|null
  48.      */
  49.     protected $_user;
  50.     /**
  51.      * System fields used by filter conditions
  52.      *
  53.      * @var array
  54.      */
  55.     protected static $systemFields = ['o_path''o_key''o_id''o_published''o_creationDate''o_modificationDate''o_fullpath'];
  56.     /**
  57.      * @param Model\User $user
  58.      */
  59.     public function __construct($user null)
  60.     {
  61.         $this->_user $user;
  62.     }
  63.     /**
  64.      * finds all objects which hold a reference to a specific user
  65.      *
  66.      * @static
  67.      *
  68.      * @param  int $userId
  69.      *
  70.      * @return Concrete[]
  71.      */
  72.     public static function getObjectsReferencingUser($userId)
  73.     {
  74.         $userObjects = [[]];
  75.         $classesList = new ClassDefinition\Listing();
  76.         $classesList->setOrderKey('name');
  77.         $classesList->setOrder('asc');
  78.         $classesToCheck = [];
  79.         foreach ($classesList as $class) {
  80.             $fieldDefinitions $class->getFieldDefinitions();
  81.             $dataKeys = [];
  82.             if (is_array($fieldDefinitions)) {
  83.                 foreach ($fieldDefinitions as $tag) {
  84.                     if ($tag instanceof ClassDefinition\Data\User) {
  85.                         $dataKeys[] = $tag->getName();
  86.                     }
  87.                 }
  88.             }
  89.             if (is_array($dataKeys) && count($dataKeys) > 0) {
  90.                 $classesToCheck[$class->getName()] = $dataKeys;
  91.             }
  92.         }
  93.         foreach ($classesToCheck as $classname => $fields) {
  94.             $listName '\\Pimcore\\Model\\DataObject\\' ucfirst($classname) . '\\Listing';
  95.             $list = new $listName();
  96.             $conditionParts = [];
  97.             foreach ($fields as $field) {
  98.                 $conditionParts[] = $field ' = ?';
  99.             }
  100.             $list->setCondition(implode(' AND '$conditionParts), array_fill(0count($conditionParts), $userId));
  101.             $objects $list->load();
  102.             $userObjects[] = $objects;
  103.         }
  104.         if ($userObjects) {
  105.             $userObjects \array_merge(...$userObjects);
  106.         }
  107.         return $userObjects;
  108.     }
  109.     /**
  110.      * @param AbstractObject $target
  111.      * @param AbstractObject $source
  112.      *
  113.      * @return AbstractObject|void
  114.      */
  115.     public function copyRecursive($target$source)
  116.     {
  117.         // avoid recursion
  118.         if (!$this->_copyRecursiveIds) {
  119.             $this->_copyRecursiveIds = [];
  120.         }
  121.         if (in_array($source->getId(), $this->_copyRecursiveIds)) {
  122.             return;
  123.         }
  124.         $source->getProperties();
  125.         //load all in case of lazy loading fields
  126.         self::loadAllObjectFields($source);
  127.         /** @var Concrete $new */
  128.         $new Element\Service::cloneMe($source);
  129.         $new->setId(null);
  130.         $new->setChildren(null);
  131.         $new->setKey(Element\Service::getSafeCopyName($new->getKey(), $target));
  132.         $new->setParentId($target->getId());
  133.         $new->setUserOwner($this->_user $this->_user->getId() : 0);
  134.         $new->setUserModification($this->_user $this->_user->getId() : 0);
  135.         $new->setDao(null);
  136.         $new->setLocked(false);
  137.         $new->setCreationDate(time());
  138.         if ($new instanceof Concrete) {
  139.             foreach ($new->getClass()->getFieldDefinitions() as $fieldDefinition) {
  140.                 if ($fieldDefinition->getUnique()) {
  141.                     $new->set($fieldDefinition->getName(), null);
  142.                     $new->setPublished(false);
  143.                 }
  144.             }
  145.         }
  146.         $new->save();
  147.         // add to store
  148.         $this->_copyRecursiveIds[] = $new->getId();
  149.         $children $source->getChildren([
  150.             DataObject::OBJECT_TYPE_OBJECT,
  151.             DataObject::OBJECT_TYPE_VARIANT,
  152.             DataObject::OBJECT_TYPE_FOLDER,
  153.         ], true);
  154.         foreach ($children as $child) {
  155.             $this->copyRecursive($new$child);
  156.         }
  157.         $this->updateChildren($target$new);
  158.         // triggers actions after the complete document cloning
  159.         $event = new DataObjectEvent($new, [
  160.             'base_element' => $source// the element used to make a copy
  161.         ]);
  162.         \Pimcore::getEventDispatcher()->dispatch($eventDataObjectEvents::POST_COPY);
  163.         return $new;
  164.     }
  165.     /**
  166.      * @param  AbstractObject $target
  167.      * @param  AbstractObject $source
  168.      *
  169.      * @return AbstractObject copied object
  170.      */
  171.     public function copyAsChild($target$source)
  172.     {
  173.         $isDirtyDetectionDisabled DataObject::isDirtyDetectionDisabled();
  174.         DataObject::setDisableDirtyDetection(true);
  175.         //load properties
  176.         $source->getProperties();
  177.         //load all in case of lazy loading fields
  178.         self::loadAllObjectFields($source);
  179.         /** @var Concrete $new */
  180.         $new Element\Service::cloneMe($source);
  181.         $new->setId(null);
  182.         $new->setChildren(null);
  183.         $new->setKey(Element\Service::getSafeCopyName($new->getKey(), $target));
  184.         $new->setParentId($target->getId());
  185.         $new->setUserOwner($this->_user $this->_user->getId() : 0);
  186.         $new->setUserModification($this->_user $this->_user->getId() : 0);
  187.         $new->setDao(null);
  188.         $new->setLocked(false);
  189.         $new->setCreationDate(time());
  190.         if ($new instanceof Concrete) {
  191.             foreach ($new->getClass()->getFieldDefinitions() as $fieldDefinition) {
  192.                 if ($fieldDefinition->getUnique()) {
  193.                     $new->set($fieldDefinition->getName(), null);
  194.                     $new->setPublished(false);
  195.                 }
  196.             }
  197.         }
  198.         $new->save();
  199.         DataObject::setDisableDirtyDetection($isDirtyDetectionDisabled);
  200.         $this->updateChildren($target$new);
  201.         // triggers actions after the complete object cloning
  202.         $event = new DataObjectEvent($new, [
  203.             'base_element' => $source// the element used to make a copy
  204.         ]);
  205.         \Pimcore::getEventDispatcher()->dispatch($eventDataObjectEvents::POST_COPY);
  206.         return $new;
  207.     }
  208.     /**
  209.      * @param Concrete $target
  210.      * @param Concrete $source
  211.      *
  212.      * @return Concrete
  213.      *
  214.      * @throws \Exception
  215.      */
  216.     public function copyContents($target$source)
  217.     {
  218.         // check if the type is the same
  219.         if (get_class($source) !== get_class($target)) {
  220.             throw new \Exception('Source and target have to be the same type');
  221.         }
  222.         //load all in case of lazy loading fields
  223.         self::loadAllObjectFields($source);
  224.         /**
  225.          * @var Concrete $new
  226.          */
  227.         $new Element\Service::cloneMe($source);
  228.         $new->setChildren($target->getChildren());
  229.         $new->setId($target->getId());
  230.         $new->setPath($target->getRealPath());
  231.         $new->setKey($target->getKey());
  232.         $new->setParentId($target->getParentId());
  233.         $new->setScheduledTasks($source->getScheduledTasks());
  234.         $new->setProperties($source->getProperties());
  235.         $new->setUserModification($this->_user $this->_user->getId() : 0);
  236.         $new->save();
  237.         $target Concrete::getById($new->getId());
  238.         return $target;
  239.     }
  240.     /**
  241.      * @param string $field
  242.      *
  243.      * @return bool
  244.      *
  245.      * @internal
  246.      */
  247.     public static function isHelperGridColumnConfig($field)
  248.     {
  249.         return strpos($field'#') === 0;
  250.     }
  251.     /**
  252.      * Language only user for classification store !!!
  253.      *
  254.      * @param AbstractObject $object
  255.      * @param array|null $fields
  256.      * @param string|null $requestedLanguage
  257.      * @param array $params
  258.      *
  259.      * @return array
  260.      *
  261.      * @internal
  262.      */
  263.     public static function gridObjectData($object$fields null$requestedLanguage null$params = [])
  264.     {
  265.         $data Element\Service::gridElementData($object);
  266.         $csvMode $params['csvMode'] ?? false;
  267.         if ($object instanceof Concrete) {
  268.             $context = ['object' => $object,
  269.                 'purpose' => 'gridview',
  270.                 'language' => $requestedLanguage, ];
  271.             $data['classname'] = $object->getClassName();
  272.             $data['idPath'] = Element\Service::getIdPath($object);
  273.             $data['inheritedFields'] = [];
  274.             $data['permissions'] = $object->getUserPermissions();
  275.             $data['locked'] = $object->isLocked();
  276.             $user AdminTool::getCurrentUser();
  277.             if (is_null($fields)) {
  278.                 $fields array_keys($object->getclass()->getFieldDefinitions());
  279.             }
  280.             $haveHelperDefinition false;
  281.             foreach ($fields as $key) {
  282.                 $brickDescriptor null;
  283.                 $brickKey null;
  284.                 $brickType null;
  285.                 $brickGetter null;
  286.                 $dataKey $key;
  287.                 $keyParts explode('~'$key);
  288.                 $def $object->getClass()->getFieldDefinition($key$context);
  289.                 if (strpos($key'#') === 0) {
  290.                     if (!$haveHelperDefinition) {
  291.                         $helperDefinitions self::getHelperDefinitions();
  292.                         $haveHelperDefinition true;
  293.                     }
  294.                     if (!empty($helperDefinitions[$key])) {
  295.                         $context['fieldname'] = $key;
  296.                         $data[$key] = self::calculateCellValue($object$helperDefinitions$key$context);
  297.                     }
  298.                 } elseif (strpos($key'~') === 0) {
  299.                     $type $keyParts[1];
  300.                     if ($type === 'classificationstore') {
  301.                         $data[$key] = self::getStoreValueForObject($object$key$requestedLanguage);
  302.                     }
  303.                 } elseif (count($keyParts) > 1) {
  304.                     // brick
  305.                     $brickType $keyParts[0];
  306.                     if (strpos($brickType'?') !== false) {
  307.                         $brickDescriptor substr($brickType1);
  308.                         $brickDescriptor json_decode($brickDescriptortrue);
  309.                         $brickType $brickDescriptor['containerKey'];
  310.                     }
  311.                     $brickKey $keyParts[1];
  312.                     $key self::getFieldForBrickType($object->getclass(), $brickType);
  313.                     $brickClass Objectbrick\Definition::getByKey($brickType);
  314.                     $context['outerFieldname'] = $key;
  315.                     if ($brickDescriptor) {
  316.                         $innerContainer $brickDescriptor['innerContainer'] ?? 'localizedfields';
  317.                         /** @var Model\DataObject\ClassDefinition\Data\Localizedfields $localizedFields */
  318.                         $localizedFields $brickClass->getFieldDefinition($innerContainer);
  319.                         $def $localizedFields->getFieldDefinition($brickDescriptor['brickfield']);
  320.                     } elseif ($brickClass instanceof Objectbrick\Definition) {
  321.                         $def $brickClass->getFieldDefinition($brickKey$context);
  322.                     }
  323.                 }
  324.                 if (!empty($key)) {
  325.                     // some of the not editable field require a special response
  326.                     $getter 'get' ucfirst($key);
  327.                     $needLocalizedPermissions false;
  328.                     // if the definition is not set try to get the definition from localized fields
  329.                     if (!$def) {
  330.                         /** @var Model\DataObject\ClassDefinition\Data\Localizedfields|null $locFields */
  331.                         $locFields $object->getClass()->getFieldDefinition('localizedfields');
  332.                         if ($locFields) {
  333.                             $def $locFields->getFieldDefinition($key$context);
  334.                             if ($def) {
  335.                                 $needLocalizedPermissions true;
  336.                             }
  337.                         }
  338.                     }
  339.                     //relation type fields with remote owner do not have a getter
  340.                     if (method_exists($object$getter)) {
  341.                         //system columns must not be inherited
  342.                         if (in_array($keyConcrete::SYSTEM_COLUMN_NAMES)) {
  343.                             $data[$dataKey] = $object->$getter();
  344.                         } else {
  345.                             $valueObject self::getValueForObject($object$key$brickType$brickKey$def$context$brickDescriptor);
  346.                             $data['inheritedFields'][$dataKey] = ['inherited' => $valueObject->objectid != $object->getId(), 'objectid' => $valueObject->objectid];
  347.                             if ($csvMode || method_exists($def'getDataForGrid')) {
  348.                                 if ($brickKey) {
  349.                                     $context['containerType'] = 'objectbrick';
  350.                                     $context['containerKey'] = $brickType;
  351.                                     $context['outerFieldname'] = $key;
  352.                                 }
  353.                                 $params array_merge($params, ['context' => $context]);
  354.                                 if (!isset($params['purpose'])) {
  355.                                     $params['purpose'] = 'gridview';
  356.                                 }
  357.                                 if ($csvMode) {
  358.                                     $getterParams = ['language' => $requestedLanguage];
  359.                                     $tempData $def->getForCsvExport($object$getterParams);
  360.                                 } elseif (method_exists($def'getDataForGrid')) {
  361.                                     $tempData $def->getDataForGrid($valueObject->value$object$params);
  362.                                 } else {
  363.                                     continue;
  364.                                 }
  365.                                 if ($def instanceof ClassDefinition\Data\Localizedfields) {
  366.                                     $needLocalizedPermissions true;
  367.                                     foreach ($tempData as $tempKey => $tempValue) {
  368.                                         $data[$tempKey] = $tempValue;
  369.                                     }
  370.                                 } else {
  371.                                     $data[$dataKey] = $tempData;
  372.                                     if ($def instanceof Model\DataObject\ClassDefinition\Data\Select && $def->getOptionsProviderClass()) {
  373.                                         $data[$dataKey '%options'] = $def->getOptions();
  374.                                     }
  375.                                 }
  376.                             } else {
  377.                                 $data[$dataKey] = $valueObject->value;
  378.                             }
  379.                         }
  380.                     }
  381.                     // because the key for the classification store has not a direct getter, you have to check separately if the data is inheritable
  382.                     if (strpos($key'~') === && empty($data[$key])) {
  383.                         $type $keyParts[1];
  384.                         if ($type === 'classificationstore') {
  385.                             $parent self::hasInheritableParentObject($object);
  386.                             if (!empty($parent)) {
  387.                                 $data[$dataKey] = self::getStoreValueForObject($parent$key$requestedLanguage);
  388.                                 $data['inheritedFields'][$dataKey] = ['inherited' => $parent->getId() != $object->getId(), 'objectid' => $parent->getId()];
  389.                             }
  390.                         }
  391.                     }
  392.                     if ($needLocalizedPermissions) {
  393.                         if (!$user->isAdmin()) {
  394.                             $locale \Pimcore::getContainer()->get(LocaleServiceInterface::class)->findLocale();
  395.                             $permissionTypes = ['View''Edit'];
  396.                             foreach ($permissionTypes as $permissionType) {
  397.                                 //TODO, this needs refactoring! Ideally, call it only once!
  398.                                 $languagesAllowed self::getLanguagePermissions($object$user'l' $permissionType);
  399.                                 if ($languagesAllowed) {
  400.                                     $languagesAllowed array_keys($languagesAllowed);
  401.                                     if (!in_array($locale$languagesAllowed)) {
  402.                                         $data['metadata']['permission'][$key]['no' $permissionType] = 1;
  403.                                         if ($permissionType === 'View') {
  404.                                             $data[$key] = null;
  405.                                         }
  406.                                     }
  407.                                 }
  408.                             }
  409.                         }
  410.                     }
  411.                 }
  412.             }
  413.         }
  414.         return $data;
  415.     }
  416.     /**
  417.      * @param array $helperDefinitions
  418.      * @param string $key
  419.      *
  420.      * @return string[]|null
  421.      *
  422.      * @internal
  423.      */
  424.     public static function expandGridColumnForExport($helperDefinitions$key)
  425.     {
  426.         $config self::getConfigForHelperDefinition($helperDefinitions$key);
  427.         if ($config instanceof AbstractOperator && $config->expandLocales()) {
  428.             return $config->getValidLanguages();
  429.         }
  430.         return null;
  431.     }
  432.     /**
  433.      * @param array $helperDefinitions
  434.      * @param string $key
  435.      * @param array $context
  436.      *
  437.      * @return mixed|null|ConfigElementInterface|ConfigElementInterface[]
  438.      *
  439.      * @internal
  440.      */
  441.     public static function getConfigForHelperDefinition($helperDefinitions$key$context = [])
  442.     {
  443.         $cacheKey 'gridcolumn_config_' $key;
  444.         if (isset($context['language'])) {
  445.             $cacheKey .= '_' $context['language'];
  446.         }
  447.         if (Runtime::isRegistered($cacheKey)) {
  448.             $config Runtime::get($cacheKey);
  449.         } else {
  450.             $definition $helperDefinitions[$key];
  451.             $attributes json_decode(json_encode($definition->attributes));
  452.             // TODO refactor how the service is accessed into something non-static and inject the service there
  453.             $service \Pimcore::getContainer()->get(GridColumnConfigService::class);
  454.             $config $service->buildOutputDataConfig([$attributes], $context);
  455.             if (!$config) {
  456.                 return null;
  457.             }
  458.             $config $config[0];
  459.             Runtime::save($config$cacheKey);
  460.         }
  461.         return $config;
  462.     }
  463.     /**
  464.      * @param AbstractObject $object
  465.      * @param array $helperDefinitions
  466.      * @param string $key
  467.      * @param array $context
  468.      *
  469.      * @return \stdClass|array|null
  470.      */
  471.     public static function calculateCellValue($object$helperDefinitions$key$context = [])
  472.     {
  473.         $config = static::getConfigForHelperDefinition($helperDefinitions$key$context);
  474.         if (!$config) {
  475.             return null;
  476.         }
  477.         $inheritanceEnabled AbstractObject::getGetInheritedValues();
  478.         AbstractObject::setGetInheritedValues(true);
  479.         $result $config->getLabeledValue($object);
  480.         if (isset($result->value)) {
  481.             $result $result->value;
  482.             if (!empty($config->renderer)) {
  483.                 $classname 'Pimcore\\Model\\DataObject\\ClassDefinition\\Data\\' ucfirst($config->renderer);
  484.                 /** @var Model\DataObject\ClassDefinition\Data $rendererImpl */
  485.                 $rendererImpl = new $classname();
  486.                 if (method_exists($rendererImpl'getDataForGrid')) {
  487.                     $result $rendererImpl->getDataForGrid($result$object, []);
  488.                 }
  489.             }
  490.             return $result;
  491.         }
  492.         AbstractObject::setGetInheritedValues($inheritanceEnabled);
  493.         return null;
  494.     }
  495.     /**
  496.      * @return mixed
  497.      */
  498.     public static function getHelperDefinitions()
  499.     {
  500.         return Session::useSession(function (AttributeBagInterface $session) {
  501.             $existingColumns $session->get('helpercolumns', []);
  502.             return $existingColumns;
  503.         }, 'pimcore_gridconfig');
  504.     }
  505.     /**
  506.      * @param AbstractObject|Model\DataObject\Fieldcollection\Data\AbstractData|Model\DataObject\Objectbrick\Data\AbstractData $object
  507.      * @param Model\User $user
  508.      * @param string $type
  509.      *
  510.      * @return array|null
  511.      */
  512.     public static function getLanguagePermissions($object$user$type)
  513.     {
  514.         $languageAllowed null;
  515.         $object $object instanceof Model\DataObject\Fieldcollection\Data\AbstractData ||
  516.         $object instanceof  Model\DataObject\Objectbrick\Data\AbstractData ?
  517.             $object->getObject() : $object;
  518.         $permission $object->getPermissions($type$user);
  519.         if ($permission !== null) {
  520.             // backwards compatibility. If all entries are null, then the workspace rule was set up with
  521.             // an older pimcore
  522.             $permission $permission[$type];
  523.             if ($permission) {
  524.                 $permission explode(','$permission);
  525.                 if ($languageAllowed === null) {
  526.                     $languageAllowed = [];
  527.                 }
  528.                 foreach ($permission as $language) {
  529.                     $languageAllowed[$language] = 1;
  530.                 }
  531.             }
  532.         }
  533.         return $languageAllowed;
  534.     }
  535.     /**
  536.      * @param string $classId
  537.      * @param array $permissionSet
  538.      *
  539.      * @return array|null
  540.      */
  541.     public static function getLayoutPermissions($classId$permissionSet)
  542.     {
  543.         $layoutPermissions null;
  544.         if ($permissionSet !== null) {
  545.             // backwards compatibility. If all entries are null, then the workspace rule was set up with
  546.             // an older pimcore
  547.             $permission $permissionSet['layouts'];
  548.             if ($permission) {
  549.                 $permission explode(','$permission);
  550.                 if ($layoutPermissions === null) {
  551.                     $layoutPermissions = [];
  552.                 }
  553.                 foreach ($permission as $p) {
  554.                     if (preg_match(sprintf('#^(%s)_(.*)#'$classId), $p$setting)) {
  555.                         $l $setting[2];
  556.                         $layoutPermissions[$l] = $l;
  557.                     }
  558.                 }
  559.             }
  560.         }
  561.         return $layoutPermissions;
  562.     }
  563.     /**
  564.      * @param ClassDefinition $class
  565.      * @param string $bricktype
  566.      *
  567.      * @return int|null|string
  568.      */
  569.     public static function getFieldForBrickType(ClassDefinition $class$bricktype)
  570.     {
  571.         $fieldDefinitions $class->getFieldDefinitions();
  572.         foreach ($fieldDefinitions as $key => $fd) {
  573.             if ($fd instanceof ClassDefinition\Data\Objectbricks && in_array($bricktype$fd->getAllowedTypes())) {
  574.                 return $key;
  575.             }
  576.         }
  577.         return null;
  578.     }
  579.     /**
  580.      * gets value for given object and getter, including inherited values
  581.      *
  582.      * @static
  583.      *
  584.      * @param Concrete $object
  585.      * @param string $key
  586.      * @param string|null $brickType
  587.      * @param string|null $brickKey
  588.      * @param ClassDefinition\Data|null $fieldDefinition
  589.      * @param array $context
  590.      * @param array|null $brickDescriptor
  591.      *
  592.      * @return \stdClass, value and objectid where the value comes from
  593.      */
  594.     private static function getValueForObject($object$key$brickType null$brickKey null$fieldDefinition null$context = [], $brickDescriptor null)
  595.     {
  596.         $getter 'get' ucfirst($key);
  597.         $value $object->$getter();
  598.         if (!empty($value) && !empty($brickType)) {
  599.             $getBrickType 'get' ucfirst($brickType);
  600.             $value $value->$getBrickType();
  601.             if (!empty($value) && !empty($brickKey)) {
  602.                 if ($brickDescriptor) {
  603.                     $innerContainer $brickDescriptor['innerContainer'] ?? 'localizedfields';
  604.                     $localizedFields $value->{'get' ucfirst($innerContainer)}();
  605.                     $brickDefinition Model\DataObject\Objectbrick\Definition::getByKey($brickType);
  606.                     /** @var Model\DataObject\ClassDefinition\Data\Localizedfields $fieldDefinitionLocalizedFields */
  607.                     $fieldDefinitionLocalizedFields $brickDefinition->getFieldDefinition('localizedfields');
  608.                     $fieldDefinition $fieldDefinitionLocalizedFields->getFieldDefinition($brickKey);
  609.                     $value $localizedFields->getLocalizedValue($brickDescriptor['brickfield']);
  610.                 } else {
  611.                     $brickFieldGetter 'get' ucfirst($brickKey);
  612.                     $value $value->$brickFieldGetter();
  613.                 }
  614.             }
  615.         }
  616.         if (!$fieldDefinition) {
  617.             $fieldDefinition $object->getClass()->getFieldDefinition($key$context);
  618.         }
  619.         if (!empty($brickType) && !empty($brickKey) && !$brickDescriptor) {
  620.             $brickClass Objectbrick\Definition::getByKey($brickType);
  621.             $context = ['object' => $object'outerFieldname' => $key];
  622.             $fieldDefinition $brickClass->getFieldDefinition($brickKey$context);
  623.         }
  624.         if ($fieldDefinition->isEmpty($value)) {
  625.             $parent self::hasInheritableParentObject($object);
  626.             if (!empty($parent)) {
  627.                 return self::getValueForObject($parent$key$brickType$brickKey$fieldDefinition$context$brickDescriptor);
  628.             }
  629.         }
  630.         $result = new \stdClass();
  631.         $result->value $value;
  632.         $result->objectid $object->getId();
  633.         return $result;
  634.     }
  635.     /**
  636.      * gets store value for given object and key
  637.      *
  638.      * @static
  639.      *
  640.      * @param Concrete $object
  641.      * @param string $key
  642.      * @param string|null $requestedLanguage
  643.      *
  644.      * @return string|null
  645.      */
  646.     private static function getStoreValueForObject($object$key$requestedLanguage)
  647.     {
  648.         $keyParts explode('~'$key);
  649.         if (strpos($key'~') === 0) {
  650.             $type $keyParts[1];
  651.             if ($type === 'classificationstore') {
  652.                 $field $keyParts[2];
  653.                 $groupKeyId explode('-'$keyParts[3]);
  654.                 $groupId $groupKeyId[0];
  655.                 $keyid $groupKeyId[1];
  656.                 $getter 'get' ucfirst($field);
  657.                 if (method_exists($object$getter)) {
  658.                     /** @var Classificationstore $classificationStoreData */
  659.                     $classificationStoreData $object->$getter();
  660.                     /** @var Model\DataObject\ClassDefinition\Data\Classificationstore $csFieldDefinition */
  661.                     $csFieldDefinition $object->getClass()->getFieldDefinition($field);
  662.                     $csLanguage $requestedLanguage;
  663.                     if (!$csFieldDefinition->isLocalized()) {
  664.                         $csLanguage 'default';
  665.                     }
  666.                     $fielddata $classificationStoreData->getLocalizedKeyValue($groupId$keyid$csLanguagetruetrue);
  667.                     $keyConfig Model\DataObject\Classificationstore\KeyConfig::getById($keyid);
  668.                     $type $keyConfig->getType();
  669.                     $definition json_decode($keyConfig->getDefinition());
  670.                     $definition \Pimcore\Model\DataObject\Classificationstore\Service::getFieldDefinitionFromJson($definition$type);
  671.                     if (method_exists($definition'getDataForGrid')) {
  672.                         $fielddata $definition->getDataForGrid($fielddata$object);
  673.                     }
  674.                     return $fielddata;
  675.                 }
  676.             }
  677.         }
  678.         return null;
  679.     }
  680.     /**
  681.      * @param Concrete $object
  682.      *
  683.      * @return AbstractObject|null
  684.      */
  685.     public static function hasInheritableParentObject(Concrete $object)
  686.     {
  687.         if ($object->getClass()->getAllowInherit()) {
  688.             return $object->getNextParentForInheritance();
  689.         }
  690.         return null;
  691.     }
  692.     /**
  693.      * call the getters of each object field, in case some of the are lazy loading and we need the data to be loaded
  694.      *
  695.      * @static
  696.      *
  697.      * @param AbstractObject $object
  698.      */
  699.     public static function loadAllObjectFields($object)
  700.     {
  701.         $object->getProperties();
  702.         if ($object instanceof Concrete) {
  703.             //load all in case of lazy loading fields
  704.             $fd $object->getClass()->getFieldDefinitions();
  705.             foreach ($fd as $def) {
  706.                 $getter 'get' ucfirst($def->getName());
  707.                 if (method_exists($object$getter)) {
  708.                     $value $object->$getter();
  709.                     if ($value instanceof Localizedfield) {
  710.                         $value->loadLazyData();
  711.                     } elseif ($value instanceof Objectbrick) {
  712.                         $value->loadLazyData();
  713.                     } elseif ($value instanceof Fieldcollection) {
  714.                         $value->loadLazyData();
  715.                     }
  716.                 }
  717.             }
  718.         }
  719.     }
  720.     /**
  721.      * @static
  722.      *
  723.      * @param Concrete|string $object
  724.      * @param string|ClassDefinition\Data\Select|ClassDefinition\Data\Multiselect $definition
  725.      *
  726.      * @return array
  727.      */
  728.     public static function getOptionsForSelectField($object$definition)
  729.     {
  730.         $class null;
  731.         $options = [];
  732.         if (is_object($object) && method_exists($object'getClass')) {
  733.             $class $object->getClass();
  734.         } elseif (is_string($object)) {
  735.             $object '\\' ltrim($object'\\');
  736.             $object = new $object();
  737.             $class $object->getClass();
  738.         }
  739.         if ($class) {
  740.             if (is_string($definition)) {
  741.                 $definition $class->getFieldDefinition($definition);
  742.             }
  743.             if ($definition instanceof ClassDefinition\Data\Select || $definition instanceof ClassDefinition\Data\Multiselect) {
  744.                 $optionsProvider DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
  745.                     $definition->getOptionsProviderClass(),
  746.                     DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT
  747.                 );
  748.                 if ($optionsProvider instanceof DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface) {
  749.                     $_options $optionsProvider->getOptions(['fieldname' => $definition->getName()], $definition);
  750.                 } else {
  751.                     $_options $definition->getOptions();
  752.                 }
  753.                 foreach ($_options as $option) {
  754.                     $options[$option['value']] = $option['key'];
  755.                 }
  756.             }
  757.         }
  758.         return $options;
  759.     }
  760.     /**
  761.      * alias of getOptionsForMultiSelectField
  762.      *
  763.      * @param Concrete|string $object
  764.      * @param string|ClassDefinition\Data\Select|ClassDefinition\Data\Multiselect $fieldname
  765.      *
  766.      * @return array
  767.      */
  768.     public static function getOptionsForMultiSelectField($object$fieldname)
  769.     {
  770.         return self::getOptionsForSelectField($object$fieldname);
  771.     }
  772.     /**
  773.      * @static
  774.      *
  775.      * @param string $path
  776.      * @param string|null $type
  777.      *
  778.      * @return bool
  779.      */
  780.     public static function pathExists($path$type null)
  781.     {
  782.         if (!$path) {
  783.             return false;
  784.         }
  785.         $path Element\Service::correctPath($path);
  786.         try {
  787.             $object = new DataObject();
  788.             $pathElements explode('/'$path);
  789.             $keyIdx count($pathElements) - 1;
  790.             $key $pathElements[$keyIdx];
  791.             $validKey Element\Service::getValidKey($key'object');
  792.             unset($pathElements[$keyIdx]);
  793.             $pathOnly implode('/'$pathElements);
  794.             if ($validKey == $key && self::isValidPath($pathOnly'object')) {
  795.                 $object->getDao()->getByPath($path);
  796.                 return true;
  797.             }
  798.         } catch (\Exception $e) {
  799.         }
  800.         return false;
  801.     }
  802.     /**
  803.      * Rewrites id from source to target, $rewriteConfig contains
  804.      * array(
  805.      *  "document" => array(
  806.      *      SOURCE_ID => TARGET_ID,
  807.      *      SOURCE_ID => TARGET_ID
  808.      *  ),
  809.      *  "object" => array(...),
  810.      *  "asset" => array(...)
  811.      * )
  812.      *
  813.      * @param AbstractObject $object
  814.      * @param array $rewriteConfig
  815.      * @param array $params
  816.      *
  817.      * @return AbstractObject
  818.      */
  819.     public static function rewriteIds($object$rewriteConfig$params = [])
  820.     {
  821.         // rewriting elements only for snippets and pages
  822.         if ($object instanceof Concrete) {
  823.             $fields $object->getClass()->getFieldDefinitions();
  824.             foreach ($fields as $field) {
  825.                 //TODO Pimcore 11: remove method_exists BC layer
  826.                 if ($field instanceof IdRewriterInterface || method_exists($field'rewriteIds')) {
  827.                     if (!$field instanceof IdRewriterInterface) {
  828.                         trigger_deprecation('pimcore/pimcore''10.1',
  829.                             sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  830.                             'Implement the %s interface instead.'IdRewriterInterface::class));
  831.                     }
  832.                     $setter 'set' ucfirst($field->getName());
  833.                     if (method_exists($object$setter)) { // check for non-owner-objects
  834.                         $object->$setter($field->rewriteIds($object$rewriteConfig));
  835.                     }
  836.                 }
  837.             }
  838.         }
  839.         // rewriting properties
  840.         $properties $object->getProperties();
  841.         foreach ($properties as &$property) {
  842.             $property->rewriteIds($rewriteConfig);
  843.         }
  844.         $object->setProperties($properties);
  845.         return $object;
  846.     }
  847.     /**
  848.      * @param Concrete $object
  849.      *
  850.      * @return DataObject\ClassDefinition\CustomLayout[]
  851.      */
  852.     public static function getValidLayouts(Concrete $object)
  853.     {
  854.         $user AdminTool::getCurrentUser();
  855.         $resultList = [];
  856.         $isMasterAllowed $user->getAdmin();
  857.         $permissionSet $object->getPermissions('layouts'$user);
  858.         $layoutPermissions self::getLayoutPermissions($object->getClassId(), $permissionSet);
  859.         if (!$layoutPermissions || isset($layoutPermissions[0])) {
  860.             $isMasterAllowed true;
  861.         }
  862.         if ($user->getAdmin()) {
  863.             $superLayout = new ClassDefinition\CustomLayout();
  864.             $superLayout->setId(-1);
  865.             $superLayout->setName('Master (Admin Mode)');
  866.             $resultList[-1] = $superLayout;
  867.         }
  868.         if ($isMasterAllowed) {
  869.             $master = new ClassDefinition\CustomLayout();
  870.             $master->setId(0);
  871.             $master->setName('Master');
  872.             $resultList[0] = $master;
  873.         }
  874.         $classId $object->getClassId();
  875.         $list = new ClassDefinition\CustomLayout\Listing();
  876.         $list->setOrderKey('name');
  877.         $condition 'classId = ' $list->quote($classId);
  878.         if (is_array($layoutPermissions) && count($layoutPermissions)) {
  879.             $layoutIds array_values($layoutPermissions);
  880.             $condition .= ' AND id IN (' implode(','array_map([$list'quote'], $layoutIds)) . ')';
  881.         }
  882.         $list->setCondition($condition);
  883.         $list $list->load();
  884.         if ((!count($resultList) && !count($list)) || (count($resultList) == && !count($list))) {
  885.             return [];
  886.         }
  887.         foreach ($list as $customLayout) {
  888.             if ($customLayout instanceof ClassDefinition\CustomLayout) {
  889.                 $resultList[$customLayout->getId()] = $customLayout;
  890.             }
  891.         }
  892.         return $resultList;
  893.     }
  894.     /**
  895.      * Returns the fields of a datatype container (e.g. block or localized fields)
  896.      *
  897.      * @param ClassDefinition\Data|Model\DataObject\ClassDefinition\Layout $layout
  898.      * @param string $targetClass
  899.      * @param ClassDefinition\Data[] $targetList
  900.      * @param bool $insideDataType
  901.      *
  902.      * @return ClassDefinition\Data[]
  903.      */
  904.     public static function extractFieldDefinitions($layout$targetClass$targetList$insideDataType)
  905.     {
  906.         if ($insideDataType && $layout instanceof ClassDefinition\Data && !is_a($layout$targetClass)) {
  907.             $targetList[$layout->getName()] = $layout;
  908.         }
  909.         if (method_exists($layout'getChildren')) {
  910.             $children $layout->getChildren();
  911.             $insideDataType |= is_a($layout$targetClass);
  912.             if (is_array($children)) {
  913.                 foreach ($children as $child) {
  914.                     $targetList self::extractFieldDefinitions($child$targetClass$targetList$insideDataType);
  915.                 }
  916.             }
  917.         }
  918.         return $targetList;
  919.     }
  920.     /** Calculates the super layout definition for the given object.
  921.      * @param Concrete $object
  922.      *
  923.      * @return mixed
  924.      */
  925.     public static function getSuperLayoutDefinition(Concrete $object)
  926.     {
  927.         $masterLayout $object->getClass()->getLayoutDefinitions();
  928.         $superLayout unserialize(serialize($masterLayout));
  929.         self::createSuperLayout($superLayout);
  930.         return $superLayout;
  931.     }
  932.     /**
  933.      * @param ClassDefinition\Data|Model\DataObject\ClassDefinition\Layout $layout
  934.      */
  935.     public static function createSuperLayout($layout)
  936.     {
  937.         if ($layout instanceof ClassDefinition\Data) {
  938.             $layout->setInvisible(false);
  939.             $layout->setNoteditable(false);
  940.         }
  941.         if ($layout instanceof Model\DataObject\ClassDefinition\Data\Fieldcollections) {
  942.             $layout->setDisallowAddRemove(false);
  943.             $layout->setDisallowReorder(false);
  944.         }
  945.         if (method_exists($layout'getChildren')) {
  946.             $children $layout->getChildren();
  947.             if (is_array($children)) {
  948.                 foreach ($children as $child) {
  949.                     self::createSuperLayout($child);
  950.                 }
  951.             }
  952.         }
  953.     }
  954.     /**
  955.      * @param ClassDefinition\Data[] $masterDefinition
  956.      * @param ClassDefinition\Data|ClassDefinition\Layout|null $layout
  957.      *
  958.      * @return bool
  959.      */
  960.     private static function synchronizeCustomLayoutFieldWithMaster($masterDefinition, &$layout)
  961.     {
  962.         if (is_null($layout)) {
  963.             return true;
  964.         }
  965.         if ($layout instanceof ClassDefinition\Data) {
  966.             $fieldname $layout->name;
  967.             if (empty($masterDefinition[$fieldname])) {
  968.                 return false;
  969.             }
  970.             if ($layout->getFieldtype() !== $masterDefinition[$fieldname]->getFieldType()) {
  971.                 $layout->adoptMasterDefinition($masterDefinition[$fieldname]);
  972.             } else {
  973.                 $layout->synchronizeWithMasterDefinition($masterDefinition[$fieldname]);
  974.             }
  975.         }
  976.         if (method_exists($layout'getChildren')) {
  977.             $children $layout->getChildren();
  978.             if (is_array($children)) {
  979.                 $count count($children);
  980.                 for ($i $count 1$i >= 0$i--) {
  981.                     $child $children[$i];
  982.                     if (!self::synchronizeCustomLayoutFieldWithMaster($masterDefinition$child)) {
  983.                         unset($children[$i]);
  984.                     }
  985.                     $layout->setChildren($children);
  986.                 }
  987.             }
  988.         }
  989.         return true;
  990.     }
  991.     /** Synchronizes a custom layout with its master layout
  992.      * @param ClassDefinition\CustomLayout $customLayout
  993.      */
  994.     public static function synchronizeCustomLayout(ClassDefinition\CustomLayout $customLayout)
  995.     {
  996.         $classId $customLayout->getClassId();
  997.         $class ClassDefinition::getById($classId);
  998.         if ($class && ($class->getModificationDate() > $customLayout->getModificationDate())) {
  999.             $masterDefinition $class->getFieldDefinitions();
  1000.             $customLayoutDefinition $customLayout->getLayoutDefinitions();
  1001.             foreach (['Localizedfields''Block'] as $dataType) {
  1002.                 $targetList self::extractFieldDefinitions($class->getLayoutDefinitions(), '\Pimcore\Model\DataObject\ClassDefinition\Data\\' $dataType, [], false);
  1003.                 $masterDefinition array_merge($masterDefinition$targetList);
  1004.             }
  1005.             self::synchronizeCustomLayoutFieldWithMaster($masterDefinition$customLayoutDefinition);
  1006.             $customLayout->save();
  1007.         }
  1008.     }
  1009.     /**
  1010.      * @param string $classId
  1011.      * @param int $objectId
  1012.      *
  1013.      * @return array|null
  1014.      *
  1015.      * @internal
  1016.      */
  1017.     public static function getCustomGridFieldDefinitions($classId$objectId)
  1018.     {
  1019.         $object DataObject::getById($objectId);
  1020.         $class ClassDefinition::getById($classId);
  1021.         $masterFieldDefinition $class->getFieldDefinitions();
  1022.         if (!$object) {
  1023.             return null;
  1024.         }
  1025.         $user AdminTool::getCurrentUser();
  1026.         if ($user->isAdmin()) {
  1027.             return null;
  1028.         }
  1029.         $permissionList = [];
  1030.         $parentPermissionSet $object->getPermissions(null$usertrue);
  1031.         if ($parentPermissionSet) {
  1032.             $permissionList[] = $parentPermissionSet;
  1033.         }
  1034.         $childPermissions $object->getChildPermissions(null$user);
  1035.         $permissionList array_merge($permissionList$childPermissions);
  1036.         $layoutDefinitions = [];
  1037.         foreach ($permissionList as $permissionSet) {
  1038.             $allowedLayoutIds self::getLayoutPermissions($classId$permissionSet);
  1039.             if (is_array($allowedLayoutIds)) {
  1040.                 foreach ($allowedLayoutIds as $allowedLayoutId) {
  1041.                     if ($allowedLayoutId) {
  1042.                         if (!isset($layoutDefinitions[$allowedLayoutId])) {
  1043.                             $customLayout ClassDefinition\CustomLayout::getById($allowedLayoutId);
  1044.                             if (!$customLayout) {
  1045.                                 continue;
  1046.                             }
  1047.                             $layoutDefinitions[$allowedLayoutId] = $customLayout;
  1048.                         }
  1049.                     }
  1050.                 }
  1051.             }
  1052.         }
  1053.         $mergedFieldDefinition self::cloneDefinition($masterFieldDefinition);
  1054.         if (count($layoutDefinitions)) {
  1055.             foreach ($mergedFieldDefinition as $key => $def) {
  1056.                 if ($def instanceof ClassDefinition\Data\Localizedfields) {
  1057.                     $mergedLocalizedFieldDefinitions $mergedFieldDefinition[$key]->getFieldDefinitions();
  1058.                     foreach ($mergedLocalizedFieldDefinitions as $locKey => $locValue) {
  1059.                         $mergedLocalizedFieldDefinitions[$locKey]->setInvisible(false);
  1060.                         $mergedLocalizedFieldDefinitions[$locKey]->setNotEditable(false);
  1061.                     }
  1062.                     $mergedFieldDefinition[$key]->setChildren($mergedLocalizedFieldDefinitions);
  1063.                 } else {
  1064.                     $mergedFieldDefinition[$key]->setInvisible(false);
  1065.                     $mergedFieldDefinition[$key]->setNotEditable(false);
  1066.                 }
  1067.             }
  1068.         }
  1069.         foreach ($layoutDefinitions as $customLayoutDefinition) {
  1070.             $layoutDefinitions $customLayoutDefinition->getLayoutDefinitions();
  1071.             $dummyClass = new ClassDefinition();
  1072.             $dummyClass->setLayoutDefinitions($layoutDefinitions);
  1073.             $customFieldDefinitions $dummyClass->getFieldDefinitions();
  1074.             foreach ($mergedFieldDefinition as $key => $value) {
  1075.                 if (empty($customFieldDefinitions[$key])) {
  1076.                     unset($mergedFieldDefinition[$key]);
  1077.                 }
  1078.             }
  1079.             foreach ($customFieldDefinitions as $key => $def) {
  1080.                 if ($def instanceof ClassDefinition\Data\Localizedfields) {
  1081.                     if (!$mergedFieldDefinition[$key]) {
  1082.                         continue;
  1083.                     }
  1084.                     $customLocalizedFieldDefinitions $def->getFieldDefinitions();
  1085.                     $mergedLocalizedFieldDefinitions $mergedFieldDefinition[$key]->getFieldDefinitions();
  1086.                     foreach ($mergedLocalizedFieldDefinitions as $locKey => $locValue) {
  1087.                         self::mergeFieldDefinition($mergedLocalizedFieldDefinitions$customLocalizedFieldDefinitions$locKey);
  1088.                     }
  1089.                     $mergedFieldDefinition[$key]->setChildren($mergedLocalizedFieldDefinitions);
  1090.                 } else {
  1091.                     self::mergeFieldDefinition($mergedFieldDefinition$customFieldDefinitions$key);
  1092.                 }
  1093.             }
  1094.         }
  1095.         return $mergedFieldDefinition;
  1096.     }
  1097.     /**
  1098.      * @param mixed $definition
  1099.      *
  1100.      * @return array
  1101.      */
  1102.     public static function cloneDefinition($definition)
  1103.     {
  1104.         $deepCopy = new \DeepCopy\DeepCopy();
  1105.         $deepCopy->addFilter(new SetNullFilter(), new PropertyNameMatcher('fieldDefinitionsCache'));
  1106.         $theCopy $deepCopy->copy($definition);
  1107.         return $theCopy;
  1108.     }
  1109.     /**
  1110.      * @param array $mergedFieldDefinition
  1111.      * @param array $customFieldDefinitions
  1112.      * @param string $key
  1113.      */
  1114.     private static function mergeFieldDefinition(&$mergedFieldDefinition, &$customFieldDefinitions$key)
  1115.     {
  1116.         if (!$customFieldDefinitions[$key]) {
  1117.             unset($mergedFieldDefinition[$key]);
  1118.         } elseif (isset($mergedFieldDefinition[$key])) {
  1119.             $def $customFieldDefinitions[$key];
  1120.             if ($def->getNotEditable()) {
  1121.                 $mergedFieldDefinition[$key]->setNotEditable(true);
  1122.             }
  1123.             if ($def->getInvisible()) {
  1124.                 if ($mergedFieldDefinition[$key] instanceof ClassDefinition\Data\Objectbricks) {
  1125.                     unset($mergedFieldDefinition[$key]);
  1126.                     return;
  1127.                 }
  1128.                 $mergedFieldDefinition[$key]->setInvisible(true);
  1129.             }
  1130.             if ($def->title) {
  1131.                 $mergedFieldDefinition[$key]->setTitle($def->title);
  1132.             }
  1133.         }
  1134.     }
  1135.     /**
  1136.      * @param ClassDefinition\Data|ClassDefinition\Layout $layout
  1137.      * @param ClassDefinition\Data[] $fieldDefinitions
  1138.      *
  1139.      * @return bool
  1140.      */
  1141.     private static function doFilterCustomGridFieldDefinitions(&$layout$fieldDefinitions)
  1142.     {
  1143.         if ($layout instanceof ClassDefinition\Data) {
  1144.             $name $layout->getName();
  1145.             if (empty($fieldDefinitions[$name]) || $fieldDefinitions[$name]->getInvisible()) {
  1146.                 return false;
  1147.             }
  1148.             $layout->setNoteditable($layout->getNoteditable() | $fieldDefinitions[$name]->getNoteditable());
  1149.         }
  1150.         if (method_exists($layout'getChildren')) {
  1151.             $children $layout->getChildren();
  1152.             if (is_array($children)) {
  1153.                 $count count($children);
  1154.                 for ($i $count 1$i >= 0$i--) {
  1155.                     $child $children[$i];
  1156.                     if (!self::doFilterCustomGridFieldDefinitions($child$fieldDefinitions)) {
  1157.                         unset($children[$i]);
  1158.                     }
  1159.                 }
  1160.                 $layout->setChildren(array_values($children));
  1161.             }
  1162.         }
  1163.         return true;
  1164.     }
  1165.     /**  Determines the custom layout definition (if necessary) for the given class
  1166.      * @param ClassDefinition $class
  1167.      * @param int $objectId
  1168.      *
  1169.      * @return array layout
  1170.      *
  1171.      * @internal
  1172.      */
  1173.     public static function getCustomLayoutDefinitionForGridColumnConfig(ClassDefinition $class$objectId)
  1174.     {
  1175.         $layoutDefinitions $class->getLayoutDefinitions();
  1176.         $result = [
  1177.             'layoutDefinition' => $layoutDefinitions,
  1178.         ];
  1179.         if (!$objectId) {
  1180.             return $result;
  1181.         }
  1182.         $user AdminTool::getCurrentUser();
  1183.         if ($user->isAdmin()) {
  1184.             return $result;
  1185.         }
  1186.         $mergedFieldDefinition self::getCustomGridFieldDefinitions($class->getId(), $objectId);
  1187.         if (is_array($mergedFieldDefinition)) {
  1188.             if (isset($mergedFieldDefinition['localizedfields'])) {
  1189.                 $childs $mergedFieldDefinition['localizedfields']->getFieldDefinitions();
  1190.                 if (is_array($childs)) {
  1191.                     foreach ($childs as $locKey => $locValue) {
  1192.                         $mergedFieldDefinition[$locKey] = $locValue;
  1193.                     }
  1194.                 }
  1195.             }
  1196.             self::doFilterCustomGridFieldDefinitions($layoutDefinitions$mergedFieldDefinition);
  1197.             $result['layoutDefinition'] = $layoutDefinitions;
  1198.             $result['fieldDefinition'] = $mergedFieldDefinition;
  1199.         }
  1200.         return $result;
  1201.     }
  1202.     /**
  1203.      * @param AbstractObject $item
  1204.      * @param int $nr
  1205.      *
  1206.      * @return string
  1207.      *
  1208.      * @throws \Exception
  1209.      */
  1210.     public static function getUniqueKey($item$nr 0)
  1211.     {
  1212.         $list = new Listing();
  1213.         $list->setUnpublished(true);
  1214.         $list->setObjectTypes(DataObject::$types);
  1215.         $key Element\Service::getValidKey($item->getKey(), 'object');
  1216.         if (!$key) {
  1217.             throw new \Exception('No item key set.');
  1218.         }
  1219.         if ($nr) {
  1220.             $key .= '_'.$nr;
  1221.         }
  1222.         $parent $item->getParent();
  1223.         if (!$parent) {
  1224.             throw new \Exception('You have to set a parent Object to determine a unique Key');
  1225.         }
  1226.         if (!$item->getId()) {
  1227.             $list->setCondition('o_parentId = ? AND `o_key` = ? ', [$parent->getId(), $key]);
  1228.         } else {
  1229.             $list->setCondition('o_parentId = ? AND `o_key` = ? AND o_id != ? ', [$parent->getId(), $key$item->getId()]);
  1230.         }
  1231.         $check $list->loadIdList();
  1232.         if (!empty($check)) {
  1233.             $nr++;
  1234.             $key self::getUniqueKey($item$nr);
  1235.         }
  1236.         return $key;
  1237.     }
  1238.     /**
  1239.      * Enriches the layout definition before it is returned to the admin interface.
  1240.      *
  1241.      * @param Model\DataObject\ClassDefinition\Data|Model\DataObject\ClassDefinition\Layout|null $layout
  1242.      * @param Concrete|null $object
  1243.      * @param array $context additional contextual data
  1244.      *
  1245.      * @internal
  1246.      */
  1247.     public static function enrichLayoutDefinition(&$layout$object null$context = [])
  1248.     {
  1249.         if (is_null($layout)) {
  1250.             return;
  1251.         }
  1252.         $context['object'] = $object;
  1253.         //TODO Pimcore 11: remove method_exists BC layer
  1254.         if ($layout instanceof LayoutDefinitionEnrichmentInterface || method_exists($layout'enrichLayoutDefinition')) {
  1255.             if (!$layout instanceof LayoutDefinitionEnrichmentInterface) {
  1256.                 trigger_deprecation('pimcore/pimcore''10.1',
  1257.                     sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  1258.                     'Implement the %s interface instead.'LayoutDefinitionEnrichmentInterface::class));
  1259.             }
  1260.             $layout->enrichLayoutDefinition($object$context);
  1261.         }
  1262.         if ($layout instanceof Model\DataObject\ClassDefinition\Data\Localizedfields || $layout instanceof Model\DataObject\ClassDefinition\Data\Classificationstore && $layout->localized === true) {
  1263.             $user AdminTool::getCurrentUser();
  1264.             if (!$user->isAdmin() && ($context['purpose'] ?? null) !== 'gridconfig' && $object) {
  1265.                 $allowedView self::getLanguagePermissions($object$user'lView');
  1266.                 $allowedEdit self::getLanguagePermissions($object$user'lEdit');
  1267.                 self::enrichLayoutPermissions($layout$allowedView$allowedEdit);
  1268.             }
  1269.             if (isset($context['containerType']) && $context['containerType'] === 'fieldcollection') {
  1270.                 $context['subContainerType'] = 'localizedfield';
  1271.             } elseif (isset($context['containerType']) && $context['containerType'] === 'objectbrick') {
  1272.                 $context['subContainerType'] = 'localizedfield';
  1273.             } else {
  1274.                 $context['ownerType'] = 'localizedfield';
  1275.             }
  1276.             $context['ownerName'] = 'localizedfields';
  1277.         }
  1278.         if (method_exists($layout'getChildren')) {
  1279.             $children $layout->getChildren();
  1280.             if (is_array($children)) {
  1281.                 foreach ($children as $child) {
  1282.                     self::enrichLayoutDefinition($child$object$context);
  1283.                 }
  1284.             }
  1285.         }
  1286.     }
  1287.     /**
  1288.      * @param Model\DataObject\ClassDefinition\Data $layout
  1289.      * @param array $allowedView
  1290.      * @param array $allowedEdit
  1291.      *
  1292.      * @internal
  1293.      */
  1294.     public static function enrichLayoutPermissions(&$layout$allowedView$allowedEdit)
  1295.     {
  1296.         if ($layout instanceof Model\DataObject\ClassDefinition\Data\Localizedfields || $layout instanceof Model\DataObject\ClassDefinition\Data\Classificationstore && $layout->localized === true) {
  1297.             if (is_array($allowedView) && count($allowedView) > 0) {
  1298.                 $haveAllowedViewDefault null;
  1299.                 if ($layout->getFieldtype() === 'localizedfields') {
  1300.                     $haveAllowedViewDefault = isset($allowedView['default']);
  1301.                     if ($haveAllowedViewDefault) {
  1302.                         unset($allowedView['default']);
  1303.                     }
  1304.                 }
  1305.                 if (!($haveAllowedViewDefault && count($allowedView) == 0)) {
  1306.                     $layout->setPermissionView(
  1307.                         AdminTool::reorderWebsiteLanguages(
  1308.                             AdminTool::getCurrentUser(),
  1309.                             array_keys($allowedView),
  1310.                             true
  1311.                         )
  1312.                     );
  1313.                 }
  1314.             }
  1315.             if (is_array($allowedEdit) && count($allowedEdit) > 0) {
  1316.                 $haveAllowedEditDefault null;
  1317.                 if ($layout->getFieldtype() === 'localizedfields') {
  1318.                     $haveAllowedEditDefault = isset($allowedEdit['default']);
  1319.                     if ($haveAllowedEditDefault) {
  1320.                         unset($allowedEdit['default']);
  1321.                     }
  1322.                 }
  1323.                 if (!($haveAllowedEditDefault && count($allowedEdit) == 0)) {
  1324.                     $layout->setPermissionEdit(
  1325.                         AdminTool::reorderWebsiteLanguages(
  1326.                             AdminTool::getCurrentUser(),
  1327.                             array_keys($allowedEdit),
  1328.                             true
  1329.                         )
  1330.                     );
  1331.                 }
  1332.             }
  1333.         } else {
  1334.             if (method_exists($layout'getChildren')) {
  1335.                 $children $layout->getChildren();
  1336.                 if (is_array($children)) {
  1337.                     foreach ($children as $child) {
  1338.                         self::enrichLayoutPermissions($child$allowedView$allowedEdit);
  1339.                     }
  1340.                 }
  1341.             }
  1342.         }
  1343.     }
  1344.     private static function evaluateExpression(Model\DataObject\ClassDefinition\Data\CalculatedValue $fdConcrete $object, ?DataObject\Data\CalculatedValue $data)
  1345.     {
  1346.         $expressionLanguage = new ExpressionLanguage();
  1347.         //overwrite constant function to aviod exposing internal information
  1348.         $expressionLanguage->register('constant', function ($str) {
  1349.             throw new SyntaxError('`constant` function not available');
  1350.         }, function ($arguments$str) {
  1351.             throw new SyntaxError('`constant` function not available');
  1352.         });
  1353.         return $expressionLanguage->evaluate($fd->getCalculatorExpression(), ['object' => $object'data' => $data]);
  1354.     }
  1355.     /**
  1356.      * @param Concrete $object
  1357.      * @param array $params
  1358.      * @param Model\DataObject\Data\CalculatedValue|null $data
  1359.      *
  1360.      * @return string|null
  1361.      *
  1362.      * @internal
  1363.      */
  1364.     public static function getCalculatedFieldValueForEditMode($object$params$data)
  1365.     {
  1366.         if (!$data) {
  1367.             return null;
  1368.         }
  1369.         $fieldname $data->getFieldname();
  1370.         $ownerType $data->getOwnerType();
  1371.         $fd $data->getKeyDefinition();
  1372.         if ($fd === null) {
  1373.             if ($ownerType === 'object') {
  1374.                 $fd $object->getClass()->getFieldDefinition($fieldname);
  1375.             } elseif ($ownerType === 'localizedfield') {
  1376.                 /** @var Model\DataObject\ClassDefinition\Data\Localizedfields $lfDef */
  1377.                 $lfDef $object->getClass()->getFieldDefinition('localizedfields');
  1378.                 $fd $lfDef->getFieldDefinition($fieldname);
  1379.             }
  1380.         }
  1381.         if (!$fd instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
  1382.             return null;
  1383.         }
  1384.         $inheritanceEnabled Model\DataObject\Concrete::getGetInheritedValues();
  1385.         Model\DataObject\Concrete::setGetInheritedValues(true);
  1386.         switch ($fd->getCalculatorType()) {
  1387.             case DataObject\ClassDefinition\Data\CalculatedValue::CALCULATOR_TYPE_CLASS:
  1388.                 $className $fd->getCalculatorClass();
  1389.                 $calculator Model\DataObject\ClassDefinition\Helper\CalculatorClassResolver::resolveCalculatorClass($className);
  1390.                 if (!$calculator instanceof DataObject\ClassDefinition\CalculatorClassInterface) {
  1391.                     Logger::error('Class does not exist or is not valid: ' $className);
  1392.                     return null;
  1393.                 }
  1394.                 $result $calculator->getCalculatedValueForEditMode($object$data);
  1395.                 break;
  1396.             case DataObject\ClassDefinition\Data\CalculatedValue::CALCULATOR_TYPE_EXPRESSION:
  1397.                 try {
  1398.                     $result self::evaluateExpression($fd$object$data);
  1399.                 } catch (SyntaxError $exception) {
  1400.                     return $exception->getMessage();
  1401.                 }
  1402.                 break;
  1403.             default:
  1404.                 return null;
  1405.         }
  1406.         Model\DataObject\Concrete::setGetInheritedValues($inheritanceEnabled);
  1407.         return $result;
  1408.     }
  1409.     /**
  1410.      * @param Concrete|Model\DataObject\Fieldcollection\Data\AbstractData|Model\DataObject\Objectbrick\Data\AbstractData $object
  1411.      * @param Model\DataObject\Data\CalculatedValue|null $data
  1412.      *
  1413.      * @return mixed|null
  1414.      */
  1415.     public static function getCalculatedFieldValue($object$data)
  1416.     {
  1417.         if (!$data) {
  1418.             return null;
  1419.         }
  1420.         $fieldname $data->getFieldname();
  1421.         $ownerType $data->getOwnerType();
  1422.         $fd $data->getKeyDefinition();
  1423.         if ($fd === null) {
  1424.             if ($ownerType === 'object') {
  1425.                 $fd $object->getClass()->getFieldDefinition($fieldname);
  1426.             } elseif ($ownerType === 'localizedfield') {
  1427.                 /** @var Model\DataObject\ClassDefinition\Data\Localizedfields $lfDef */
  1428.                 $lfDef $object->getClass()->getFieldDefinition('localizedfields');
  1429.                 $fd $lfDef->getFieldDefinition($fieldname);
  1430.             }
  1431.         }
  1432.         if (!$fd instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
  1433.             return null;
  1434.         }
  1435.         $inheritanceEnabled Model\DataObject\Concrete::getGetInheritedValues();
  1436.         Model\DataObject\Concrete::setGetInheritedValues(true);
  1437.         if (
  1438.             $object instanceof Model\DataObject\Fieldcollection\Data\AbstractData ||
  1439.             $object instanceof Model\DataObject\Objectbrick\Data\AbstractData
  1440.         ) {
  1441.             $object $object->getObject();
  1442.         }
  1443.         switch ($fd->getCalculatorType()) {
  1444.             case DataObject\ClassDefinition\Data\CalculatedValue::CALCULATOR_TYPE_CLASS:
  1445.                 $className $fd->getCalculatorClass();
  1446.                 $calculator Model\DataObject\ClassDefinition\Helper\CalculatorClassResolver::resolveCalculatorClass($className);
  1447.                 if (!$calculator instanceof DataObject\ClassDefinition\CalculatorClassInterface) {
  1448.                     Logger::error('Class does not exist or is not valid: ' $className);
  1449.                     return null;
  1450.                 }
  1451.                 $result $calculator->compute($object$data);
  1452.                 break;
  1453.             case DataObject\ClassDefinition\Data\CalculatedValue::CALCULATOR_TYPE_EXPRESSION:
  1454.                 try {
  1455.                     $result self::evaluateExpression($fd$object$data);
  1456.                 } catch (SyntaxError $exception) {
  1457.                     return $exception->getMessage();
  1458.                 }
  1459.                 break;
  1460.             default:
  1461.                 return null;
  1462.         }
  1463.         Model\DataObject\Concrete::setGetInheritedValues($inheritanceEnabled);
  1464.         return $result;
  1465.     }
  1466.     /**
  1467.      * @return array
  1468.      */
  1469.     public static function getSystemFields()
  1470.     {
  1471.         return self::$systemFields;
  1472.     }
  1473.     /**
  1474.      * @param Concrete $container
  1475.      * @param ClassDefinition|ClassDefinition\Data $fd
  1476.      */
  1477.     public static function doResetDirtyMap($container$fd)
  1478.     {
  1479.         if (!method_exists($fd'getFieldDefinitions')) {
  1480.             return;
  1481.         }
  1482.         $fieldDefinitions $fd->getFieldDefinitions();
  1483.         if (is_array($fieldDefinitions)) {
  1484.             foreach ($fieldDefinitions as $fieldDefinition) {
  1485.                 $value $container->getObjectVar($fieldDefinition->getName());
  1486.                 if ($value instanceof Localizedfield) {
  1487.                     $value->resetLanguageDirtyMap();
  1488.                 }
  1489.                 if ($value instanceof DirtyIndicatorInterface) {
  1490.                     $value->resetDirtyMap();
  1491.                     self::doResetDirtyMap($value$fieldDefinitions[$fieldDefinition->getName()]);
  1492.                 }
  1493.             }
  1494.         }
  1495.     }
  1496.     /**
  1497.      * @param AbstractObject $object
  1498.      */
  1499.     public static function recursiveResetDirtyMap(AbstractObject $object)
  1500.     {
  1501.         if ($object instanceof DirtyIndicatorInterface) {
  1502.             $object->resetDirtyMap();
  1503.         }
  1504.         if ($object instanceof Concrete) {
  1505.             self::doResetDirtyMap($object$object->getClass());
  1506.         }
  1507.     }
  1508.     /**
  1509.      * @internal
  1510.      *
  1511.      * @param array $descriptor
  1512.      *
  1513.      * @return array
  1514.      */
  1515.     public static function buildConditionPartsFromDescriptor($descriptor)
  1516.     {
  1517.         $db Db::get();
  1518.         $conditionParts = [];
  1519.         foreach ($descriptor as $key => $value) {
  1520.             $lastChar is_string($value) ? $value[strlen($value) - 1] : null;
  1521.             if ($lastChar === '%') {
  1522.                 $conditionParts[] = $key ' LIKE ' $db->quote($value);
  1523.             } else {
  1524.                 $conditionParts[] = $key ' = ' $db->quote($value);
  1525.             }
  1526.         }
  1527.         return $conditionParts;
  1528.     }
  1529.     /**
  1530.      * @param AbstractObject $object
  1531.      * @param string $requestedLanguage
  1532.      * @param array $fields
  1533.      * @param array $helperDefinitions
  1534.      * @param LocaleServiceInterface $localeService
  1535.      * @param bool $returnMappedFieldNames
  1536.      * @param array $context
  1537.      *
  1538.      * @return array
  1539.      *
  1540.      * @internal
  1541.      */
  1542.     public static function getCsvDataForObject(AbstractObject $object$requestedLanguage$fields$helperDefinitionsLocaleServiceInterface $localeService$returnMappedFieldNames false$context = [])
  1543.     {
  1544.         $objectData = [];
  1545.         $mappedFieldnames = [];
  1546.         foreach ($fields as $field) {
  1547.             if (static::isHelperGridColumnConfig($field) && $validLanguages = static::expandGridColumnForExport($helperDefinitions$field)) {
  1548.                 $currentLocale $localeService->getLocale();
  1549.                 $mappedFieldnameBase self::mapFieldname($field$helperDefinitions);
  1550.                 foreach ($validLanguages as $validLanguage) {
  1551.                     $localeService->setLocale($validLanguage);
  1552.                     $fieldData self::getCsvFieldData($currentLocale$field$object$validLanguage$helperDefinitions);
  1553.                     $localizedFieldKey $field '-' $validLanguage;
  1554.                     if (!isset($mappedFieldnames[$localizedFieldKey])) {
  1555.                         $mappedFieldnames[$localizedFieldKey] = $mappedFieldnameBase '-' $validLanguage;
  1556.                     }
  1557.                     $objectData[$localizedFieldKey] = $fieldData;
  1558.                 }
  1559.                 $localeService->setLocale($currentLocale);
  1560.             } else {
  1561.                 $fieldData self::getCsvFieldData($requestedLanguage$field$object$requestedLanguage$helperDefinitions);
  1562.                 if (!isset($mappedFieldnames[$field])) {
  1563.                     $mappedFieldnames[$field] = self::mapFieldname($field$helperDefinitions);
  1564.                 }
  1565.                 $objectData[$field] = $fieldData;
  1566.             }
  1567.         }
  1568.         if ($returnMappedFieldNames) {
  1569.             $tmp = [];
  1570.             foreach ($mappedFieldnames as $key => $value) {
  1571.                 $tmp[$value] = $objectData[$key];
  1572.             }
  1573.             $objectData $tmp;
  1574.         }
  1575.         $event = new DataObjectEvent($object, ['objectData' => $objectData,
  1576.             'context' => $context,
  1577.             'requestedLanguage' => $requestedLanguage,
  1578.             'fields' => $fields,
  1579.             'helperDefinitions' => $helperDefinitions,
  1580.             'localeService' => $localeService,
  1581.             'returnMappedFieldNames' => $returnMappedFieldNames,
  1582.         ]);
  1583.         \Pimcore::getEventDispatcher()->dispatch($eventDataObjectEvents::POST_CSV_ITEM_EXPORT);
  1584.         $objectData $event->getArgument('objectData');
  1585.         return $objectData;
  1586.     }
  1587.     /**
  1588.      * @param string $requestedLanguage
  1589.      * @param LocaleServiceInterface $localeService
  1590.      * @param DataObject\Listing $list
  1591.      * @param string[] $fields
  1592.      * @param bool $addTitles
  1593.      * @param array $context
  1594.      *
  1595.      * @return array
  1596.      *
  1597.      * @internal
  1598.      */
  1599.     public static function getCsvData($requestedLanguageLocaleServiceInterface $localeService$list$fields$addTitles true$context = [])
  1600.     {
  1601.         $mappedFieldnames = [];
  1602.         $data = [];
  1603.         Logger::debug('objects in list:' count($list->getObjects()));
  1604.         $helperDefinitions = static::getHelperDefinitions();
  1605.         foreach ($list->getObjects() as $object) {
  1606.             if ($fields) {
  1607.                 if ($addTitles && empty($data)) {
  1608.                     $tmp = [];
  1609.                     $mapped self::getCsvDataForObject($object$requestedLanguage$fields$helperDefinitions$localeServicetrue$context);
  1610.                     foreach ($mapped as $key => $value) {
  1611.                         $tmp[] = '"' $key '"';
  1612.                     }
  1613.                     $data[] = $tmp;
  1614.                 }
  1615.                 $rowData self::getCsvDataForObject($object$requestedLanguage$fields$helperDefinitions$localeService$context);
  1616.                 $rowData self::escapeCsvRecord($rowData);
  1617.                 $data[] = $rowData;
  1618.             }
  1619.         }
  1620.         return $data;
  1621.     }
  1622.     /**
  1623.      * @param string $field
  1624.      * @param array $helperDefinitions
  1625.      *
  1626.      * @return string
  1627.      */
  1628.     protected static function mapFieldname($field$helperDefinitions)
  1629.     {
  1630.         if (strpos($field'#') === 0) {
  1631.             if (isset($helperDefinitions[$field])) {
  1632.                 if ($helperDefinitions[$field]->attributes) {
  1633.                     return $helperDefinitions[$field]->attributes->label $helperDefinitions[$field]->attributes->label $field;
  1634.                 }
  1635.                 return $field;
  1636.             }
  1637.         } elseif (substr($field01) == '~') {
  1638.             $fieldParts explode('~'$field);
  1639.             $type $fieldParts[1];
  1640.             if ($type == 'classificationstore') {
  1641.                 $fieldname $fieldParts[2];
  1642.                 $groupKeyId explode('-'$fieldParts[3]);
  1643.                 $groupId $groupKeyId[0];
  1644.                 $keyId $groupKeyId[1];
  1645.                 $groupConfig DataObject\Classificationstore\GroupConfig::getById($groupId);
  1646.                 $keyConfig DataObject\Classificationstore\KeyConfig::getById($keyId);
  1647.                 $field $fieldname '~' $groupConfig->getName() . '~' $keyConfig->getName();
  1648.             }
  1649.         }
  1650.         return $field;
  1651.     }
  1652.     /**
  1653.      * @param string $fallbackLanguage
  1654.      * @param string $field
  1655.      * @param DataObject\Concrete $object
  1656.      * @param string $requestedLanguage
  1657.      * @param array $helperDefinitions
  1658.      *
  1659.      * @return mixed
  1660.      *
  1661.      * @internal
  1662.      */
  1663.     protected static function getCsvFieldData($fallbackLanguage$field$object$requestedLanguage$helperDefinitions)
  1664.     {
  1665.         //check if field is systemfield
  1666.         $systemFieldMap = [
  1667.             'id' => 'getId',
  1668.             'fullpath' => 'getRealFullPath',
  1669.             'published' => 'getPublished',
  1670.             'creationDate' => 'getCreationDate',
  1671.             'modificationDate' => 'getModificationDate',
  1672.             'filename' => 'getKey',
  1673.             'key' => 'getKey',
  1674.             'classname' => 'getClassname',
  1675.         ];
  1676.         if (in_array($fieldarray_keys($systemFieldMap))) {
  1677.             $getter $systemFieldMap[$field];
  1678.             return $object->$getter();
  1679.         } else {
  1680.             //check if field is standard object field
  1681.             $fieldDefinition $object->getClass()->getFieldDefinition($field);
  1682.             if ($fieldDefinition) {
  1683.                 return $fieldDefinition->getForCsvExport($object);
  1684.             } else {
  1685.                 $fieldParts explode('~'$field);
  1686.                 // check for objects bricks and localized fields
  1687.                 if (static::isHelperGridColumnConfig($field)) {
  1688.                     if ($helperDefinitions[$field]) {
  1689.                         $cellValue = static::calculateCellValue($object$helperDefinitions$field, ['language' => $requestedLanguage]);
  1690.                         // Mimic grid concatenation behavior
  1691.                         if (is_array($cellValue)) {
  1692.                             $cellValue implode(','$cellValue);
  1693.                         }
  1694.                         return $cellValue;
  1695.                     }
  1696.                 } elseif (substr($field01) == '~') {
  1697.                     $type $fieldParts[1];
  1698.                     if ($type == 'classificationstore') {
  1699.                         $fieldname $fieldParts[2];
  1700.                         $groupKeyId explode('-'$fieldParts[3]);
  1701.                         $groupId $groupKeyId[0];
  1702.                         $keyId $groupKeyId[1];
  1703.                         $getter 'get' ucfirst($fieldname);
  1704.                         if (method_exists($object$getter)) {
  1705.                             $keyConfig DataObject\Classificationstore\KeyConfig::getById($keyId);
  1706.                             $type $keyConfig->getType();
  1707.                             $definition json_decode($keyConfig->getDefinition());
  1708.                             $fieldDefinition \Pimcore\Model\DataObject\Classificationstore\Service::getFieldDefinitionFromJson($definition$type);
  1709.                             /** @var DataObject\ClassDefinition\Data\Classificationstore $csFieldDefinition */
  1710.                             $csFieldDefinition $object->getClass()->getFieldDefinition($fieldname);
  1711.                             $csLanguage $requestedLanguage;
  1712.                             if (!$csFieldDefinition->isLocalized()) {
  1713.                                 $csLanguage 'default';
  1714.                             }
  1715.                             return $fieldDefinition->getForCsvExport(
  1716.                                 $object,
  1717.                                 ['context' => [
  1718.                                     'containerType' => 'classificationstore',
  1719.                                     'fieldname' => $fieldname,
  1720.                                     'groupId' => $groupId,
  1721.                                     'keyId' => $keyId,
  1722.                                     'language' => $csLanguage,
  1723.                                 ]]
  1724.                             );
  1725.                         }
  1726.                     }
  1727.                     //key value store - ignore for now
  1728.                 } elseif (count($fieldParts) > 1) {
  1729.                     // brick
  1730.                     $brickType $fieldParts[0];
  1731.                     $brickDescriptor null;
  1732.                     $innerContainer null;
  1733.                     if (strpos($brickType'?') !== false) {
  1734.                         $brickDescriptor substr($brickType1);
  1735.                         $brickDescriptor json_decode($brickDescriptortrue);
  1736.                         $innerContainer $brickDescriptor['innerContainer'] ?? 'localizedfields';
  1737.                         $brickType $brickDescriptor['containerKey'];
  1738.                     }
  1739.                     $brickKey $fieldParts[1];
  1740.                     $key = static::getFieldForBrickType($object->getClass(), $brickType);
  1741.                     $brickClass DataObject\Objectbrick\Definition::getByKey($brickType);
  1742.                     if ($brickDescriptor) {
  1743.                         /** @var DataObject\ClassDefinition\Data\Localizedfields $localizedFields */
  1744.                         $localizedFields $brickClass->getFieldDefinition($innerContainer);
  1745.                         $fieldDefinition $localizedFields->getFieldDefinition($brickDescriptor['brickfield']);
  1746.                     } else {
  1747.                         $fieldDefinition $brickClass->getFieldDefinition($brickKey);
  1748.                     }
  1749.                     if ($fieldDefinition) {
  1750.                         $brickContainer $object->{'get' ucfirst($key)}();
  1751.                         if ($brickContainer && !empty($brickKey)) {
  1752.                             $brick $brickContainer->{'get' ucfirst($brickType)}();
  1753.                             if ($brick) {
  1754.                                 $params = [
  1755.                                     'context' => [
  1756.                                         'containerType' => 'objectbrick',
  1757.                                         'containerKey' => $brickType,
  1758.                                         'fieldname' => $brickKey,
  1759.                                     ],
  1760.                                 ];
  1761.                                 $value $brick;
  1762.                                 if ($brickDescriptor) {
  1763.                                     $innerContainer $brickDescriptor['innerContainer'] ?? 'localizedfields';
  1764.                                     $value $brick->{'get' ucfirst($innerContainer)}();
  1765.                                 }
  1766.                                 return $fieldDefinition->getForCsvExport($value$params);
  1767.                             }
  1768.                         }
  1769.                     }
  1770.                 } else {
  1771.                     // if the definition is not set try to get the definition from localized fields
  1772.                     /** @var DataObject\ClassDefinition\Data\Localizedfields|null $locFields */
  1773.                     $locFields $object->getClass()->getFieldDefinition('localizedfields');
  1774.                     if ($locFields) {
  1775.                         $fieldDefinition $locFields->getFieldDefinition($field);
  1776.                         if ($fieldDefinition) {
  1777.                             return $fieldDefinition->getForCsvExport($object->get('localizedFields'), ['language' => $fallbackLanguage]);
  1778.                         }
  1779.                     }
  1780.                 }
  1781.             }
  1782.         }
  1783.         return null;
  1784.     }
  1785. }