vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data.php line 299

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;
  15. use Pimcore\Db\Helper;
  16. use Pimcore\Model;
  17. use Pimcore\Model\DataObject;
  18. use Pimcore\Model\DataObject\Exception\InheritanceParentNotFoundException;
  19. abstract class Data implements DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface
  20. {
  21.     use DataObject\ClassDefinition\Helper\VarExport;
  22.     /**
  23.      * @var string|null
  24.      */
  25.     public $name;
  26.     /**
  27.      * @var string|null
  28.      */
  29.     public $title;
  30.     /**
  31.      * @var string|null
  32.      */
  33.     public $tooltip;
  34.     /**
  35.      * @var bool
  36.      */
  37.     public $mandatory;
  38.     /**
  39.      * @var bool
  40.      */
  41.     public $noteditable;
  42.     /**
  43.      * @var bool
  44.      */
  45.     public $index;
  46.     /**
  47.      * @var bool
  48.      */
  49.     public $locked false;
  50.     /**
  51.      * @var string
  52.      */
  53.     public $style;
  54.     /**
  55.      * @var array
  56.      */
  57.     public $permissions;
  58.     /**
  59.      * @deprecated Will be removed with Pimcore 11
  60.      *
  61.      * @var string
  62.      */
  63.     public $datatype 'data';
  64.     /**
  65.      * @var string
  66.      */
  67.     public $fieldtype;
  68.     /**
  69.      * @var bool
  70.      */
  71.     public $relationType false;
  72.     /**
  73.      * @var bool
  74.      */
  75.     public $invisible false;
  76.     /**
  77.      * @var bool
  78.      */
  79.     public $visibleGridView true;
  80.     /**
  81.      * @var bool
  82.      */
  83.     public $visibleSearch true;
  84.     /**
  85.      * @var array
  86.      */
  87.     public static $validFilterOperators = [
  88.         'LIKE',
  89.         'NOT LIKE',
  90.         '=',
  91.         'IS',
  92.         'IS NOT',
  93.         '!=',
  94.         '<',
  95.         '>',
  96.         '>=',
  97.         '<=',
  98.     ];
  99.     /**
  100.      * @var array
  101.      */
  102.     protected const FORBIDDEN_NAMES = [
  103.         'id''key''path''type''index''classname''creationdate''userowner''value''class''list',
  104.         'fullpath''childs''children''values''cachetag''cachetags''parent''published''valuefromparent',
  105.         'userpermissions''dependencies''modificationdate''usermodification''byid''bypath''data',
  106.         'versions''properties''permissions''permissionsforuser''childamount''apipluginbroker''resource',
  107.         'parentClass''definition''locked''language''omitmandatorycheck''idpath''object''fieldname',
  108.         'property''parentid''children''scheduledtasks''latestVersion',
  109.     ];
  110.     /**
  111.      * Returns the data for the editmode
  112.      *
  113.      * @param mixed $data
  114.      * @param null|DataObject\AbstractObject $object
  115.      * @param mixed $params
  116.      *
  117.      * @return mixed
  118.      */
  119.     abstract public function getDataForEditmode($data$object null$params = []);
  120.     /**
  121.      * Converts data from editmode to internal eg. Image-Id to Asset\Image object
  122.      *
  123.      * @param mixed $data
  124.      * @param null|DataObject\AbstractObject $object
  125.      * @param mixed $params
  126.      *
  127.      * @return mixed
  128.      */
  129.     abstract public function getDataFromEditmode($data$object null$params = []);
  130.     /**
  131.      * Checks if data is valid for current data field
  132.      *
  133.      * @param mixed $data
  134.      * @param bool $omitMandatoryCheck
  135.      * @param array $params
  136.      *
  137.      * @throws \Exception
  138.      */
  139.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  140.     {
  141.         $isEmpty true;
  142.         // this is to do not treated "0" as empty
  143.         if (is_string($data) || is_numeric($data)) {
  144.             if (strlen($data) > 0) {
  145.                 $isEmpty false;
  146.             }
  147.         }
  148.         if (!empty($data)) {
  149.             $isEmpty false;
  150.         }
  151.         if (!$omitMandatoryCheck && $this->getMandatory() && $isEmpty) {
  152.             throw new Model\Element\ValidationException('Empty mandatory field [ ' $this->getName() . ' ]');
  153.         }
  154.     }
  155.     /**
  156.      * converts object data to a simple string value or CSV Export
  157.      *
  158.      * @internal
  159.      *
  160.      * @param DataObject\Concrete|DataObject\Localizedfield|DataObject\Objectbrick\Data\AbstractData|DataObject\Fieldcollection\Data\AbstractData $object
  161.      * @param array $params
  162.      *
  163.      * @return string
  164.      */
  165.     public function getForCsvExport($object$params = [])
  166.     {
  167.         return $this->getDataFromObjectParam($object$params);
  168.     }
  169.     /**
  170.      * @param DataObject\Concrete|DataObject\Localizedfield|DataObject\Objectbrick\Data\AbstractData|DataObject\Fieldcollection\Data\AbstractData $object
  171.      * @param mixed $params
  172.      *
  173.      * @return string
  174.      */
  175.     public function getDataForSearchIndex($object$params = [])
  176.     {
  177.         // this is the default, but csv doesn't work for all data types
  178.         return $this->getForCsvExport($object$params);
  179.     }
  180.     /**
  181.      * @return string|null
  182.      */
  183.     public function getName()
  184.     {
  185.         return $this->name;
  186.     }
  187.     /**
  188.      * @return string
  189.      */
  190.     public function getTitle()
  191.     {
  192.         return $this->title ?? '';
  193.     }
  194.     /**
  195.      * @return bool
  196.      */
  197.     public function getMandatory()
  198.     {
  199.         return $this->mandatory;
  200.     }
  201.     /**
  202.      * @return array
  203.      */
  204.     public function getPermissions()
  205.     {
  206.         return $this->permissions;
  207.     }
  208.     /**
  209.      * @param string $name
  210.      *
  211.      * @return $this
  212.      */
  213.     public function setName($name)
  214.     {
  215.         $this->name $name;
  216.         return $this;
  217.     }
  218.     /**
  219.      * @param string $title
  220.      *
  221.      * @return $this
  222.      */
  223.     public function setTitle($title)
  224.     {
  225.         $this->title $title;
  226.         return $this;
  227.     }
  228.     /**
  229.      * @param bool $mandatory
  230.      *
  231.      * @return $this
  232.      */
  233.     public function setMandatory($mandatory)
  234.     {
  235.         $this->mandatory = (bool)$mandatory;
  236.         return $this;
  237.     }
  238.     /**
  239.      * @param array $permissions
  240.      *
  241.      * @return $this
  242.      */
  243.     public function setPermissions($permissions)
  244.     {
  245.         $this->permissions $permissions;
  246.         return $this;
  247.     }
  248.     /**
  249.      * @param array $data
  250.      * @param array $blockedKeys
  251.      *
  252.      * @return $this
  253.      */
  254.     public function setValues($data = [], $blockedKeys = [])
  255.     {
  256.         foreach ($data as $key => $value) {
  257.             if (!in_array($key$blockedKeys)) {
  258.                 $method 'set' $key;
  259.                 if (method_exists($this$method)) {
  260.                     $this->$method($value);
  261.                 }
  262.             }
  263.         }
  264.         return $this;
  265.     }
  266.     /**
  267.      * @deprecated Will be removed with Pimcore 11
  268.      *
  269.      * @return string
  270.      */
  271.     public function getDatatype()
  272.     {
  273.         return $this->datatype;
  274.     }
  275.     /**
  276.      * @deprecated Will be removed with Pimcore 11
  277.      *
  278.      * @param string $datatype
  279.      *
  280.      * @return $this
  281.      */
  282.     public function setDatatype($datatype)
  283.     {
  284.         $this->datatype $datatype;
  285.         return $this;
  286.     }
  287.     /**
  288.      * @return string
  289.      */
  290.     public function getFieldtype()
  291.     {
  292.         return $this->fieldtype;
  293.     }
  294.     /**
  295.      * @return bool
  296.      */
  297.     public function getNoteditable()
  298.     {
  299.         return $this->noteditable;
  300.     }
  301.     /**
  302.      * @param bool $noteditable
  303.      *
  304.      * @return $this
  305.      */
  306.     public function setNoteditable($noteditable)
  307.     {
  308.         $this->noteditable = (bool)$noteditable;
  309.         return $this;
  310.     }
  311.     /**
  312.      * @return bool
  313.      */
  314.     public function getIndex()
  315.     {
  316.         return $this->index;
  317.     }
  318.     /**
  319.      * @param bool $index
  320.      *
  321.      * @return $this
  322.      */
  323.     public function setIndex($index)
  324.     {
  325.         $this->index = (bool) $index;
  326.         return $this;
  327.     }
  328.     /**
  329.      *
  330.      * @return string
  331.      */
  332.     public function getStyle()
  333.     {
  334.         return $this->style;
  335.     }
  336.     /**
  337.      * @param string|null $style
  338.      *
  339.      * @return $this
  340.      */
  341.     public function setStyle($style)
  342.     {
  343.         $this->style = (string)$style;
  344.         return $this;
  345.     }
  346.     /**
  347.      *
  348.      * @return bool
  349.      */
  350.     public function getLocked()
  351.     {
  352.         return $this->locked;
  353.     }
  354.     /**
  355.      * @param bool $locked
  356.      *
  357.      * @return $this
  358.      */
  359.     public function setLocked($locked)
  360.     {
  361.         $this->locked = (bool)$locked;
  362.         return $this;
  363.     }
  364.     /**
  365.      *
  366.      * @return string|null
  367.      */
  368.     public function getTooltip()
  369.     {
  370.         return $this->tooltip;
  371.     }
  372.     /**
  373.      * @param string|null $tooltip
  374.      *
  375.      * @return $this
  376.      */
  377.     public function setTooltip($tooltip)
  378.     {
  379.         $this->tooltip = (string)$tooltip;
  380.         return $this;
  381.     }
  382.     /**
  383.      *
  384.      * @return bool
  385.      */
  386.     public function isRelationType()
  387.     {
  388.         return $this->relationType;
  389.     }
  390.     /**
  391.      * @return bool
  392.      */
  393.     public function getInvisible()
  394.     {
  395.         return $this->invisible;
  396.     }
  397.     /**
  398.      * @param bool $invisible
  399.      *
  400.      * @return $this
  401.      */
  402.     public function setInvisible($invisible)
  403.     {
  404.         $this->invisible = (bool)$invisible;
  405.         return $this;
  406.     }
  407.     /**
  408.      * @return bool
  409.      */
  410.     public function getVisibleGridView()
  411.     {
  412.         return $this->visibleGridView;
  413.     }
  414.     /**
  415.      * @param bool $visibleGridView
  416.      *
  417.      * @return $this
  418.      */
  419.     public function setVisibleGridView($visibleGridView)
  420.     {
  421.         $this->visibleGridView = (bool)$visibleGridView;
  422.         return $this;
  423.     }
  424.     /**
  425.      * @return bool
  426.      */
  427.     public function getVisibleSearch()
  428.     {
  429.         return $this->visibleSearch;
  430.     }
  431.     /**
  432.      * @param bool $visibleSearch
  433.      *
  434.      * @return $this
  435.      */
  436.     public function setVisibleSearch($visibleSearch)
  437.     {
  438.         $this->visibleSearch = (bool)$visibleSearch;
  439.         return $this;
  440.     }
  441.     /**
  442.      * @param mixed $data
  443.      * @param array $tags
  444.      *
  445.      * @return array
  446.      */
  447.     public function getCacheTags($data, array $tags = [])
  448.     {
  449.         return $tags;
  450.     }
  451.     /**
  452.      * @param mixed $data
  453.      *
  454.      * @return array
  455.      */
  456.     public function resolveDependencies($data)
  457.     {
  458.         return [];
  459.     }
  460.     /**
  461.      * returns sql query statement to filter according to this data types value(s)
  462.      *
  463.      * @param  mixed $value
  464.      * @param  string $operator
  465.      * @param  mixed $params
  466.      *
  467.      * @return string
  468.      *
  469.      */
  470.     public function getFilterCondition($value$operator$params = [])
  471.     {
  472.         $params['name'] = $this->name;
  473.         return $this->getFilterConditionExt(
  474.             $value,
  475.             $operator,
  476.             $params
  477.         );
  478.     }
  479.     /**
  480.      * returns sql query statement to filter according to this data types value(s)
  481.      *
  482.      * @param mixed $value
  483.      * @param string $operator
  484.      * @param array $params optional params used to change the behavior
  485.      *
  486.      * @return string
  487.      */
  488.     public function getFilterConditionExt($value$operator$params = [])
  489.     {
  490.         if (is_array($value) && empty($value)) {
  491.             return '';
  492.         }
  493.         $db \Pimcore\Db::get();
  494.         $name $params['name'] ?: $this->name;
  495.         $key $db->quoteIdentifier($name);
  496.         if (!empty($params['brickPrefix'])) {
  497.             $key $params['brickPrefix'].$key;
  498.         }
  499.         if ($value === 'NULL') {
  500.             if ($operator === '=') {
  501.                 $operator 'IS';
  502.             } elseif ($operator === '!=') {
  503.                 $operator 'IS NOT';
  504.             }
  505.         } elseif (!is_array($value) && !is_object($value)) {
  506.             if ($operator === 'LIKE') {
  507.                 $value $db->quote('%' $value '%');
  508.             } else {
  509.                 $value $db->quote($value);
  510.             }
  511.         }
  512.         if (in_array($operatorDataObject\ClassDefinition\Data::$validFilterOperators)) {
  513.             $trailer '';
  514.             //the db interprets 0 as NULL -> if empty (0) is selected in the filter, we must also filter for NULL
  515.             if ($value === '\'0\'' || is_array($value) && in_array(0$value)) {
  516.                 $trailer ' OR ' $key ' IS NULL';
  517.             }
  518.             if (str_contains($name'cskey') && is_array($value) && !empty($value)) {
  519.                 $values array_map(function ($val) use ($db) {
  520.                     return $db->quote(Helper::escapeLike($val));
  521.                 }, $value);
  522.                 return $key ' ' $operator ' ' implode(' OR ' $key ' ' $operator ' '$values) . $trailer;
  523.             }
  524.             return $key ' ' $operator ' ' $value ' ' $trailer;
  525.         }
  526.         return '';
  527.     }
  528.     /**
  529.      * @param string $key
  530.      *
  531.      * @return string
  532.      */
  533.     protected function getPreGetValueHookCode(string $key): string
  534.     {
  535.         $code "\t" 'if ($this instanceof PreGetValueHookInterface && !\Pimcore::inAdmin()) {' "\n";
  536.         $code .= "\t\t" '$preValue = $this->preGetValue("' $key '");' "\n";
  537.         $code .= "\t\t" 'if ($preValue !== null) {' "\n";
  538.         $code .= "\t\t\t" 'return $preValue;' "\n";
  539.         $code .= "\t\t" '}' "\n";
  540.         $code .= "\t" '}' "\n\n";
  541.         return $code;
  542.     }
  543.     /**
  544.      * Creates getter code which is used for generation of php file for object classes using this data type
  545.      *
  546.      * @param DataObject\ClassDefinition|DataObject\Objectbrick\Definition|DataObject\Fieldcollection\Definition $class
  547.      *
  548.      * @return string
  549.      */
  550.     public function getGetterCode($class)
  551.     {
  552.         $key $this->getName();
  553.         if ($class->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getReturnTypeDeclaration()) {
  554.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  555.         } else {
  556.             $typeDeclaration '';
  557.         }
  558.         $code '/**' "\n";
  559.         $code .= '* Get ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  560.         $code .= '* @return ' $this->getPhpdocReturnType() . "\n";
  561.         $code .= '*/' "\n";
  562.         $code .= 'public function get' ucfirst($key) . '()' $typeDeclaration "\n";
  563.         $code .= '{' "\n";
  564.         $code .= $this->getPreGetValueHookCode($key);
  565.         //TODO Pimcore 11: remove method_exists BC layer
  566.         if ($this instanceof DataObject\ClassDefinition\Data\PreGetDataInterface ||method_exists($this'preGetData')) {
  567.             $code .= "\t" '$data = $this->getClass()->getFieldDefinition("' $key '")->preGetData($this);' "\n\n";
  568.         } else {
  569.             $code .= "\t" '$data = $this->' $key ";\n\n";
  570.         }
  571.         // insert this line if inheritance from parent objects is allowed
  572.         if ($class instanceof DataObject\ClassDefinition && $class->getAllowInherit() && $this->supportsInheritance()) {
  573.             $code .= "\t" 'if (\Pimcore\Model\DataObject::doGetInheritedValues() && $this->getClass()->getFieldDefinition("' $key '")->isEmpty($data)) {' "\n";
  574.             $code .= "\t\t" 'try {' "\n";
  575.             $code .= "\t\t\t" 'return $this->getValueFromParent("' $key '");' "\n";
  576.             $code .= "\t\t" '} catch (InheritanceParentNotFoundException $e) {' "\n";
  577.             $code .= "\t\t\t" '// no data from parent available, continue ...' "\n";
  578.             $code .= "\t\t" '}' "\n";
  579.             $code .= "\t" '}' "\n\n";
  580.         }
  581.         $code .= "\t" 'if ($data instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField) {' "\n";
  582.         $code .= "\t\t" 'return $data->getPlain();' "\n";
  583.         $code .= "\t" '}' "\n\n";
  584.         $code .= "\t" 'return $data;' "\n";
  585.         $code .= "}\n\n";
  586.         return $code;
  587.     }
  588.     /**
  589.      * Creates setter code which is used for generation of php file for object classes using this data type
  590.      *
  591.      * @param DataObject\ClassDefinition|DataObject\Objectbrick\Definition|DataObject\Fieldcollection\Definition $class
  592.      *
  593.      * @return string
  594.      */
  595.     public function getSetterCode($class)
  596.     {
  597.         if ($class instanceof DataObject\Objectbrick\Definition) {
  598.             $classname 'Objectbrick\\Data\\' ucfirst($class->getKey());
  599.         } elseif ($class instanceof DataObject\Fieldcollection\Definition) {
  600.             $classname 'Fieldcollection\\Data\\' ucfirst($class->getKey());
  601.         } else {
  602.             $classname $class->getName();
  603.         }
  604.         $key $this->getName();
  605.         if ($class->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getParameterTypeDeclaration()) {
  606.             $typeDeclaration $this->getParameterTypeDeclaration() . ' ';
  607.         } else {
  608.             $typeDeclaration '';
  609.         }
  610.         $code '/**' "\n";
  611.         $code .= '* Set ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  612.         $code .= '* @param ' $this->getPhpdocInputType() . ' $' $key "\n";
  613.         $code .= '* @return \\Pimcore\\Model\\DataObject\\' ucfirst($classname) . "\n";
  614.         $code .= '*/' "\n";
  615.         $code .= 'public function set' ucfirst($key) . '(' $typeDeclaration '$' $key ')' "\n";
  616.         $code .= '{' "\n";
  617.         if (
  618.             (
  619.                 $this->supportsDirtyDetection() &&
  620.                 $this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface
  621.             ) || method_exists($this'preSetData')
  622.         ) {
  623.             $code .= "\t" '/** @var \\' . static::class . ' $fd */' "\n";
  624.             $code .= "\t" '$fd = $this->getClass()->getFieldDefinition("' $key '");' "\n";
  625.         }
  626.         if ($this instanceof DataObject\ClassDefinition\Data\EncryptedField) {
  627.             if ($this->getDelegate()) {
  628.                 $code .= "\t" '$encryptedFd = $this->getClass()->getFieldDefinition("' $key '");' "\n";
  629.                 $code .= "\t" '$delegate = $encryptedFd->getDelegate();' "\n";
  630.                 $code .= "\t" 'if ($delegate && !($' $key ' instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField)) {' "\n";
  631.                 $code .= "\t\t" '$' $key ' = new \\Pimcore\\Model\\DataObject\\Data\\EncryptedField($delegate, $' $key ');' "\n";
  632.                 $code .= "\t" '}' "\n";
  633.             }
  634.         }
  635.         if ($this->supportsDirtyDetection()) {
  636.             if ($class instanceof DataObject\ClassDefinition && $class->getAllowInherit()) {
  637.                 $code .= "\t" '$inheritValues = self::getGetInheritedValues();'."\n";
  638.                 $code .= "\t" 'self::setGetInheritedValues(false);'."\n";
  639.             }
  640.             $code .= "\t" '$hideUnpublished = \\Pimcore\\Model\\DataObject\\Concrete::getHideUnpublished();' "\n";
  641.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished(false);' "\n";
  642.             $code .= "\t" '$currentData = $this->get' ucfirst($this->getName()) . '();' "\n";
  643.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished($hideUnpublished);' "\n";
  644.             if ($class instanceof DataObject\ClassDefinition && $class->getAllowInherit()) {
  645.                 $code .= "\t" 'self::setGetInheritedValues($inheritValues);'."\n";
  646.             }
  647.             if ($this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface) {
  648.                 $code .= "\t" '$isEqual = $fd->isEqual($currentData, $' $key ');' "\n";
  649.                 $code .= "\t" 'if (!$isEqual) {' "\n";
  650.                 $code .= "\t\t" '$this->markFieldDirty("' $key '", true);' "\n";
  651.                 $code .= "\t" '}' "\n";
  652.             } else {
  653.                 $code .= "\t" '$this->markFieldDirty("' $key '", true);' "\n";
  654.             }
  655.         }
  656.         //TODO Pimcore 11: remove method_exists BC layer
  657.         if ($this instanceof DataObject\ClassDefinition\Data\PreSetDataInterface || method_exists($this'preSetData')) {
  658.             $code .= "\t" '$this->' $key ' = ' '$fd->preSetData($this, $' $key ');' "\n";
  659.         } else {
  660.             $code .= "\t" '$this->' $key ' = ' '$' $key ";\n\n";
  661.         }
  662.         $code .= "\t" 'return $this;' "\n";
  663.         $code .= "}\n\n";
  664.         return $code;
  665.     }
  666.     /**
  667.      * Creates getter code which is used for generation of php file for object brick classes using this data type
  668.      *
  669.      * @param DataObject\Objectbrick\Definition $brickClass
  670.      *
  671.      * @return string
  672.      */
  673.     public function getGetterCodeObjectbrick($brickClass)
  674.     {
  675.         $key $this->getName();
  676.         if ($brickClass->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getReturnTypeDeclaration()) {
  677.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  678.         } else {
  679.             $typeDeclaration '';
  680.         }
  681.         $code '';
  682.         $code .= '/**' "\n";
  683.         $code .= '* Get ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  684.         $code .= '* @return ' $this->getPhpdocReturnType() . "\n";
  685.         $code .= '*/' "\n";
  686.         $code .= 'public function get' ucfirst($key) . '()' $typeDeclaration "\n";
  687.         $code .= '{' "\n";
  688.         //TODO Pimcore 11: remove method_exists BC layer
  689.         if ($this instanceof DataObject\ClassDefinition\Data\PreGetDataInterface ||method_exists($this'preGetData')) {
  690.             $code .= "\t" '$data = $this->getDefinition()->getFieldDefinition("' $key '")->preGetData($this);' "\n";
  691.         } else {
  692.             $code .= "\t" '$data = $this->' $key ";\n";
  693.         }
  694.         if ($this->supportsInheritance()) {
  695.             $code .= "\t" 'if(\Pimcore\Model\DataObject::doGetInheritedValues($this->getObject()) && $this->getDefinition()->getFieldDefinition("' $key '")->isEmpty($data)) {' "\n";
  696.             $code .= "\t\t" 'try {' "\n";
  697.             $code .= "\t\t\t" 'return $this->getValueFromParent("' $key '");' "\n";
  698.             $code .= "\t\t" '} catch (InheritanceParentNotFoundException $e) {' "\n";
  699.             $code .= "\t\t\t" '// no data from parent available, continue ...' "\n";
  700.             $code .= "\t\t" '}' "\n";
  701.             $code .= "\t" '}' "\n";
  702.         }
  703.         $code .= "\t" 'if ($data instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField) {' "\n";
  704.         $code .= "\t\t" 'return $data->getPlain();' "\n";
  705.         $code .= "\t" '}' "\n\n";
  706.         $code .= "\t" 'return $data;' "\n";
  707.         $code .= "}\n\n";
  708.         return $code;
  709.     }
  710.     /**
  711.      * Creates setter code which is used for generation of php file for object brick classes using this data type
  712.      *
  713.      * @param DataObject\Objectbrick\Definition $brickClass
  714.      *
  715.      * @return string
  716.      */
  717.     public function getSetterCodeObjectbrick($brickClass)
  718.     {
  719.         $key $this->getName();
  720.         if ($brickClass->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getParameterTypeDeclaration()) {
  721.             $typeDeclaration $this->getParameterTypeDeclaration() . ' ';
  722.         } else {
  723.             $typeDeclaration '';
  724.         }
  725.         $code '/**' "\n";
  726.         $code .= '* Set ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  727.         $code .= '* @param ' $this->getPhpdocInputType() . ' $' $key "\n";
  728.         $code .= '* @return \\Pimcore\\Model\\DataObject\\Objectbrick\\Data\\' ucfirst($brickClass->getKey()) . "\n";
  729.         $code .= '*/' "\n";
  730.         $code .= 'public function set' ucfirst($key) . ' (' $typeDeclaration '$' $key ')' "\n";
  731.         $code .= '{' "\n";
  732.         if (
  733.             (
  734.                 $this->supportsDirtyDetection() &&
  735.                 $this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface
  736.             ) || method_exists($this'preSetData')
  737.         ) {
  738.             $code .= "\t" '/** @var \\' . static::class . ' $fd */' "\n";
  739.             $code .= "\t" '$fd = $this->getDefinition()->getFieldDefinition("' $key '");' "\n";
  740.         }
  741.         if ($this instanceof DataObject\ClassDefinition\Data\EncryptedField) {
  742.             if ($this->getDelegate()) {
  743.                 $code .= "\t" '/** @var \\' . static::class . ' $encryptedFd */' "\n";
  744.                 $code .= "\t" '$encryptedFd = $this->getDefinition()->getFieldDefinition("' $key '");' "\n";
  745.                 $code .= "\t" '$delegate = $encryptedFd->getDelegate();' "\n";
  746.                 $code .= "\t" 'if ($delegate && !($' $key ' instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField)) {' "\n";
  747.                 $code .= "\t\t" '$' $key ' = new \\Pimcore\\Model\\DataObject\\Data\\EncryptedField($delegate, $' $key ');' "\n";
  748.                 $code .= "\t" '}' "\n";
  749.             }
  750.         }
  751.         if ($this->supportsDirtyDetection()) {
  752.             $code .= "\t" '$class = $this->getObject() ? $this->getObject()->getClass() : null;' "\n";
  753.             $code .= "\t" 'if ($class && $class->getAllowInherit()) {' "\n";
  754.             $code .= "\t\t" '$inheritValues = $this->getObject()::getGetInheritedValues();'."\n";
  755.             $code .= "\t\t" '$this->getObject()::setGetInheritedValues(false);'."\n";
  756.             $code .= "\t" '}'."\n";
  757.             $code .= "\t" '$hideUnpublished = \\Pimcore\\Model\\DataObject\\Concrete::getHideUnpublished();' "\n";
  758.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished(false);' "\n";
  759.             $code .= "\t" '$currentData = $this->get' ucfirst($this->getName()) . '();' "\n";
  760.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished($hideUnpublished);' "\n";
  761.             $code .= "\t" 'if($class && $class->getAllowInherit()) {' "\n";
  762.             $code .= "\t\t" '$this->getObject()::setGetInheritedValues($inheritValues);'."\n";
  763.             $code .= "\t" '}' "\n";
  764.             if ($this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface) {
  765.                 $code .= "\t" '$isEqual = $fd->isEqual($currentData, $' $key ');' "\n";
  766.                 $code .= "\t" 'if (!$isEqual) {' "\n";
  767.                 $code .= "\t\t" '$this->markFieldDirty("' $key '", true);' "\n";
  768.                 $code .= "\t" '}' "\n";
  769.             } else {
  770.                 $code .= "\t" '$this->markFieldDirty("' $key '", true);' "\n";
  771.             }
  772.         }
  773.         //TODO Pimcore 11: remove method_exists BC layer
  774.         if ($this instanceof DataObject\ClassDefinition\Data\PreSetDataInterface || method_exists($this'preSetData')) {
  775.             $code .= "\t" '$this->' $key ' = ' '$fd->preSetData($this, $' $key ');' "\n";
  776.         } else {
  777.             $code .= "\t" '$this->' $key ' = ' '$' $key ";\n\n";
  778.         }
  779.         $code .= "\t" 'return $this;' "\n";
  780.         $code .= "}\n\n";
  781.         return $code;
  782.     }
  783.     /**
  784.      * Creates getter code which is used for generation of php file for fieldcollectionk classes using this data type
  785.      *
  786.      * @param DataObject\Fieldcollection\Definition $fieldcollectionDefinition
  787.      *
  788.      * @return string
  789.      */
  790.     public function getGetterCodeFieldcollection($fieldcollectionDefinition)
  791.     {
  792.         $key $this->getName();
  793.         if ($fieldcollectionDefinition->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getReturnTypeDeclaration()) {
  794.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  795.         } else {
  796.             $typeDeclaration '';
  797.         }
  798.         $code '/**' "\n";
  799.         $code .= '* Get ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  800.         $code .= '* @return ' $this->getPhpdocReturnType() . "\n";
  801.         $code .= '*/' "\n";
  802.         $code .= 'public function get' ucfirst($key) . '()' $typeDeclaration "\n";
  803.         $code .= '{' "\n";
  804.         //TODO Pimcore 11: remove method_exists BC layer
  805.         if ($this instanceof DataObject\ClassDefinition\Data\PreGetDataInterface || method_exists($this'preGetData')) {
  806.             $code .= "\t" '$container = $this;' "\n";
  807.             $code .= "\t" '/** @var \\' . static::class . ' $fd */' "\n";
  808.             $code .= "\t" '$fd = $this->getDefinition()->getFieldDefinition("' $key '");' "\n";
  809.             $code .= "\t" '$data = $fd->preGetData($container);' "\n";
  810.         } else {
  811.             $code .= "\t" '$data = $this->' $key ";\n";
  812.         }
  813.         $code .= "\t" 'if ($data instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField) {' "\n";
  814.         $code .= "\t\t" 'return $data->getPlain();' "\n";
  815.         $code .= "\t" '}' "\n\n";
  816.         $code .= "\t" 'return $data;' "\n";
  817.         $code .= "}\n\n";
  818.         return $code;
  819.     }
  820.     /**
  821.      * Creates setter code which is used for generation of php file for fieldcollection classes using this data type
  822.      *
  823.      * @param DataObject\Fieldcollection\Definition $fieldcollectionDefinition
  824.      *
  825.      * @return string
  826.      */
  827.     public function getSetterCodeFieldcollection($fieldcollectionDefinition)
  828.     {
  829.         $key $this->getName();
  830.         if ($fieldcollectionDefinition->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getParameterTypeDeclaration()) {
  831.             $typeDeclaration $this->getParameterTypeDeclaration() . ' ';
  832.         } else {
  833.             $typeDeclaration '';
  834.         }
  835.         $code '/**' "\n";
  836.         $code .= '* Set ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  837.         $code .= '* @param ' $this->getPhpdocInputType() . ' $' $key "\n";
  838.         $code .= '* @return \\Pimcore\\Model\\DataObject\\Fieldcollection\\Data\\' ucfirst($fieldcollectionDefinition->getKey()) . "\n";
  839.         $code .= '*/' "\n";
  840.         $code .= 'public function set' ucfirst($key) . '(' $typeDeclaration '$' $key ')' "\n";
  841.         $code .= '{' "\n";
  842.         if (
  843.             (
  844.                 $this->supportsDirtyDetection() &&
  845.                 $this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface
  846.             ) || method_exists($this'preSetData')
  847.         ) {
  848.             $code .= "\t" '/** @var \\' . static::class . ' $fd */' "\n";
  849.             $code .= "\t" '$fd = $this->getDefinition()->getFieldDefinition("' $key '");' "\n";
  850.         }
  851.         if ($this instanceof DataObject\ClassDefinition\Data\EncryptedField) {
  852.             if ($this->getDelegate()) {
  853.                 $code .= "\t" '/** @var \\' . static::class . ' $encryptedFd */' "\n";
  854.                 $code .= "\t" '$encryptedFd = $this->getDefinition()->getFieldDefinition("' $key '");' "\n";
  855.                 $code .= "\t" '$delegate = $encryptedFd->getDelegate();' "\n";
  856.                 $code .= "\t" 'if ($delegate && !($' $key ' instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField)) {' "\n";
  857.                 $code .= "\t\t" '$' $key ' = new \\Pimcore\\Model\\DataObject\\Data\\EncryptedField($delegate, $' $key ');' "\n";
  858.                 $code .= "\t" '}' "\n";
  859.             }
  860.         }
  861.         if ($this->supportsDirtyDetection()) {
  862.             $code .= "\t" '$hideUnpublished = \\Pimcore\\Model\\DataObject\\Concrete::getHideUnpublished();' "\n";
  863.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished(false);' "\n";
  864.             $code .= "\t" '$currentData = $this->get' ucfirst($this->getName()) . '();' "\n";
  865.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished($hideUnpublished);' "\n";
  866.             if ($this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface) {
  867.                 $code .= "\t" '$isEqual = $fd->isEqual($currentData, $' $key ');' "\n";
  868.                 $code .= "\t" 'if (!$isEqual) {' "\n";
  869.                 $code .= "\t\t" '$this->markFieldDirty("' $key '", true);' "\n";
  870.                 $code .= "\t" '}' "\n";
  871.             } else {
  872.                 $code .= "\t" '$this->markFieldDirty("' $key '", true);' "\n";
  873.             }
  874.         }
  875.         //TODO Pimcore 11: remove method_exists BC layer
  876.         if ($this instanceof DataObject\ClassDefinition\Data\PreSetDataInterface || method_exists($this'preSetData')) {
  877.             $code .= "\t" '$this->' $key ' = ' '$fd->preSetData($this, $' $key ');' "\n";
  878.         } else {
  879.             $code .= "\t" '$this->' $key ' = ' '$' $key ";\n\n";
  880.         }
  881.         $code .= "\t" 'return $this;' "\n";
  882.         $code .= "}\n\n";
  883.         return $code;
  884.     }
  885.     /**
  886.      * Creates getter code which is used for generation of php file for localized fields in classes using this data type
  887.      *
  888.      * @param DataObject\ClassDefinition|DataObject\Objectbrick\Definition|DataObject\Fieldcollection\Definition $class
  889.      *
  890.      * @return string
  891.      */
  892.     public function getGetterCodeLocalizedfields($class)
  893.     {
  894.         $key $this->getName();
  895.         if ($class->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getReturnTypeDeclaration()) {
  896.             $typeDeclaration ': ' $this->getReturnTypeDeclaration();
  897.         } else {
  898.             $typeDeclaration '';
  899.         }
  900.         $code '/**' "\n";
  901.         $code .= '* Get ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  902.         $code .= '* @return ' $this->getPhpdocReturnType() . "\n";
  903.         $code .= '*/' "\n";
  904.         $code .= 'public function get' ucfirst($key) . '($language = null)' $typeDeclaration "\n";
  905.         $code .= '{' "\n";
  906.         $code .= "\t" '$data = $this->getLocalizedfields()->getLocalizedValue("' $key '", $language);' "\n";
  907.         if (!$class instanceof DataObject\Fieldcollection\Definition) {
  908.             $code .= $this->getPreGetValueHookCode($key);
  909.         }
  910.         $code .= "\t" 'if ($data instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField) {' "\n";
  911.         $code .= "\t\t" 'return $data->getPlain();' "\n";
  912.         $code .= "\t" '}' "\n\n";
  913.         // we don't need to consider preGetData, because this is already managed directly by the localized fields within getLocalizedValue()
  914.         $code .= "\t" 'return $data;' "\n";
  915.         $code .= "}\n\n";
  916.         return $code;
  917.     }
  918.     /**
  919.      * Creates setter code which is used for generation of php file for localized fields in classes using this data type
  920.      *
  921.      * @param DataObject\ClassDefinition|DataObject\Objectbrick\Definition|DataObject\Fieldcollection\Definition $class
  922.      *
  923.      * @return string
  924.      */
  925.     public function getSetterCodeLocalizedfields($class)
  926.     {
  927.         $key $this->getName();
  928.         if ($class instanceof DataObject\Objectbrick\Definition) {
  929.             $classname 'Objectbrick\\Data\\' ucfirst($class->getKey());
  930.             $containerGetter 'getDefinition';
  931.         } elseif ($class instanceof DataObject\Fieldcollection\Definition) {
  932.             $classname 'Fieldcollection\\Data\\' ucfirst($class->getKey());
  933.             $containerGetter 'getDefinition';
  934.         } else {
  935.             $classname $class->getName();
  936.             $containerGetter 'getClass';
  937.         }
  938.         if ($class->getGenerateTypeDeclarations() && $this instanceof DataObject\ClassDefinition\Data\TypeDeclarationSupportInterface && $this->getParameterTypeDeclaration()) {
  939.             $typeDeclaration $this->getParameterTypeDeclaration() . ' ';
  940.         } else {
  941.             $typeDeclaration '';
  942.         }
  943.         $code '/**' "\n";
  944.         $code .= '* Set ' str_replace(['/**''*/''//'], ''$this->getName()) . ' - ' str_replace(['/**''*/''//'], ''$this->getTitle()) . "\n";
  945.         $code .= '* @param ' $this->getPhpdocInputType() . ' $' $key "\n";
  946.         $code .= '* @return \\Pimcore\\Model\\DataObject\\' ucfirst($classname) . "\n";
  947.         $code .= '*/' "\n";
  948.         $code .= 'public function set' ucfirst($key) . ' (' $typeDeclaration '$' $key ', $language = null)' "\n";
  949.         $code .= '{' "\n";
  950.         if ($this->supportsDirtyDetection()) {
  951.             $code .= "\t" '$fd = $this->' $containerGetter '()->getFieldDefinition("localizedfields")->getFieldDefinition("' $key '");' "\n";
  952.         }
  953.         if ($this instanceof DataObject\ClassDefinition\Data\EncryptedField) {
  954.             if ($this->getDelegate()) {
  955.                 $code .= "\t" '$encryptedFd = $this->getClass()->getFieldDefinition("' $key '");' "\n";
  956.                 $code .= "\t" '$delegate = $encryptedFd->getDelegate();' "\n";
  957.                 $code .= "\t" 'if ($delegate && !($' $key ' instanceof \\Pimcore\\Model\\DataObject\\Data\\EncryptedField)) {' "\n";
  958.                 $code .= "\t\t" '$' $key ' = new \\Pimcore\\Model\\DataObject\\Data\\EncryptedField($delegate, $' $key ');' "\n";
  959.                 $code .= "\t" '}' "\n";
  960.             }
  961.         }
  962.         if ($this->supportsDirtyDetection()) {
  963.             if ($class instanceof DataObject\ClassDefinition && $class->getAllowInherit()) {
  964.                 $code .= "\t" '$inheritValues = self::getGetInheritedValues();'."\n";
  965.                 $code .= "\t" 'self::setGetInheritedValues(false);'."\n";
  966.             }
  967.             $code .= "\t" '$hideUnpublished = \\Pimcore\\Model\\DataObject\\Concrete::getHideUnpublished();' "\n";
  968.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished(false);' "\n";
  969.             $code .= "\t" '$currentData = $this->get' ucfirst($this->getName()) . '($language);' "\n";
  970.             $code .= "\t" '\\Pimcore\\Model\\DataObject\\Concrete::setHideUnpublished($hideUnpublished);' "\n";
  971.             if ($class instanceof DataObject\ClassDefinition && $class->getAllowInherit()) {
  972.                 $code .= "\t" 'self::setGetInheritedValues($inheritValues);'."\n";
  973.             }
  974.             if ($this instanceof DataObject\ClassDefinition\Data\EqualComparisonInterface) {
  975.                 $code .= "\t" '$isEqual = $fd->isEqual($currentData, $' $key ');' "\n";
  976.             } else {
  977.                 $code .= "\t" '$isEqual = false;' "\n";
  978.             }
  979.             $code .= "\t" 'if (!$isEqual) {' "\n";
  980.             $code .= "\t\t" '$this->markFieldDirty("' $key '", true);' "\n";
  981.             $code .= "\t" '}' "\n";
  982.         } else {
  983.             $code .= "\t" '$isEqual = false;' "\n";
  984.         }
  985.         $code .= "\t" '$this->getLocalizedfields()->setLocalizedValue("' $key '", $' $key ', $language, !$isEqual)' ";\n\n";
  986.         $code .= "\t" 'return $this;' "\n";
  987.         $code .= "}\n\n";
  988.         return $code;
  989.     }
  990.     /**
  991.      * Creates filter method code for listing classes
  992.      *
  993.      * @return string
  994.      */
  995.     public function getFilterCode()
  996.     {
  997.         $key $this->getName();
  998.         $code '/**' "\n";
  999.         $code .= '* Filter by ' str_replace(['/**''*/''//'], ''$key) . ' (' str_replace(['/**''*/''//'], ''$this->getTitle()) . ")\n";
  1000.         $dataParamDoc 'mixed $data';
  1001.         $reflectionMethod = new \ReflectionMethod($this'addListingFilter');
  1002.         $docComment $reflectionMethod->getDocComment();
  1003.         if ($docComment && preg_match('/@param\s+([^\s]+)\s+\$data(.*)/'$docComment$dataParam)) {
  1004.             $dataParamDoc $dataParam[1].' $data '.$dataParam[2];
  1005.         }
  1006.         $operatorParamDoc 'string $operator SQL comparison operator, e.g. =, <, >= etc. You can use "?" as placeholder, e.g. "IN (?)"';
  1007.         if ($docComment && preg_match('/@param\s+([^\s]+)\s+\$operator(.*)/'$docComment$dataParam)) {
  1008.             $operatorParamDoc $dataParam[1].' $operator '.$dataParam[2];
  1009.         }
  1010.         $code .= '* @param '.$dataParamDoc."\n";
  1011.         $code .= '* @param '.$operatorParamDoc."\n";
  1012.         $code .= '* @return static'."\n";
  1013.         $code .= '*/' "\n";
  1014.         $code .= 'public function filterBy' ucfirst($key) .' ($data, $operator = \'=\')' "\n";
  1015.         $code .= '{' "\n";
  1016.         $code .= "\t" '$this->getClass()->getFieldDefinition("' $key '")->addListingFilter($this, $data, $operator);' "\n";
  1017.         $code .= "\treturn " '$this' ";\n";
  1018.         $code .= "}\n\n";
  1019.         return $code;
  1020.     }
  1021.     /**
  1022.      * @param mixed $number
  1023.      *
  1024.      * @return int|null
  1025.      */
  1026.     public function getAsIntegerCast($number)
  1027.     {
  1028.         return strlen((string) $number) === null : (int)$number;
  1029.     }
  1030.     /**
  1031.      * @param mixed $number
  1032.      *
  1033.      * @return float|null
  1034.      */
  1035.     public function getAsFloatCast($number)
  1036.     {
  1037.         return strlen((string) $number) === null : (float)$number;
  1038.     }
  1039.     /**
  1040.      * @param mixed $data
  1041.      * @param DataObject\Concrete|null $object
  1042.      * @param mixed $params
  1043.      *
  1044.      * @return string
  1045.      */
  1046.     public function getVersionPreview($data$object null$params = [])
  1047.     {
  1048.         return 'no preview';
  1049.     }
  1050.     /**
  1051.      * @param mixed $data
  1052.      *
  1053.      * @return bool
  1054.      */
  1055.     public function isEmpty($data)
  1056.     {
  1057.         return empty($data);
  1058.     }
  1059.     /** True if change is allowed in edit mode.
  1060.      * @param DataObject\Concrete $object
  1061.      * @param mixed $params
  1062.      *
  1063.      * @return bool
  1064.      */
  1065.     public function isDiffChangeAllowed($object$params = [])
  1066.     {
  1067.         return false;
  1068.     }
  1069.     /** Converts the data sent from the object merger back to the internal object. Similar to
  1070.      * getDiffDataForEditMode() an array of data elements is passed in containing the following attributes:
  1071.      *  - "field" => the name of (this) field
  1072.      *  - "key" => the key of the data element
  1073.      *  - "data" => the data
  1074.      *
  1075.      * @param array $data
  1076.      * @param DataObject\Concrete|null $object
  1077.      * @param mixed $params
  1078.      *
  1079.      * @return mixed
  1080.      */
  1081.     public function getDiffDataFromEditmode($data$object null$params = [])
  1082.     {
  1083.         $thedata $this->getDataFromEditmode($data[0]['data'], $object$params);
  1084.         return $thedata;
  1085.     }
  1086.     /**
  1087.      * Returns the data for the editmode in the format expected by the object merger plugin.
  1088.      * The return value is a list of data definitions containing the following attributes:
  1089.      *      - "field" => the name of the object field
  1090.      *      - "key" => a unique key identifying the data element
  1091.      *      - "type" => the type of the data component
  1092.      *      - "value" => the value used as preview
  1093.      *      - "data" => the actual data which is then sent back again by the editor. Note that the data is opaque
  1094.      *                          and will not be touched by the editor in any way.
  1095.      *      - "disabled" => whether the data element can be edited or not
  1096.      *      - "title" => pretty name describing the data element
  1097.      *
  1098.      *
  1099.      * @param mixed $data
  1100.      * @param DataObject\Concrete|null $object
  1101.      * @param mixed $params
  1102.      *
  1103.      * @return null|array
  1104.      */
  1105.     public function getDiffDataForEditMode($data$object null$params = [])
  1106.     {
  1107.         $diffdata = [];
  1108.         $diffdata['data'] = $this->getDataForEditmode($data$object$params);
  1109.         $diffdata['disabled'] = !($this->isDiffChangeAllowed($object));
  1110.         $diffdata['field'] = $this->getName();
  1111.         $diffdata['key'] = $this->getName();
  1112.         $diffdata['type'] = $this->fieldtype;
  1113.         if (method_exists($this'getDiffVersionPreview')) {
  1114.             $value $this->getDiffVersionPreview($data$object$params);
  1115.         } else {
  1116.             $value $this->getVersionPreview($data$object$params);
  1117.         }
  1118.         $diffdata['title'] = !empty($this->title) ? $this->title $this->name;
  1119.         $diffdata['value'] = $value;
  1120.         $result = [];
  1121.         $result[] = $diffdata;
  1122.         return $result;
  1123.     }
  1124.     /**
  1125.      * @return bool
  1126.      */
  1127.     public function getUnique()
  1128.     {
  1129.         return false;
  1130.     }
  1131.     /**
  1132.      * @param DataObject\Concrete|DataObject\Localizedfield|DataObject\Objectbrick\Data\AbstractData|DataObject\Fieldcollection\Data\AbstractData $object
  1133.      * @param array $params
  1134.      *
  1135.      * @return mixed
  1136.      *
  1137.      * @throws \Exception
  1138.      */
  1139.     protected function getDataFromObjectParam($object$params = [])
  1140.     {
  1141.         $data null;
  1142.         if (array_key_exists('injectedData'$params)) {
  1143.             return $params['injectedData'];
  1144.         }
  1145.         $context $params['context'] ?? null;
  1146.         if (isset($context['containerType'])) {
  1147.             if ($context['containerType'] === 'fieldcollection' || $context['containerType'] === 'block') {
  1148.                 if ($this instanceof DataObject\ClassDefinition\Data\Localizedfields || $object instanceof DataObject\Localizedfield) {
  1149.                     $fieldname $context['fieldname'];
  1150.                     $index $context['index'] ?? null;
  1151.                     if ($object instanceof DataObject\Concrete) {
  1152.                         $containerGetter 'get' ucfirst($fieldname);
  1153.                         $container $object->$containerGetter();
  1154.                         if (!$container && $context['containerType'] === 'block') {
  1155.                             // no data, so check if inheritance is enabled + there is parent value
  1156.                             if ($object->getClass()->getAllowInherit()) {
  1157.                                 try {
  1158.                                     $container $object->getValueFromParent($fieldname);
  1159.                                 } catch (InheritanceParentNotFoundException $e) {
  1160.                                     //nothing to do here - just no parent data available
  1161.                                 }
  1162.                             }
  1163.                         }
  1164.                         if ($container) {
  1165.                             $originalIndex $context['oIndex'] ?? null;
  1166.                             // field collection or block items
  1167.                             if ($originalIndex !== null) {
  1168.                                 if ($context['containerType'] === 'block') {
  1169.                                     $items $container;
  1170.                                 } else {
  1171.                                     $items $container->getItems();
  1172.                                 }
  1173.                                 if ($items && (count($items) > $originalIndex || count($items) > --$originalIndex)) {
  1174.                                     $item $items[$originalIndex];
  1175.                                     if ($context['containerType'] === 'block') {
  1176.                                         $data $item[$this->getName()] ?? null;
  1177.                                         if ($data instanceof DataObject\Data\BlockElement) {
  1178.                                             $data $data->getData();
  1179.                                             return $data;
  1180.                                         }
  1181.                                     } else {
  1182.                                         $getter 'get' ucfirst($this->getName());
  1183.                                         $data $item->$getter();
  1184.                                     }
  1185.                                     return $data;
  1186.                                 }
  1187.                                 throw new \Exception('object seems to be modified, item with orginal index ' $originalIndex ' not found, new index: ' $index);
  1188.                             } else {
  1189.                                 return null;
  1190.                             }
  1191.                         } else {
  1192.                             return null;
  1193.                         }
  1194.                     } elseif ($object instanceof DataObject\Localizedfield) {
  1195.                         $data $object->getLocalizedValue($this->getName(), $params['language'], true);
  1196.                         return $data;
  1197.                     }
  1198.                 }
  1199.             } elseif ($context['containerType'] === 'objectbrick' && ($this instanceof DataObject\ClassDefinition\Data\Localizedfields || $object instanceof DataObject\Localizedfield)) {
  1200.                 $fieldname $context['fieldname'];
  1201.                 if ($object instanceof DataObject\Concrete) {
  1202.                     $containerGetter 'get' ucfirst($fieldname);
  1203.                     $container $object->$containerGetter();
  1204.                     if ($container) {
  1205.                         $brickGetter 'get' ucfirst($context['containerKey']);
  1206.                         $brickData $container->$brickGetter();
  1207.                         if ($brickData instanceof DataObject\Objectbrick\Data\AbstractData) {
  1208.                             return $brickData->get('localizedfields');
  1209.                         }
  1210.                     }
  1211.                     return null;
  1212.                 } elseif ($object instanceof DataObject\Localizedfield) {
  1213.                     $data $object->getLocalizedValue($this->getName(), $params['language'], true);
  1214.                     return $data;
  1215.                 }
  1216.             } elseif ($context['containerType'] === 'classificationstore') {
  1217.                 $fieldname $context['fieldname'];
  1218.                 $getter 'get' ucfirst($fieldname);
  1219.                 if (method_exists($object$getter)) {
  1220.                     $groupId $context['groupId'];
  1221.                     $keyId $context['keyId'];
  1222.                     $language $context['language'];
  1223.                     /** @var DataObject\Classificationstore $classificationStoreData */
  1224.                     $classificationStoreData $object->$getter();
  1225.                     $data $classificationStoreData->getLocalizedKeyValue($groupId$keyId$languagetruetrue);
  1226.                     return $data;
  1227.                 }
  1228.             }
  1229.         }
  1230.         $container $object;
  1231.         $getter 'get' ucfirst($this->getName());
  1232.         if (method_exists($container$getter)) { // for DataObject\Concrete, DataObject\Fieldcollection\Data\AbstractData, DataObject\Objectbrick\Data\AbstractData
  1233.             $data $container->$getter();
  1234.         } elseif ($object instanceof DataObject\Localizedfield) {
  1235.             $data $object->getLocalizedValue($this->getName(), $params['language'], true);
  1236.         }
  1237.         return $data;
  1238.     }
  1239.     /**
  1240.      * @param DataObject\ClassDefinition\Data $mainDefinition
  1241.      */
  1242.     public function synchronizeWithMainDefinition(DataObject\ClassDefinition\Data $mainDefinition)
  1243.     {
  1244.         // implement in child classes
  1245.     }
  1246.     /**
  1247.      * @deprecated will be removed in Pimcore 11
  1248.      *
  1249.      * @param DataObject\ClassDefinition\Data $masterDefinition
  1250.      */
  1251.     public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  1252.     {
  1253.         trigger_deprecation(
  1254.             'pimcore/pimcore',
  1255.             '10.6.0',
  1256.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use %s instead.'__METHOD__str_replace('Master''Main'__METHOD__))
  1257.         );
  1258.         $this->synchronizeWithMainDefinition($masterDefinition);
  1259.     }
  1260.     /**
  1261.      * @param DataObject\ClassDefinition\Data $mainDefinition
  1262.      */
  1263.     public function adoptMainDefinition(DataObject\ClassDefinition\Data $mainDefinition)
  1264.     {
  1265.         $vars get_object_vars($this);
  1266.         $protectedFields = ['noteditable''invisible'];
  1267.         foreach ($vars as $name => $value) {
  1268.             if (!in_array($name$protectedFields)) {
  1269.                 unset($this->$name);
  1270.             }
  1271.         }
  1272.         $vars get_object_vars($mainDefinition);
  1273.         foreach ($vars as $name => $value) {
  1274.             if (!in_array($name$protectedFields)) {
  1275.                 $this->$name $value;
  1276.             }
  1277.         }
  1278.     }
  1279.     /**
  1280.      * @deprecated will be removed in Pimcore 11
  1281.      *
  1282.      * @param DataObject\ClassDefinition\Data $masterDefinition
  1283.      */
  1284.     public function adoptMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  1285.     {
  1286.         $vars get_object_vars($this);
  1287.         $protectedFields = ['noteditable''invisible'];
  1288.         foreach ($vars as $name => $value) {
  1289.             if (!in_array($name$protectedFields)) {
  1290.                 unset($this->$name);
  1291.             }
  1292.         }
  1293.         $vars get_object_vars($masterDefinition);
  1294.         foreach ($vars as $name => $value) {
  1295.             if (!in_array($name$protectedFields)) {
  1296.                 $this->$name $value;
  1297.             }
  1298.         }
  1299.     }
  1300.     /**
  1301.      * @param array|null $existingData
  1302.      * @param array $additionalData
  1303.      *
  1304.      * @return array|null
  1305.      */
  1306.     public function appendData($existingData$additionalData)
  1307.     {
  1308.         return $existingData;
  1309.     }
  1310.     /**
  1311.      * @param mixed $existingData
  1312.      * @param mixed $removeData
  1313.      *
  1314.      * @return mixed
  1315.      */
  1316.     public function removeData($existingData$removeData)
  1317.     {
  1318.         return $existingData;
  1319.     }
  1320.     /**
  1321.      * Returns if datatype supports data inheritance
  1322.      *
  1323.      * @return bool
  1324.      */
  1325.     public function supportsInheritance()
  1326.     {
  1327.         return true;
  1328.     }
  1329.     /**
  1330.      * @return bool
  1331.      */
  1332.     public function supportsDirtyDetection()
  1333.     {
  1334.         return false;
  1335.     }
  1336.     /**
  1337.      * @param DataObject\Concrete $object
  1338.      */
  1339.     public function markLazyloadedFieldAsLoaded($object)
  1340.     {
  1341.         if ($object instanceof DataObject\LazyLoadedFieldsInterface) {
  1342.             $object->markLazyKeyAsLoaded($this->getName());
  1343.         }
  1344.     }
  1345.     /**
  1346.      * Returns if datatype supports listing filters: getBy, filterBy
  1347.      *
  1348.      * @return bool
  1349.      */
  1350.     public function isFilterable(): bool
  1351.     {
  1352.         return false;
  1353.     }
  1354.     /**
  1355.      * @param DataObject\Listing $listing
  1356.      * @param string|int|float|array|Model\Element\ElementInterface $data comparison data, can be scalar or array (if operator is e.g. "IN (?)")
  1357.      * @param string $operator SQL comparison operator, e.g. =, <, >= etc. You can use "?" as placeholder, e.g. "IN (?)"
  1358.      *
  1359.      * @return DataObject\Listing
  1360.      */
  1361.     public function addListingFilter(DataObject\Listing $listing$data$operator '=')
  1362.     {
  1363.         return $listing->addFilterByField($this->getName(), $operator$data);
  1364.     }
  1365.     /**
  1366.      * @return bool
  1367.      */
  1368.     public function isForbiddenName()
  1369.     {
  1370.         return in_array($this->getName(), self::FORBIDDEN_NAMES);
  1371.     }
  1372. }