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

Open in your IDE?
  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. namespace Pimcore\Model\DataObject\ClassDefinition;
  15. use Pimcore\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 string|array|object $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($operator, DataObject\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) === 0 ? '' : (int)$number;
  1007. }
  1008. /**
  1009. * @param mixed $number
  1010. *
  1011. * @return float
  1012. */
  1013. public function getAsFloatCast($number)
  1014. {
  1015. return strlen($number) === 0 ? '' : (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, $language, true, true);
  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. }