vendor/pimcore/pimcore/models/Element/AbstractElement.php line 350

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\Element;
  15. use Pimcore\Cache\Runtime;
  16. use Pimcore\Event\AdminEvents;
  17. use Pimcore\Event\Model\ElementEvent;
  18. use Pimcore\Model;
  19. use Pimcore\Model\DataObject\AbstractObject;
  20. use Pimcore\Model\Element\Traits\DirtyIndicatorTrait;
  21. /**
  22. * @method Model\Document\Dao|Model\Asset\Dao|Model\DataObject\AbstractObject\Dao getDao()
  23. */
  24. abstract class AbstractElement extends Model\AbstractModel implements ElementInterface, ElementDumpStateInterface, DirtyIndicatorInterface
  25. {
  26. use ElementDumpStateTrait;
  27. use DirtyIndicatorTrait;
  28. /**
  29. * @internal
  30. *
  31. * @var Model\Dependency|null
  32. */
  33. protected $dependencies;
  34. /**
  35. * @internal
  36. *
  37. * @var int
  38. */
  39. protected $__dataVersionTimestamp = null;
  40. /**
  41. * @internal
  42. */
  43. protected function updateModificationInfos()
  44. {
  45. $this->setVersionCount($this->getDao()->getVersionCountForUpdate() + 1);
  46. if ($this->getVersionCount() > 4200000000) {
  47. $this->setVersionCount(1);
  48. }
  49. $modificationDateKey = $this instanceof AbstractObject ? 'o_modificationDate' : 'modificationDate';
  50. if (!$this->isFieldDirty($modificationDateKey)) {
  51. $updateTime = time();
  52. $this->setModificationDate($updateTime);
  53. }
  54. if (!$this->getCreationDate()) {
  55. $this->setCreationDate($this->getModificationDate());
  56. }
  57. // auto assign user if possible, if not changed explicitly, if no user present, use ID=0 which represents the "system" user
  58. $userModificationKey = $this instanceof AbstractObject ? 'o_userModification' : 'userModification';
  59. if (!$this->isFieldDirty($userModificationKey)) {
  60. $userId = 0;
  61. $user = \Pimcore\Tool\Admin::getCurrentUser();
  62. if ($user instanceof Model\User) {
  63. $userId = $user->getId();
  64. }
  65. $this->setUserModification($userId);
  66. }
  67. if ($this->getUserOwner() === null) {
  68. $this->setUserOwner($this->getUserModification());
  69. }
  70. }
  71. /**
  72. * {@inheritdoc}
  73. */
  74. public function getProperty($name, $asContainer = false)
  75. {
  76. $properties = $this->getProperties();
  77. if ($this->hasProperty($name)) {
  78. if ($asContainer) {
  79. return $properties[$name];
  80. } else {
  81. return $properties[$name]->getData();
  82. }
  83. }
  84. return null;
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public function hasProperty($name)
  90. {
  91. $properties = $this->getProperties();
  92. return array_key_exists($name, $properties);
  93. }
  94. /**
  95. * @param string $name
  96. */
  97. public function removeProperty($name)
  98. {
  99. $properties = $this->getProperties();
  100. unset($properties[$name]);
  101. $this->setProperties($properties);
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. public function getCacheTag()
  107. {
  108. $elementType = Service::getElementType($this);
  109. return $elementType . '_' . $this->getId();
  110. }
  111. /**
  112. * @internal
  113. *
  114. * @param string|int $id
  115. *
  116. * @return string
  117. */
  118. protected static function getCacheKey($id): string
  119. {
  120. $elementType = Service::getElementTypeByClassName(static::class);
  121. return $elementType . '_' . $id;
  122. }
  123. /**
  124. * {@inheritdoc}
  125. */
  126. public function getCacheTags(array $tags = []): array
  127. {
  128. $tags[$this->getCacheTag()] = $this->getCacheTag();
  129. return $tags;
  130. }
  131. /**
  132. * Resolves the dependencies of the element and returns an array of them - Used by update()
  133. *
  134. * @internal
  135. *
  136. * @return array
  137. */
  138. protected function resolveDependencies(): array
  139. {
  140. $dependencies = [[]];
  141. // check for properties
  142. if (method_exists($this, 'getProperties')) {
  143. foreach ($this->getProperties() as $property) {
  144. $dependencies[] = $property->resolveDependencies();
  145. }
  146. }
  147. return array_merge(...$dependencies);
  148. }
  149. /**
  150. * {@inheritdoc}
  151. */
  152. public function isLocked()
  153. {
  154. if ($this->getLocked()) {
  155. return true;
  156. }
  157. // check for inherited
  158. return $this->getDao()->isLocked();
  159. }
  160. /**
  161. * @internal
  162. *
  163. * @return array
  164. */
  165. public function getUserPermissions()
  166. {
  167. $baseClass = Service::getBaseClassNameForElement($this);
  168. $workspaceClass = '\\Pimcore\\Model\\User\\Workspace\\' . $baseClass;
  169. /** @var Model\AbstractModel $dummy */
  170. $dummy = new $workspaceClass();
  171. $vars = $dummy->getObjectVars();
  172. $ignored = ['userId', 'cid', 'cpath', 'dao'];
  173. $permissions = [];
  174. foreach ($vars as $name => $defaultValue) {
  175. if (!in_array($name, $ignored)) {
  176. $permissions[$name] = $this->isAllowed($name);
  177. }
  178. }
  179. return $permissions;
  180. }
  181. /**
  182. * {@inheritdoc}
  183. */
  184. public function isAllowed($type, ?Model\User $user = null)
  185. {
  186. if (null === $user) {
  187. $user = \Pimcore\Tool\Admin::getCurrentUser();
  188. }
  189. if (!$user) {
  190. if (php_sapi_name() === 'cli') {
  191. return true;
  192. }
  193. return false;
  194. }
  195. //everything is allowed for admin
  196. if ($user->isAdmin()) {
  197. return true;
  198. }
  199. $isAllowed = $this->getDao()->isAllowed($type, $user);
  200. $event = new ElementEvent($this, ['isAllowed' => $isAllowed, 'permissionType' => $type, 'user' => $user]);
  201. \Pimcore::getEventDispatcher()->dispatch($event, AdminEvents::ELEMENT_PERMISSION_IS_ALLOWED);
  202. return (bool) $event->getArgument('isAllowed');
  203. }
  204. /**
  205. * @internal
  206. */
  207. public function unlockPropagate()
  208. {
  209. $type = Service::getType($this);
  210. $ids = $this->getDao()->unlockPropagate();
  211. // invalidate cache items
  212. foreach ($ids as $id) {
  213. $element = Service::getElementById($type, $id);
  214. if ($element) {
  215. $element->clearDependentCache();
  216. }
  217. }
  218. }
  219. /**
  220. * @internal
  221. *
  222. * @throws \Exception
  223. */
  224. protected function validatePathLength()
  225. {
  226. if (mb_strlen($this->getRealFullPath()) > 765) {
  227. throw new \Exception("Full path is limited to 765 characters, reduce the length of your parent's path");
  228. }
  229. }
  230. /**
  231. * {@inheritdoc}
  232. */
  233. public function __toString()
  234. {
  235. return $this->getFullPath();
  236. }
  237. /**
  238. * @return int
  239. */
  240. public function __getDataVersionTimestamp()
  241. {
  242. return $this->__dataVersionTimestamp;
  243. }
  244. /**
  245. * @param int $_dataVersionTimestamp
  246. */
  247. public function __setDataVersionTimestamp($_dataVersionTimestamp)
  248. {
  249. $this->__dataVersionTimestamp = $_dataVersionTimestamp;
  250. }
  251. /**
  252. * {@inheritdoc}
  253. */
  254. public function __isBasedOnLatestData()
  255. {
  256. return $this->getDao()->__isBasedOnLatestData();
  257. }
  258. /**
  259. * @internal
  260. *
  261. * @param string|null $versionNote
  262. * @param bool $saveOnlyVersion
  263. * @param bool $saveStackTrace
  264. * @param bool $isAutoSave
  265. *
  266. * @return Model\Version
  267. *
  268. * @throws \Exception
  269. */
  270. protected function doSaveVersion($versionNote = null, $saveOnlyVersion = true, $saveStackTrace = true, $isAutoSave = false)
  271. {
  272. $version = null;
  273. if ($isAutoSave) {
  274. $list = new Model\Version\Listing();
  275. $list->setLoadAutoSave(true);
  276. $list->setCondition('autoSave = 1 AND cid = ? AND cType = ? AND userId = ? ', [$this->getId(), Service::getElementType($this), $this->getUserModification()]);
  277. $version = $list->current();
  278. }
  279. if (!$version) {
  280. /** @var Model\Version $version */
  281. $version = self::getModelFactory()->build(Model\Version::class);
  282. }
  283. $version->setCid($this->getId());
  284. $version->setCtype(Service::getElementType($this));
  285. $version->setDate($this->getModificationDate());
  286. $version->setUserId($this->getUserModification());
  287. $version->setData($this);
  288. $version->setNote($versionNote);
  289. $version->setGenerateStackTrace($saveStackTrace);
  290. $version->setAutoSave($isAutoSave);
  291. if ($saveOnlyVersion) {
  292. $versionCount = $this->getDao()->getVersionCountForUpdate();
  293. $versionCount++;
  294. } else {
  295. $versionCount = $this->getVersionCount();
  296. }
  297. $version->setVersionCount($versionCount);
  298. $version->save();
  299. return $version;
  300. }
  301. /**
  302. * {@inheritdoc}
  303. */
  304. public function getDependencies()
  305. {
  306. if (!$this->dependencies) {
  307. $this->dependencies = Model\Dependency::getBySourceId($this->getId(), Service::getElementType($this));
  308. }
  309. return $this->dependencies;
  310. }
  311. /**
  312. * {@inheritdoc}
  313. */
  314. public function getScheduledTasks()
  315. {
  316. return [];
  317. }
  318. /**
  319. * {@inheritdoc}
  320. */
  321. public function getVersions()
  322. {
  323. return [];
  324. }
  325. /**
  326. * {@inheritdoc}
  327. */
  328. public function __sleep()
  329. {
  330. $parentVars = parent::__sleep();
  331. $blockedVars = ['dependencies'];
  332. return array_diff($parentVars, $blockedVars);
  333. }
  334. /**
  335. * {@inheritdoc}
  336. */
  337. public function __clone()
  338. {
  339. parent::__clone();
  340. $this->dependencies = null;
  341. }
  342. /**
  343. * @internal
  344. *
  345. * @param int $userId
  346. */
  347. public function deleteAutoSaveVersions($userId = null)
  348. {
  349. $list = new Model\Version\Listing();
  350. $list->setLoadAutoSave(true);
  351. if ($userId) {
  352. $list->setCondition('`ctype` = ? AND cid = ? AND `autoSave` = 1 AND userId = ?', [Service::getType($this), $this->getId(), $userId]);
  353. } else {
  354. $list->setCondition('`ctype` = ? AND cid = ? AND `autoSave` = 1', [Service::getType($this), $this->getId()]);
  355. }
  356. foreach ($list->load() as $version) {
  357. $version->delete();
  358. }
  359. }
  360. /**
  361. * @internal
  362. */
  363. protected function removeInheritedProperties()
  364. {
  365. $myProperties = $this->getProperties();
  366. if ($myProperties) {
  367. foreach ($this->getProperties() as $name => $property) {
  368. if ($property->getInherited()) {
  369. unset($myProperties[$name]);
  370. }
  371. }
  372. }
  373. $this->setProperties($myProperties);
  374. }
  375. /**
  376. * @internal
  377. */
  378. protected function renewInheritedProperties()
  379. {
  380. $this->removeInheritedProperties();
  381. // add to registry to avoid infinite regresses in the following $this->getDao()->getProperties()
  382. $cacheKey = self::getCacheKey($this->getId());
  383. if (!Runtime::isRegistered($cacheKey)) {
  384. Runtime::set($cacheKey, $this);
  385. }
  386. $myProperties = $this->getProperties();
  387. $inheritedProperties = $this->getDao()->getProperties(true);
  388. $this->setProperties(array_merge($inheritedProperties, $myProperties));
  389. }
  390. }