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

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