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

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