vendor/pimcore/pimcore/models/DataObject/Classificationstore.php line 537

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;
  15. use Pimcore\Model;
  16. use Pimcore\Model\DataObject\ClassDefinition\Data\PreGetDataInterface;
  17. use Pimcore\Model\Element\DirtyIndicatorInterface;
  18. use Pimcore\Tool;
  19. /**
  20. * @method \Pimcore\Model\DataObject\Classificationstore\Dao createUpdateTable()
  21. * @method \Pimcore\Model\DataObject\Classificationstore\Dao getDao()
  22. * @method void delete()
  23. * @method Classificationstore load()
  24. * @method void save()
  25. */
  26. class Classificationstore extends Model\AbstractModel implements DirtyIndicatorInterface
  27. {
  28. use Model\Element\Traits\DirtyIndicatorTrait;
  29. /**
  30. * @internal
  31. *
  32. * @var array
  33. */
  34. protected $items = [];
  35. /**
  36. * @internal
  37. *
  38. * @var Concrete|null
  39. */
  40. protected ?Concrete $object = null;
  41. /**
  42. * @internal
  43. *
  44. * @var ClassDefinition|null
  45. */
  46. protected ?ClassDefinition $class = null;
  47. /**
  48. * @internal
  49. *
  50. * @var string
  51. */
  52. protected $fieldname;
  53. /**
  54. * @internal
  55. *
  56. * @var array
  57. */
  58. protected $activeGroups = [];
  59. /**
  60. * @internal
  61. *
  62. * @var array
  63. */
  64. protected $groupCollectionMapping = [];
  65. /**
  66. * @param array $items
  67. */
  68. public function __construct($items = null)
  69. {
  70. if ($items) {
  71. $this->setItems($items);
  72. $this->markFieldDirty('_self');
  73. }
  74. }
  75. /**
  76. * @param array $item
  77. */
  78. public function addItem($item)
  79. {
  80. $this->items[] = $item;
  81. $this->markFieldDirty('_self');
  82. }
  83. /**
  84. * @param array $items
  85. *
  86. * @return $this
  87. */
  88. public function setItems($items)
  89. {
  90. $this->items = $items;
  91. $this->markFieldDirty('_self');
  92. return $this;
  93. }
  94. /**
  95. * @return array
  96. */
  97. public function getItems()
  98. {
  99. return $this->items;
  100. }
  101. /**
  102. * @param Concrete $object
  103. *
  104. * @return $this
  105. */
  106. public function setObject(Concrete $object)
  107. {
  108. if ($this->object) {
  109. if ($this->object->getId() != $object->getId()) {
  110. $this->markFieldDirty('_self');
  111. }
  112. }
  113. $this->object = $object;
  114. return $this;
  115. }
  116. /**
  117. * @return Concrete|null
  118. */
  119. public function getObject(): ?Concrete
  120. {
  121. return $this->object;
  122. }
  123. /**
  124. * @param ClassDefinition|null $class
  125. *
  126. * @return $this
  127. */
  128. public function setClass(?ClassDefinition $class)
  129. {
  130. $this->class = $class;
  131. return $this;
  132. }
  133. /**
  134. * @return Model\DataObject\ClassDefinition|null
  135. */
  136. public function getClass(): ?ClassDefinition
  137. {
  138. if (!$this->class && $this->getObject()) {
  139. $this->class = $this->getObject()->getClass();
  140. }
  141. return $this->class;
  142. }
  143. /**
  144. * @param string|null $language
  145. *
  146. * @return string
  147. */
  148. public function getLanguage($language = null)
  149. {
  150. if ($language) {
  151. return (string) $language;
  152. }
  153. return 'default';
  154. }
  155. /**
  156. * @param int $groupId
  157. * @param int $keyId
  158. * @param mixed $value
  159. * @param string|null $language
  160. *
  161. * @return $this
  162. *
  163. * @throws \Exception
  164. */
  165. public function setLocalizedKeyValue($groupId, $keyId, $value, $language = null)
  166. {
  167. if (!$groupId) {
  168. throw new \Exception('groupId not valid');
  169. }
  170. if (!$keyId) {
  171. throw new \Exception('keyId not valid');
  172. }
  173. $language = $this->getLanguage($language);
  174. // treat value "0" nonempty
  175. $nonEmpty = (is_string($value) || is_numeric($value)) && strlen($value) > 0;
  176. // Workaround for booleanSelect
  177. // @TODO Find a better solution for using isEmpty() in all ClassDefintion DataTypes
  178. $keyConfig = Model\DataObject\Classificationstore\DefinitionCache::get($keyId);
  179. /** @var Model\DataObject\ClassDefinition\Data\ResourcePersistenceAwareInterface $dataDefinition */
  180. $dataDefinition = Model\DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  181. // set the given group to active groups
  182. $this->setActiveGroups($this->activeGroups + [$groupId => true]);
  183. if (!$this->isFieldDirty('_self')) {
  184. if ($this->object) {
  185. $oldData = $this->items[$groupId][$keyId][$language] ?? null;
  186. $oldData = $dataDefinition->getDataForResource($oldData, $this->object, ['owner' => $this]);
  187. if (!$dataDefinition instanceof Model\DataObject\ClassDefinition\Data\Password) {
  188. $oldData = serialize($oldData);
  189. }
  190. $newData = $dataDefinition->getDataForResource($value, $this->object, ['owner' => $this]);
  191. if ($dataDefinition instanceof Model\DataObject\ClassDefinition\Data\Password) {
  192. $value = $newData;
  193. } else {
  194. $newData = serialize($newData);
  195. }
  196. if ($newData != $oldData) {
  197. $this->markFieldDirty('_self');
  198. }
  199. } else {
  200. $this->markFieldDirty('_self');
  201. }
  202. }
  203. if ($dataDefinition instanceof Model\DataObject\ClassDefinition\Data\BooleanSelect) {
  204. $nonEmpty = true;
  205. }
  206. if ($dataDefinition instanceof Model\DataObject\ClassDefinition\Data\Multiselect && is_array($value) && empty($value)) {
  207. $nonEmpty = true;
  208. }
  209. if ($nonEmpty || $value) {
  210. $this->items[$groupId][$keyId][$language] = $value;
  211. } elseif (isset($this->items[$groupId][$keyId][$language])) {
  212. unset($this->items[$groupId][$keyId][$language]);
  213. if (empty($this->items[$groupId][$keyId])) {
  214. unset($this->items[$groupId][$keyId]);
  215. if (empty($this->items[$groupId])) {
  216. unset($this->items[$groupId]);
  217. }
  218. }
  219. }
  220. return $this;
  221. }
  222. /**
  223. * Removes the group with the given id
  224. *
  225. * @param int $groupId
  226. */
  227. public function removeGroupData($groupId)
  228. {
  229. unset($this->items[$groupId]);
  230. }
  231. /** Returns an array of
  232. * @return array
  233. */
  234. public function getGroupIdsWithData()
  235. {
  236. return array_keys($this->items);
  237. }
  238. /**
  239. * @return string
  240. */
  241. public function getFieldname()
  242. {
  243. return $this->fieldname;
  244. }
  245. /**
  246. * @param string $fieldname
  247. */
  248. public function setFieldname($fieldname)
  249. {
  250. $this->fieldname = $fieldname;
  251. }
  252. /**
  253. * @return array
  254. */
  255. public function getActiveGroups()
  256. {
  257. return $this->activeGroups;
  258. }
  259. private function sanitizeActiveGroups($activeGroups)
  260. {
  261. $newList = [];
  262. if ($activeGroups) {
  263. foreach ($activeGroups as $key => $value) {
  264. if ($value) {
  265. $newList[$key] = true;
  266. }
  267. }
  268. }
  269. return $newList;
  270. }
  271. /**
  272. * @param array $activeGroups
  273. */
  274. public function setActiveGroups($activeGroups)
  275. {
  276. $activeGroups = $this->sanitizeActiveGroups($activeGroups);
  277. $diff1 = array_diff(array_keys($activeGroups), array_keys($this->activeGroups));
  278. $diff2 = array_diff(array_keys($this->activeGroups), array_keys($activeGroups));
  279. if ($diff1 || $diff2) {
  280. $this->markFieldDirty('_self');
  281. }
  282. $this->activeGroups = $activeGroups;
  283. }
  284. /**
  285. * @param int $groupId
  286. * @param int $keyId
  287. * @param string $language
  288. * @param Model\DataObject\ClassDefinition\Data $fielddefinition
  289. *
  290. * @return mixed
  291. */
  292. private function getFallbackValue($groupId, $keyId, $language, $fielddefinition)
  293. {
  294. $fallbackLanguages = Tool::getFallbackLanguagesFor($language);
  295. $data = null;
  296. foreach ($fallbackLanguages as $l) {
  297. if (
  298. array_key_exists($groupId, $this->items)
  299. && array_key_exists($keyId, $this->items[$groupId])
  300. && array_key_exists($l, $this->items[$groupId][$keyId])
  301. ) {
  302. $data = $this->items[$groupId][$keyId][$l];
  303. if (!$fielddefinition->isEmpty($data)) {
  304. return $data;
  305. }
  306. }
  307. }
  308. foreach ($fallbackLanguages as $l) {
  309. $data = $this->getFallbackValue($groupId, $keyId, $l, $fielddefinition);
  310. }
  311. return $data;
  312. }
  313. /**
  314. * @param int $groupId
  315. * @param int $keyId
  316. * @param string $language
  317. * @param bool $ignoreFallbackLanguage
  318. * @param bool $ignoreDefaultLanguage
  319. *
  320. * @return mixed
  321. *
  322. * @throws \Exception
  323. */
  324. public function getLocalizedKeyValue($groupId, $keyId, $language = 'default', $ignoreFallbackLanguage = false, $ignoreDefaultLanguage = false)
  325. {
  326. $keyConfig = Model\DataObject\Classificationstore\DefinitionCache::get($keyId);
  327. if ($keyConfig->getType() == 'calculatedValue') {
  328. $data = new Model\DataObject\Data\CalculatedValue($this->getFieldname());
  329. $childDef = Model\DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  330. $data->setContextualData('classificationstore', $this->getFieldname(), null, $language, $groupId, $keyId, $childDef);
  331. $data = Model\DataObject\Service::getCalculatedFieldValueForEditMode($this->getObject(), [], $data);
  332. return $data;
  333. }
  334. $fieldDefinition = Model\DataObject\Classificationstore\Service::getFieldDefinitionFromKeyConfig($keyConfig);
  335. $language = $this->getLanguage($language);
  336. $data = null;
  337. if (array_key_exists($groupId, $this->items) && array_key_exists($keyId, $this->items[$groupId])
  338. && array_key_exists($language, $this->items[$groupId][$keyId])
  339. ) {
  340. $data = $this->items[$groupId][$keyId][$language];
  341. }
  342. // check for fallback value
  343. if ($fieldDefinition->isEmpty($data) && !$ignoreFallbackLanguage && self::doGetFallbackValues()) {
  344. $data = $this->getFallbackValue($groupId, $keyId, $language, $fieldDefinition);
  345. }
  346. if ($fieldDefinition->isEmpty($data) && !$ignoreDefaultLanguage && $language != 'default') {
  347. $data = $this->items[$groupId][$keyId]['default'] ?? null;
  348. }
  349. // check for inherited value
  350. $doGetInheritedValues = Model\DataObject::doGetInheritedValues();
  351. if ($fieldDefinition->isEmpty($data) && $doGetInheritedValues) {
  352. $object = $this->getObject();
  353. $class = $object->getClass();
  354. $allowInherit = $class->getAllowInherit();
  355. if ($allowInherit) {
  356. if ($object->getParent() instanceof AbstractObject) {
  357. $parent = $object->getParent();
  358. while ($parent && $parent->getType() == AbstractObject::OBJECT_TYPE_FOLDER) {
  359. $parent = $parent->getParent();
  360. }
  361. if ($parent && ($parent->getType() == AbstractObject::OBJECT_TYPE_OBJECT || $parent->getType() == AbstractObject::OBJECT_TYPE_VARIANT)) {
  362. /** @var Concrete $parent */
  363. if ($parent->getClassId() == $object->getClassId()) {
  364. $getter = 'get' . ucfirst($this->fieldname);
  365. $classificationStore = $parent->$getter();
  366. if ($classificationStore instanceof Classificationstore) {
  367. if ($classificationStore->object->getId() != $this->object->getId()) {
  368. $data = $classificationStore->getLocalizedKeyValue($groupId, $keyId, $language, false);
  369. }
  370. }
  371. }
  372. }
  373. }
  374. }
  375. }
  376. //TODO Pimcore 11: remove method_exists BC layer
  377. if ($fieldDefinition instanceof PreGetDataInterface || method_exists($fieldDefinition, 'preGetData')) {
  378. if (!$fieldDefinition instanceof PreGetDataInterface) {
  379. trigger_deprecation('pimcore/pimcore', '10.1',
  380. sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  381. 'Implement the %s interface instead.', PreGetDataInterface::class));
  382. }
  383. $data = $fieldDefinition->preGetData($this, [
  384. 'data' => $data,
  385. 'language' => $language,
  386. 'name' => $groupId . '-' . $keyId,
  387. ]);
  388. }
  389. return $data;
  390. }
  391. /**
  392. * @return bool
  393. */
  394. public static function doGetFallbackValues()
  395. {
  396. return true;
  397. }
  398. /**
  399. * @return array
  400. */
  401. public function getGroupCollectionMappings(): array
  402. {
  403. return $this->groupCollectionMapping;
  404. }
  405. /**
  406. * @param array $groupCollectionMapping
  407. */
  408. public function setGroupCollectionMappings(array $groupCollectionMapping): void
  409. {
  410. $this->groupCollectionMapping = $groupCollectionMapping;
  411. }
  412. /**
  413. * @param int|null $groupId
  414. * @param int|null $collectionId
  415. */
  416. public function setGroupCollectionMapping($groupId = null, $collectionId = null): void
  417. {
  418. if ($groupId && $collectionId) {
  419. $this->groupCollectionMapping[$groupId] = $collectionId;
  420. }
  421. }
  422. /**
  423. * @param int $groupId
  424. *
  425. * @return int|null
  426. */
  427. public function getGroupCollectionMapping($groupId)
  428. {
  429. return $this->groupCollectionMapping[$groupId] ?? null;
  430. }
  431. /**
  432. * @return Model\DataObject\Classificationstore\Group[]
  433. */
  434. public function getGroups(): array
  435. {
  436. $activeGroups = $this->getActiveGroups();
  437. $groups = [];
  438. foreach (array_keys($activeGroups) as $groupId) {
  439. $groupConfig = $this->getGroupConfigById($groupId);
  440. $groups[] = $this->createGroup($this, $groupConfig);
  441. }
  442. return $groups;
  443. }
  444. /**
  445. * @param Classificationstore $classificationstore
  446. * @param Classificationstore\GroupConfig $groupConfig
  447. *
  448. * @return Model\DataObject\Classificationstore\Group
  449. */
  450. public function createGroup(
  451. Classificationstore $classificationstore,
  452. Classificationstore\GroupConfig $groupConfig
  453. ): Model\DataObject\Classificationstore\Group {
  454. return new Model\DataObject\Classificationstore\Group($classificationstore, $groupConfig);
  455. }
  456. /**
  457. * @param int $groupId
  458. *
  459. * @return Classificationstore\GroupConfig|null
  460. */
  461. private function getGroupConfigById(int $groupId): ?Classificationstore\GroupConfig
  462. {
  463. return Classificationstore\GroupConfig::getById($groupId);
  464. }
  465. }