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

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