vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/Objectbricks.php line 448

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\DataObject\ClassDefinition\Data;
  15. use Pimcore\Logger;
  16. use Pimcore\Model;
  17. use Pimcore\Model\DataObject;
  18. use Pimcore\Model\DataObject\ClassDefinition\Data;
  19. use Pimcore\Model\DataObject\Objectbrick;
  20. use Pimcore\Normalizer\NormalizerInterface;
  21. use Pimcore\Tool;
  22. class Objectbricks extends Data implements CustomResourcePersistingInterfaceTypeDeclarationSupportInterfaceNormalizerInterfaceDataContainerAwareInterfaceIdRewriterInterfacePreSetDataInterface
  23. {
  24.     use DataObject\Traits\ClassSavedTrait;
  25.     /**
  26.      * Static type of this element
  27.      *
  28.      * @internal
  29.      *
  30.      * @var string
  31.      */
  32.     public $fieldtype 'objectbricks';
  33.     /**
  34.      * @internal
  35.      *
  36.      * @var array
  37.      */
  38.     public $allowedTypes = [];
  39.     /**
  40.      * @internal
  41.      *
  42.      * @var int|null
  43.      */
  44.     public $maxItems;
  45.     /**
  46.      * @internal
  47.      *
  48.      * @var bool
  49.      */
  50.     public $border false;
  51.     /**
  52.      * @param int|null $maxItems
  53.      *
  54.      * @return $this
  55.      */
  56.     public function setMaxItems($maxItems)
  57.     {
  58.         $this->maxItems $this->getAsIntegerCast($maxItems);
  59.         return $this;
  60.     }
  61.     /**
  62.      * @return int|null
  63.      */
  64.     public function getMaxItems()
  65.     {
  66.         return $this->maxItems;
  67.     }
  68.     /**
  69.      * @return bool
  70.      */
  71.     public function getBorder(): bool
  72.     {
  73.         return $this->border;
  74.     }
  75.     /**
  76.      * @param bool $border
  77.      */
  78.     public function setBorder(bool $border): void
  79.     {
  80.         $this->border $border;
  81.     }
  82.     /**
  83.      * @see Data::getDataForEditmode
  84.      *
  85.      * @param DataObject\Objectbrick|null $data
  86.      * @param null|DataObject\Concrete $object
  87.      * @param array $params
  88.      *
  89.      * @return array
  90.      */
  91.     public function getDataForEditmode($data$object null$params = [])
  92.     {
  93.         $editmodeData = [];
  94.         if ($data instanceof DataObject\Objectbrick) {
  95.             $allowedBrickTypes $data->getAllowedBrickTypes();
  96.             foreach ($allowedBrickTypes as $allowedBrickType) {
  97.                 $getter 'get' ucfirst($allowedBrickType);
  98.                 $params = [
  99.                     'objectFromVersion' => $params['objectFromVersion'],
  100.                     'context' => [
  101.                         'containerType' => 'objectbrick',
  102.                         'containerKey' => $allowedBrickType,
  103.                     ],
  104.                     'owner' => $data,
  105.                     'fieldname' => $this->getName(),
  106.                 ];
  107.                 $editmodeData[] = $this->doGetDataForEditmode($getter$data$params$allowedBrickType);
  108.             }
  109.         }
  110.         return $editmodeData;
  111.     }
  112.     /**
  113.      * @param string $getter
  114.      * @param DataObject\Objectbrick $data
  115.      * @param array|null $params
  116.      * @param string $allowedBrickType
  117.      * @param int $level
  118.      *
  119.      * @return array|null
  120.      */
  121.     private function doGetDataForEditmode($getter$data$params$allowedBrickType$level 0)
  122.     {
  123.         $object $data->getObject();
  124.         if ($object) {
  125.             $parent DataObject\Service::hasInheritableParentObject($object);
  126.         }
  127.         if (!method_exists($data$getter)) {
  128.             return null;
  129.         }
  130.         $item $data->$getter();
  131.         if (!$item && !empty($parent)) {
  132.             $data $parent->{'get' ucfirst($this->getName())}();
  133.             return $this->doGetDataForEditmode($getter$data$params$allowedBrickType$level 1);
  134.         }
  135.         if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  136.             return null;
  137.         }
  138.         if (!$collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  139.             return null;
  140.         }
  141.         $brickData = [];
  142.         $brickMetaData = [];
  143.         $inherited false;
  144.         foreach ($collectionDef->getFieldDefinitions() as $fd) {
  145.             if (!$fd instanceof CalculatedValue) {
  146.                 $fieldData $this->getDataForField($item$fd->getName(), $fd$level$data->getObject(), $getter$params);
  147.                 $brickData[$fd->getName()] = $fieldData->objectData;
  148.                 $brickMetaData[$fd->getName()] = $fieldData->metaData;
  149.                 if ($fieldData->metaData['inherited'] == true) {
  150.                     $inherited true;
  151.                 }
  152.             }
  153.         }
  154.         $calculatedChilds = [];
  155.         self::collectCalculatedValueItems($collectionDef->getFieldDefinitions(), $calculatedChilds);
  156.         foreach ($calculatedChilds as $fd) {
  157.             $fieldData = new DataObject\Data\CalculatedValue($fd->getName());
  158.             $fieldData->setContextualData('objectbrick'$this->getName(), nullnullnull$fd->getName(), $fd);
  159.             $fieldData $fd->getDataForEditmode($fieldData$data->getObject(), $params);
  160.             $brickData[$fd->getName()] = $fieldData;
  161.         }
  162.         $brickDefinition DataObject\Objectbrick\Definition::getByKey($allowedBrickType);
  163.         $editmodeDataItem = [
  164.             'data' => $brickData,
  165.             'type' => $item->getType(),
  166.             'metaData' => $brickMetaData,
  167.             'inherited' => $inherited,
  168.             'title' => $brickDefinition->getTitle(),
  169.         ];
  170.         return $editmodeDataItem;
  171.     }
  172.     /**
  173.      * gets recursively attribute data from parent and fills objectData and metaData
  174.      *
  175.      * @param Objectbrick\Data\AbstractData $item
  176.      * @param string $key
  177.      * @param Data $fielddefinition
  178.      * @param int $level
  179.      * @param DataObject\Concrete|null $baseObject
  180.      * @param string $getter
  181.      * @param array|null $params
  182.      *
  183.      * @return \stdClass
  184.      */
  185.     private function getDataForField($item$key$fielddefinition$level$baseObject$getter$params)
  186.     {
  187.         $result = new \stdClass();
  188.         if ($baseObject) {
  189.             $parent DataObject\Service::hasInheritableParentObject($baseObject);
  190.         }
  191.         $valueGetter 'get' ucfirst($key);
  192.         // Editmode optimization for lazy loaded relations except metadata relations because they have additional data
  193.         // which cannot be loaded directly from the DB.
  194.         // Note that this is just for AbstractRelations, not for all LazyLoadingSupportInterface types.
  195.         // It tries to optimize fetching the data needed for the editmode without loading the entire target element.
  196.         if (
  197.             (!isset($params['objectFromVersion']) || !$params['objectFromVersion'])
  198.             && ($fielddefinition instanceof Data\Relations\AbstractRelations)
  199.             && $fielddefinition->getLazyLoading()
  200.             && !$fielddefinition instanceof ManyToManyObjectRelation
  201.             && !$fielddefinition instanceof AdvancedManyToManyRelation
  202.         ) {
  203.             //lazy loading data is fetched from DB differently, so that not every relation object is instantiated
  204.             $refKey $key;
  205.             $refId null;
  206.             $relations $item->getRelationData($refKeytrue$refId);
  207.             if (empty($relations) && !empty($parent)) {
  208.                 $parentItem $parent->{'get' ucfirst($this->getName())}();
  209.                 if (!empty($parentItem)) {
  210.                     $parentItem $parentItem->$getter();
  211.                     if ($parentItem) {
  212.                         return $this->getDataForField($parentItem$key$fielddefinition$level 1$parent$getter$params);
  213.                     }
  214.                 }
  215.             }
  216.             $data = [];
  217.             if ($fielddefinition instanceof ManyToOneRelation) {
  218.                 $data $relations[0] ?? null;
  219.             } else {
  220.                 foreach ($relations as $rel) {
  221.                     $data[] = ['id' => $rel['id'], 'fullpath' => $rel['path'],  'type' => $rel['type'], 'subtype' => $rel['subtype'], 'published' => ($rel['published'] ? true false)];
  222.                 }
  223.             }
  224.             $result->objectData $data;
  225.             $result->metaData['objectid'] = $baseObject->getId();
  226.             $result->metaData['inherited'] = $level != 0;
  227.         } else {
  228.             $fieldValue null;
  229.             $fieldValue $item->$valueGetter();
  230.             $editmodeValue $fielddefinition->getDataForEditmode($fieldValue$baseObject$params);
  231.             if ($fielddefinition->isEmpty($fieldValue) && !empty($parent)) {
  232.                 $backup DataObject::getGetInheritedValues();
  233.                 DataObject::setGetInheritedValues(true);
  234.                 $parentItem $parent->{'get' ucfirst($this->getName())}()->$getter();
  235.                 DataObject::setGetInheritedValues($backup);
  236.                 if (!empty($parentItem)) {
  237.                     return $this->getDataForField($parentItem$key$fielddefinition$level 1$parent$getter$params);
  238.                 }
  239.             }
  240.             $result->objectData $editmodeValue;
  241.             $result->metaData['objectid'] = $baseObject $baseObject->getId() : null;
  242.             $result->metaData['inherited'] = $level != 0;
  243.         }
  244.         return $result;
  245.     }
  246.     /**
  247.      * @see Data::getDataFromEditmode
  248.      *
  249.      * @param string|array $data
  250.      * @param null|DataObject\Concrete $object
  251.      * @param mixed $params
  252.      *
  253.      * @return Objectbrick\Data\AbstractData
  254.      */
  255.     public function getDataFromEditmode($data$object null$params = [])
  256.     {
  257.         $container $this->getDataFromObjectParam($object);
  258.         if (empty($container)) {
  259.             $className $object->getClass()->getName();
  260.             $containerClass '\\Pimcore\\Model\\DataObject\\' ucfirst($className) . '\\' ucfirst($this->getName());
  261.             $container = new $containerClass($object$this->getName());
  262.         }
  263.         if (is_array($data)) {
  264.             foreach ($data as $collectionRaw) {
  265.                 $collectionData = [];
  266.                 $collectionDef DataObject\Objectbrick\Definition::getByKey($collectionRaw['type']);
  267.                 $getter 'get' ucfirst($collectionRaw['type']);
  268.                 $brick $container->$getter();
  269.                 if (empty($brick)) {
  270.                     $brickClass '\\Pimcore\\Model\\DataObject\\Objectbrick\\Data\\' ucfirst($collectionRaw['type']);
  271.                     $brick = new $brickClass($object);
  272.                 }
  273.                 $brick->setFieldname($this->getName());
  274.                 if ($collectionRaw['data'] == 'deleted') {
  275.                     $brick->setDoDelete(true);
  276.                 } else {
  277.                     foreach ($collectionDef->getFieldDefinitions() as $fd) {
  278.                         if (array_key_exists($fd->getName(), $collectionRaw['data'])) {
  279.                             $collectionData[$fd->getName()] =
  280.                                 $fd->getDataFromEditmode($collectionRaw['data'][$fd->getName()], $object,
  281.                                     [
  282.                                         'context' => [
  283.                                             'containerType' => 'objectbrick',
  284.                                             'containerKey' => $collectionRaw['type'],
  285.                                             'fieldname' => $this->getName(),
  286.                                         ],
  287.                                     ]);
  288.                         }
  289.                     }
  290.                     $brick->setValues($collectionData);
  291.                     $setter 'set' ucfirst($collectionRaw['type']);
  292.                     $container->$setter($brick);
  293.                 }
  294.             }
  295.         }
  296.         return $container;
  297.     }
  298.     /**
  299.      * @see Data::getVersionPreview
  300.      *
  301.      * @param Objectbrick\Data\AbstractData|null $data
  302.      * @param null|DataObject\Concrete $object
  303.      * @param mixed $params
  304.      *
  305.      * @return string
  306.      */
  307.     public function getVersionPreview($data$object null$params = [])
  308.     {
  309.         // this is handled directly in the template
  310.         // /bundles/AdminBundle/Resources/views/Admin/DataObject/DataObject/previewVersion.html.twig
  311.         return 'BRICKS';
  312.     }
  313.     /**
  314.      * {@inheritdoc}
  315.      */
  316.     public function getForCsvExport($object$params = [])
  317.     {
  318.         return 'NOT SUPPORTED';
  319.     }
  320.     /**
  321.      * {@inheritdoc}
  322.      */
  323.     public function getDataForSearchIndex($object$params = [])
  324.     {
  325.         $dataString '';
  326.         $obData $this->getDataFromObjectParam($object$params);
  327.         if ($obData instanceof DataObject\Objectbrick) {
  328.             $items $obData->getItems();
  329.             foreach ($items as $item) {
  330.                 if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  331.                     continue;
  332.                 }
  333.                 if ($collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  334.                     foreach ($collectionDef->getFieldDefinitions() as $fd) {
  335.                         $dataString .= $fd->getDataForSearchIndex($item$params) . ' ';
  336.                     }
  337.                 }
  338.             }
  339.         }
  340.         return $dataString;
  341.     }
  342.     /**
  343.      * {@inheritdoc}
  344.      */
  345.     public function save($object$params = [])
  346.     {
  347.         $container $this->getDataFromObjectParam($object);
  348.         if ($container instanceof DataObject\Objectbrick) {
  349.             $container->save($object$params);
  350.         }
  351.     }
  352.     /**
  353.      * {@inheritdoc}
  354.      */
  355.     public function load($object$params = [])
  356.     {
  357.         $classname '\\Pimcore\\Model\\DataObject\\' ucfirst($object->getClass()->getName()) . '\\' ucfirst($this->getName());
  358.         if (Tool::classExists($classname)) {
  359.             $container = new $classname($object$this->getName());
  360.             $container->load($object);
  361.             return $container;
  362.         }
  363.         return null;
  364.     }
  365.     /**
  366.      * {@inheritdoc}
  367.      */
  368.     public function delete($object$params = [])
  369.     {
  370.         $container $this->load($object);
  371.         if ($container) {
  372.             $container->delete($object);
  373.         }
  374.     }
  375.     /**
  376.      * @return array
  377.      */
  378.     public function getAllowedTypes()
  379.     {
  380.         return $this->allowedTypes;
  381.     }
  382.     /**
  383.      * @param string|array|null $allowedTypes
  384.      *
  385.      * @return $this
  386.      */
  387.     public function setAllowedTypes($allowedTypes)
  388.     {
  389.         if (is_string($allowedTypes)) {
  390.             $allowedTypes explode(','$allowedTypes);
  391.         }
  392.         if (is_array($allowedTypes)) {
  393.             for ($i 0$i count($allowedTypes); $i++) {
  394.                 if (!DataObject\Objectbrick\Definition::getByKey($allowedTypes[$i])) {
  395.                     Logger::warn("Removed unknown allowed type [ $allowedTypes[$i] ] from allowed types of object brick");
  396.                     unset($allowedTypes[$i]);
  397.                 }
  398.             }
  399.         }
  400.         $this->allowedTypes = (array)$allowedTypes;
  401.         $this->allowedTypes array_values($this->allowedTypes); // get rid of indexed array (.join() doesnt work in JS)
  402.         return $this;
  403.     }
  404.     /**
  405.      * { @inheritdoc }
  406.      */
  407.     public function preSetData(/** mixed */ $container/**  mixed */ $data/** array */ $params = []) // : mixed
  408.     {
  409.         if ($data instanceof DataObject\Objectbrick) {
  410.             $data->setFieldname($this->getName());
  411.         }
  412.         return $data;
  413.     }
  414.     /**
  415.      * @param Objectbrick|null $data
  416.      *
  417.      * @return array
  418.      */
  419.     public function resolveDependencies($data)
  420.     {
  421.         $dependencies = [];
  422.         if ($data instanceof DataObject\Objectbrick) {
  423.             $items $data->getItems();
  424.             foreach ($items as $item) {
  425.                 if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  426.                     continue;
  427.                 }
  428.                 if ($collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  429.                     foreach ($collectionDef->getFieldDefinitions() as $fd) {
  430.                         $key $fd->getName();
  431.                         $getter 'get' ucfirst($key);
  432.                         $dependencies array_merge($dependencies$fd->resolveDependencies($item->$getter()));
  433.                     }
  434.                 }
  435.             }
  436.         }
  437.         return $dependencies;
  438.     }
  439.     /**
  440.      * {@inheritdoc}
  441.      */
  442.     public function getCacheTags($data, array $tags = [])
  443.     {
  444.         if ($data instanceof DataObject\Objectbrick) {
  445.             $items $data->getItems();
  446.             foreach ($items as $item) {
  447.                 if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  448.                     continue;
  449.                 }
  450.                 if ($collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  451.                     foreach ($collectionDef->getFieldDefinitions(['suppressEnrichment' => true]) as $fd) {
  452.                         $key $fd->getName();
  453.                         $getter 'get' ucfirst($key);
  454.                         $tags $fd->getCacheTags($item->$getter(), $tags);
  455.                     }
  456.                 }
  457.             }
  458.         }
  459.         return $tags;
  460.     }
  461.     /**
  462.      * {@inheritdoc}
  463.      */
  464.     public function getGetterCode($class)
  465.     {
  466.         // getter
  467.         if ($class->getGenerateTypeDeclarations() && $this->getReturnTypeDeclaration() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface) {
  468.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  469.         } else {
  470.             $typeDeclaration '';
  471.         }
  472.         $key $this->getName();
  473.         $classname '\\Pimcore\\Model\\DataObject\\' ucfirst($class->getName()) . '\\' ucfirst($this->getName());
  474.         $code '/**' "\n";
  475.         $code .= '* @return ' $classname "\n";
  476.         $code .= '*/' "\n";
  477.         $code .= 'public function get' ucfirst($key) . '()' $typeDeclaration "\n";
  478.         $code .= '{' "\n";
  479.         $code .= "\t" '$data = $this->' $key ";\n";
  480.         $code .= "\t" 'if (!$data) {' "\n";
  481.         $code .= "\t\t" 'if (\Pimcore\Tool::classExists("' str_replace('\\''\\\\'$classname) . '")) {' "\n";
  482.         $code .= "\t\t\t" '$data = new ' $classname '($this, "' $key '");' "\n";
  483.         $code .= "\t\t\t" '$this->' $key ' = $data;' "\n";
  484.         $code .= "\t\t" '} else {' "\n";
  485.         $code .= "\t\t\t" 'return null;' "\n";
  486.         $code .= "\t\t" '}' "\n";
  487.         $code .= "\t" '}' "\n";
  488.         //TODO Pimcore 11: remove method_exists BC layer
  489.         if ($this instanceof PreGetDataInterface || method_exists($this'preGetData')) {
  490.             $code .= "\t" '$data = $this->getClass()->getFieldDefinition("' $key '")->preGetData($this);' "\n";
  491.         }
  492.         $code .= $this->getPreGetValueHookCode($key);
  493.         $code .= "\t" 'return $data;' "\n";
  494.         $code .= "}\n\n";
  495.         return $code;
  496.     }
  497.     /**
  498.      * {@inheritdoc}
  499.      */
  500.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  501.     {
  502.         if ($data instanceof DataObject\Objectbrick) {
  503.             $validationExceptions = [];
  504.             $itemCount 0;
  505.             $allowedTypes $this->getAllowedTypes();
  506.             foreach ($allowedTypes as $allowedType) {
  507.                 $getter 'get' ucfirst($allowedType);
  508.                 /** @var DataObject\Objectbrick\Data\AbstractData $item */
  509.                 $item $data->$getter();
  510.                 if ($item instanceof DataObject\Objectbrick\Data\AbstractData) {
  511.                     if ($item->getDoDelete()) {
  512.                         continue;
  513.                     }
  514.                     $itemCount++;
  515.                     if (!$collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  516.                         continue;
  517.                     }
  518.                     //max limit check should be performed irrespective of omitMandatory check
  519.                     if (!empty($this->maxItems) && $itemCount $this->maxItems) {
  520.                         throw new Model\Element\ValidationException('Maximum limit reached for items in brick: ' $this->getName());
  521.                     }
  522.                     //needed when new brick is added but not saved yet - then validity check fails.
  523.                     if (!$item->getFieldname()) {
  524.                         $item->setFieldname($data->getFieldname());
  525.                     }
  526.                     if (!$omitMandatoryCheck) {
  527.                         foreach ($collectionDef->getFieldDefinitions() as $fd) {
  528.                             $key $fd->getName();
  529.                             $getter 'get' ucfirst($key);
  530.                             try {
  531.                                 $fd->checkValidity($item->$getter(), false$params);
  532.                             } catch (Model\Element\ValidationException $ve) {
  533.                                 if ($item->getObject()->getClass()->getAllowInherit() && $fd->supportsInheritance() && $fd->isEmpty($item->$getter())) {
  534.                                     //try again with parent data when inheritance is activated
  535.                                     try {
  536.                                         $getInheritedValues DataObject::doGetInheritedValues();
  537.                                         DataObject::setGetInheritedValues(true);
  538.                                         $fd->checkValidity($item->$getter(), $omitMandatoryCheck$params);
  539.                                         DataObject::setGetInheritedValues($getInheritedValues);
  540.                                     } catch (\Exception $e) {
  541.                                         if (!$e instanceof Model\Element\ValidationException) {
  542.                                             throw $e;
  543.                                         }
  544.                                         $e->addContext($this->getName());
  545.                                         $validationExceptions[] = $e;
  546.                                     }
  547.                                 } else {
  548.                                     $ve->addContext($this->getName());
  549.                                     $validationExceptions[] = $ve;
  550.                                 }
  551.                             }
  552.                         }
  553.                     }
  554.                 }
  555.             }
  556.             if ($validationExceptions) {
  557.                 $errors = [];
  558.                 /** @var Model\Element\ValidationException $e */
  559.                 foreach ($validationExceptions as $e) {
  560.                     $errors[] = $e->getAggregatedMessage();
  561.                 }
  562.                 $message implode(' / '$errors);
  563.                 throw new Model\Element\ValidationException('invalid brick ' $this->getName().': '.$message);
  564.             }
  565.         }
  566.     }
  567.     /**
  568.      * @param Objectbrick|null $data
  569.      * @param DataObject\Concrete $object
  570.      * @param mixed $params
  571.      *
  572.      * @return string
  573.      */
  574.     public function getDataForGrid($data$object null$params = [])
  575.     {
  576.         return 'NOT SUPPORTED';
  577.     }
  578.     /**
  579.      * @param Objectbrick\Data\AbstractData $item
  580.      * @param string $key
  581.      * @param Data $fielddefinition
  582.      * @param int $level
  583.      * @param DataObject\Concrete $baseObject
  584.      * @param string $getter
  585.      * @param array $params
  586.      *
  587.      * @return array|null
  588.      */
  589.     private function getDiffDataForField($item$key$fielddefinition$level$baseObject$getter$params = [])
  590.     {
  591.         $valueGetter 'get' ucfirst($key);
  592.         $value $fielddefinition->getDiffDataForEditmode($item->$valueGetter(), $baseObject$params);
  593.         return $value;
  594.     }
  595.     /**
  596.      * @param Objectbrick $data
  597.      * @param string $getter
  598.      * @param array $params
  599.      * @param int $level
  600.      *
  601.      * @return array|null
  602.      */
  603.     private function doGetDiffDataForEditmode($data$getter$params = [], $level 0)
  604.     {
  605.         $parent DataObject\Service::hasInheritableParentObject($data->getObject());
  606.         $item $data->$getter();
  607.         if (!$item && !empty($parent)) {
  608.             $data $parent->{'get' ucfirst($this->getName())}();
  609.             return $this->doGetDiffDataForEditmode($data$getter$params$level 1);
  610.         }
  611.         if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  612.             return null;
  613.         }
  614.         if (!$collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  615.             return null;
  616.         }
  617.         $result = [];
  618.         foreach ($collectionDef->getFieldDefinitions() as $fd) {
  619.             $fieldData $this->getDiffDataForField($item$fd->getName(), $fd$level$data->getObject(), $getter$params = []);
  620.             $diffdata = [];
  621.             foreach ($fieldData as $subdata) {
  622.                 $diffdata['field'] = $this->getName();
  623.                 $diffdata['key'] = $this->getName() . '~' $fd->getName();
  624.                 $diffdata['value'] = $subdata['value'];
  625.                 $diffdata['type'] = $subdata['type'];
  626.                 $diffdata['disabled'] = $subdata['disabled'];
  627.                 // this is not needed anymoe
  628.                 unset($subdata['type']);
  629.                 unset($subdata['value']);
  630.                 $diffdata['title'] = $this->getName() . ' / ' $subdata['title'];
  631.                 $brickdata = [
  632.                     'brick' => substr($getter3),
  633.                     'name' => $fd->getName(),
  634.                     'subdata' => $subdata,
  635.                 ];
  636.                 $diffdata['data'] = $brickdata;
  637.             }
  638.             $result[] = $diffdata;
  639.         }
  640.         return $result;
  641.     }
  642.     /** See parent class.
  643.      * @param mixed $data
  644.      * @param DataObject\Concrete|null $object
  645.      * @param mixed $params
  646.      *
  647.      * @return array|null
  648.      */
  649.     public function getDiffDataForEditMode($data$object null$params = [])
  650.     {
  651.         $editmodeData = [];
  652.         if ($data instanceof DataObject\Objectbrick) {
  653.             $getters $data->getBrickGetters();
  654.             foreach ($getters as $getter) {
  655.                 $brickdata $this->doGetDiffDataForEditmode($data$getter$params);
  656.                 if ($brickdata) {
  657.                     foreach ($brickdata as $item) {
  658.                         $editmodeData[] = $item;
  659.                     }
  660.                 }
  661.             }
  662.         }
  663.         return $editmodeData;
  664.     }
  665.     /**
  666.      * See parent class.
  667.      *
  668.      * @param array $data
  669.      * @param DataObject\Concrete|null $object
  670.      * @param mixed $params
  671.      *
  672.      * @return mixed
  673.      */
  674.     public function getDiffDataFromEditmode($data$object null$params = [])
  675.     {
  676.         $valueGetter 'get' ucfirst($this->getName());
  677.         $valueSetter 'set' ucfirst($this->getName());
  678.         $brickdata $object->$valueGetter();
  679.         foreach ($data as $item) {
  680.             $subdata $item['data'];
  681.             if (!$subdata) {
  682.                 continue;
  683.             }
  684.             $brickname $subdata['brick'];
  685.             $getter 'get' ucfirst($brickname);
  686.             $setter 'set' ucfirst($brickname);
  687.             $brick $brickdata->$getter();
  688.             if (!$brick) {
  689.                 // brick must be added to object
  690.                 $brickClass '\\Pimcore\\Model\\DataObject\\Objectbrick\\Data\\' ucfirst($brickname);
  691.                 $brick = new $brickClass($object);
  692.             }
  693.             $fieldname $subdata['name'];
  694.             $fielddata = [$subdata['subdata']];
  695.             $collectionDef DataObject\Objectbrick\Definition::getByKey($brickname);
  696.             $fd $collectionDef->getFieldDefinition($fieldname);
  697.             if ($fd && $fd->isDiffChangeAllowed($object$params)) {
  698.                 $value $fd->getDiffDataFromEditmode($fielddata$object$params);
  699.                 $brick->setValue($fieldname$value);
  700.                 $brickdata->$setter($brick);
  701.             }
  702.             $object->$valueSetter($brickdata);
  703.         }
  704.         return $brickdata;
  705.     }
  706.     /**
  707.      * {@inheritdoc}
  708.      */
  709.     public function isDiffChangeAllowed($object$params = [])
  710.     {
  711.         return true;
  712.     }
  713.     /**
  714.      * { @inheritdoc }
  715.      */
  716.     public function rewriteIds(/** mixed */ $container/** array */ $idMapping/** array */ $params = []) /** :mixed */
  717.     {
  718.         $data $this->getDataFromObjectParam($container$params);
  719.         if ($data instanceof DataObject\Objectbrick) {
  720.             $items $data->getItems();
  721.             foreach ($items as $item) {
  722.                 if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  723.                     continue;
  724.                 }
  725.                 if (!$collectionDef DataObject\Objectbrick\Definition::getByKey($item->getType())) {
  726.                     continue;
  727.                 }
  728.                 foreach ($collectionDef->getFieldDefinitions() as $fd) {
  729.                     //TODO Pimcore 11: remove method_exists BC layer
  730.                     if ($fd instanceof IdRewriterInterface || method_exists($fd'rewriteIds')) {
  731.                         if (!$fd instanceof IdRewriterInterface) {
  732.                             trigger_deprecation('pimcore/pimcore''10.1',
  733.                                 sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  734.                                 'Implement the %s interface instead.'IdRewriterInterface::class));
  735.                         }
  736.                         $d $fd->rewriteIds($item$idMapping$params);
  737.                         $setter 'set' ucfirst($fd->getName());
  738.                         $item->$setter($d);
  739.                     }
  740.                 }
  741.             }
  742.         }
  743.         return $data;
  744.     }
  745.     /**
  746.      * @param DataObject\ClassDefinition\Data\Objectbricks $masterDefinition
  747.      */
  748.     public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  749.     {
  750.         $this->allowedTypes $masterDefinition->allowedTypes;
  751.         $this->maxItems $masterDefinition->maxItems;
  752.     }
  753.     /**
  754.      * This method is called in DataObject\ClassDefinition::save() and is used to create the database table for the localized data
  755.      *
  756.      * @param DataObject\ClassDefinition $class
  757.      * @param array $params
  758.      */
  759.     public function classSaved($class$params = [])
  760.     {
  761.         if (is_array($this->allowedTypes)) {
  762.             foreach ($this->allowedTypes as $allowedType) {
  763.                 $definition DataObject\Objectbrick\Definition::getByKey($allowedType);
  764.                 if ($definition) {
  765.                     $definition->getDao()->createUpdateTable($class);
  766.                     $fieldDefinition $definition->getFieldDefinitions();
  767.                     foreach ($fieldDefinition as $fd) {
  768.                         //TODO Pimcore 11 remove method_exists call
  769.                         if (method_exists($fd'classSaved')) {
  770.                             // defer creation
  771.                             if (!$fd instanceof DataContainerAwareInterface) {
  772.                                 $fd->classSaved($class);
  773.                             }
  774.                         }
  775.                     }
  776.                     $definition->getDao()->classSaved($class);
  777.                 }
  778.             }
  779.         }
  780.     }
  781.     /**
  782.      * @param DataObject\ClassDefinition\Data[] $container
  783.      * @param CalculatedValue[] $list
  784.      */
  785.     public static function collectCalculatedValueItems($container, &$list = [])
  786.     {
  787.         if (is_array($container)) {
  788.             /** @var DataObject\ClassDefinition\Data $childDef */
  789.             foreach ($container as $childDef) {
  790.                 if ($childDef instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
  791.                     $list[] = $childDef;
  792.                 }
  793.             }
  794.         }
  795.     }
  796.     /**
  797.      * {@inheritdoc}
  798.      */
  799.     public function getParameterTypeDeclaration(): ?string
  800.     {
  801.         return '?\\' Objectbrick::class;
  802.     }
  803.     /**
  804.      * {@inheritdoc}
  805.      */
  806.     public function getReturnTypeDeclaration(): ?string
  807.     {
  808.         return '?\\' Objectbrick::class;
  809.     }
  810.     /**
  811.      * {@inheritdoc}
  812.      */
  813.     public function getPhpdocInputType(): ?string
  814.     {
  815.         return '\\' Objectbrick::class . '|null';
  816.     }
  817.     /**
  818.      * {@inheritdoc}
  819.      */
  820.     public function getPhpdocReturnType(): ?string
  821.     {
  822.         return '\\' Objectbrick::class . '|null';
  823.     }
  824.     /**
  825.      * {@inheritdoc}
  826.      */
  827.     public function normalize($value$params = [])
  828.     {
  829.         if ($value instanceof Objectbrick) {
  830.             $result = [];
  831.             $value $value->getObjectVars();
  832.             /** @var Objectbrick\Data\AbstractData $item */
  833.             foreach ($value as $item) {
  834.                 if (!$item instanceof DataObject\Objectbrick\Data\AbstractData) {
  835.                     continue;
  836.                 }
  837.                 $type $item->getType();
  838.                 $result[$type] = [];
  839.                 $brickDef Objectbrick\Definition::getByKey($type);
  840.                 $fds $brickDef->getFieldDefinitions();
  841.                 foreach ($fds as $fd) {
  842.                     $value $item->{'get' $fd->getName()}();
  843.                     if ($fd instanceof NormalizerInterface) {
  844.                         $result[$type][$fd->getName()] = $fd->normalize($value$params);
  845.                     } else {
  846.                         throw new \Exception($fd->getName() . ' does not implement NormalizerInterface');
  847.                     }
  848.                 }
  849.             }
  850.             return $result;
  851.         }
  852.         return null;
  853.     }
  854.     /**
  855.      * {@inheritdoc}
  856.      */
  857.     public function denormalize($value$params = [])
  858.     {
  859.         if (is_array($value)) {
  860.             $result = [];
  861.             foreach ($value as $key => $v) {
  862.                 $brickDef Objectbrick\Definition::getByKey($key);
  863.                 $fds $brickDef->getFieldDefinitions();
  864.                 $result[$key] = [];
  865.                 foreach ($v as $fieldKey => $fieldValue) {
  866.                     $fd $fds[$fieldKey];
  867.                     if ($fd instanceof NormalizerInterface) {
  868.                         $fieldValue $fd->denormalize($fieldValue$params);
  869.                     }
  870.                     $result[$key][$fieldKey] = $fieldValue;
  871.                 }
  872.             }
  873.             return $result;
  874.         }
  875.         return null;
  876.     }
  877. }