vendor/sulu/sulu/src/Sulu/Component/Content/Compat/Structure/StructureBridge.php line 179

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Sulu.
  4. *
  5. * (c) Sulu GmbH
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Sulu\Component\Content\Compat\Structure;
  11. use Sulu\Bundle\DocumentManagerBundle\Bridge\DocumentInspector;
  12. use Sulu\Component\Content\Compat\StructureInterface;
  13. use Sulu\Component\Content\Compat\StructureType;
  14. use Sulu\Component\Content\Document\Behavior\ExtensionBehavior;
  15. use Sulu\Component\Content\Document\Behavior\NavigationContextBehavior;
  16. use Sulu\Component\Content\Document\Behavior\OrderBehavior;
  17. use Sulu\Component\Content\Document\Behavior\RedirectTypeBehavior;
  18. use Sulu\Component\Content\Document\Behavior\ResourceSegmentBehavior;
  19. use Sulu\Component\Content\Document\Behavior\ShadowLocaleBehavior;
  20. use Sulu\Component\Content\Document\Behavior\StructureBehavior;
  21. use Sulu\Component\Content\Document\Behavior\WorkflowStageBehavior;
  22. use Sulu\Component\Content\Document\LocalizationState;
  23. use Sulu\Component\Content\Document\RedirectType;
  24. use Sulu\Component\Content\Document\WorkflowStage;
  25. use Sulu\Component\Content\Metadata\StructureMetadata;
  26. /**
  27. * @deprecated Should be replaced by a proper StructureInterface implementation
  28. */
  29. class StructureBridge implements StructureInterface
  30. {
  31. /**
  32. * @var StructureMetadata
  33. */
  34. protected $structure;
  35. /**
  36. * @var DocumentInspector
  37. */
  38. protected $inspector;
  39. /**
  40. * @var array
  41. */
  42. private $loadedProperties = [];
  43. /**
  44. * Needed by structure extensions when the document has not been set..
  45. *
  46. * @var string
  47. */
  48. protected $locale;
  49. /**
  50. * @param object $document
  51. */
  52. public function __construct(
  53. StructureMetadata $structure,
  54. DocumentInspector $inspector,
  55. private LegacyPropertyFactory $propertyFactory,
  56. protected $document = null
  57. ) {
  58. $this->structure = $structure;
  59. $this->inspector = $inspector;
  60. }
  61. public function setDocument(StructureBehavior $document)
  62. {
  63. $this->document = $document;
  64. }
  65. public function setLanguageCode($locale)
  66. {
  67. $this->locale = $locale;
  68. }
  69. public function getLanguageCode()
  70. {
  71. if (!$this->document) {
  72. return $this->locale;
  73. }
  74. return $this->inspector->getLocale($this->getDocument());
  75. }
  76. public function setWebspaceKey($webspace)
  77. {
  78. $this->readOnlyException(__METHOD__);
  79. }
  80. public function getWebspaceKey()
  81. {
  82. if (!$this->document) {
  83. return null;
  84. }
  85. return $this->inspector->getWebspace($this->getDocument());
  86. }
  87. public function getUuid()
  88. {
  89. return $this->getDocument()->getUuid();
  90. }
  91. public function setUuid($uuid)
  92. {
  93. $this->readOnlyException(__METHOD__);
  94. }
  95. public function getCreator()
  96. {
  97. return $this->getDocument()->getCreator();
  98. }
  99. public function setCreator($userId)
  100. {
  101. $this->readOnlyException(__METHOD__);
  102. }
  103. public function getChanger()
  104. {
  105. return $this->getDocument()->getChanger();
  106. }
  107. public function setChanger($userId)
  108. {
  109. $this->readOnlyException(__METHOD__);
  110. }
  111. public function getCreated()
  112. {
  113. return $this->getDocument()->getCreated();
  114. }
  115. public function setCreated(\DateTime $created)
  116. {
  117. $this->readOnlyException(__METHOD__);
  118. }
  119. public function getChanged()
  120. {
  121. return $this->getDocument()->getChanged();
  122. }
  123. public function setChanged(\DateTime $changed)
  124. {
  125. $this->readOnlyException(__METHOD__);
  126. }
  127. public function getKey()
  128. {
  129. return $this->structure->getName();
  130. }
  131. public function getInternal()
  132. {
  133. return $this->structure->isInternal();
  134. }
  135. public function getProperty($name)
  136. {
  137. if ($this->hasProperty($name)) {
  138. $property = $this->structure->getProperty($name);
  139. } else {
  140. $property = $this->structure->getChild($name);
  141. }
  142. return $this->createLegacyPropertyFromItem($property);
  143. }
  144. public function hasProperty($name)
  145. {
  146. return $this->structure->hasProperty($name);
  147. }
  148. public function getProperties($flatten = false)
  149. {
  150. if ($flatten) {
  151. $items = $this->structure->getProperties();
  152. } else {
  153. $items = $this->structure->getChildren();
  154. }
  155. $propertyBridges = [];
  156. foreach ($items as $property) {
  157. $propertyBridges[$property->getName()] = $this->createLegacyPropertyFromItem($property);
  158. }
  159. return $propertyBridges;
  160. }
  161. public function getExt()
  162. {
  163. return $this->document->getExtensionsData();
  164. }
  165. public function setExt($data)
  166. {
  167. $this->readOnlyException(__METHOD__);
  168. }
  169. public function setHasChildren($hasChildren)
  170. {
  171. $this->readOnlyException(__METHOD__);
  172. }
  173. public function getHasChildren()
  174. {
  175. return $this->inspector->hasChildren($this->getDocument());
  176. }
  177. public function setChildren($children)
  178. {
  179. $this->readOnlyException(__METHOD__);
  180. }
  181. public function getChildren()
  182. {
  183. $children = [];
  184. foreach ($this->getDocument()->getChildren() as $child) {
  185. $children[] = $this->documentToStructure($child);
  186. }
  187. return $children;
  188. }
  189. /**
  190. * @return $this
  191. */
  192. public function getParent()
  193. {
  194. return $this->documentToStructure($this->inspector->getParent($this->getDocument()));
  195. }
  196. public function getPublishedState()
  197. {
  198. return WorkflowStage::PUBLISHED === $this->getWorkflowDocument(__METHOD__)->getWorkflowStage();
  199. }
  200. public function setPublished($published)
  201. {
  202. $this->readOnlyException(__METHOD__);
  203. }
  204. public function getPublished()
  205. {
  206. return $this->getWorkflowDocument(__METHOD__)->getPublished();
  207. }
  208. public function getPropertyValue($name)
  209. {
  210. return $this->getProperty($name)->getValue();
  211. }
  212. public function getPropertyNames()
  213. {
  214. return \array_keys($this->structure->getChildren());
  215. }
  216. public function setType($type)
  217. {
  218. $this->readOnlyException(__METHOD__);
  219. }
  220. public function getType()
  221. {
  222. $document = $this->getDocument();
  223. $localizationState = $this->inspector->getLocalizationState($document);
  224. if (LocalizationState::GHOST === $localizationState) {
  225. return StructureType::getGhost($this->getDocument()->getLocale());
  226. }
  227. if (LocalizationState::SHADOW === $this->inspector->getLocalizationState($document)) {
  228. return StructureType::getShadow($this->getDocument()->getLocale());
  229. }
  230. }
  231. public function getPath()
  232. {
  233. return $this->inspector->getContentPath($this->getDocument());
  234. }
  235. public function setPath($path)
  236. {
  237. $this->readOnlyException(__METHOD__);
  238. }
  239. public function setHasTranslation($hasTranslation)
  240. {
  241. $this->readOnlyException(__METHOD__);
  242. }
  243. public function getHasTranslation()
  244. {
  245. return $this->getTitle() ? true : false;
  246. }
  247. public function toArray($complete = true)
  248. {
  249. $document = $this->getDocument();
  250. $result = [
  251. 'id' => $this->inspector->getUuid($document),
  252. 'path' => $this->inspector->getContentPath($document),
  253. 'nodeType' => $this->getNodeType(),
  254. 'nodeState' => $this->getNodeState(),
  255. 'internal' => false,
  256. 'availableLocales' => $this->inspector->getLocales($document),
  257. 'contentLocales' => $this->inspector->getConcreteLocales($document),
  258. 'hasSub' => $this->getHasChildren(),
  259. 'title' => $document->getTitle(), // legacy system returns diffent fields for title depending on $complete
  260. ];
  261. if ($document instanceof OrderBehavior) {
  262. $result['order'] = $document->getSuluOrder();
  263. }
  264. if ($document instanceof RedirectTypeBehavior) {
  265. $redirectType = $document->getRedirectType();
  266. $result['linked'] = null;
  267. if (RedirectType::INTERNAL == $redirectType && null !== $document->getRedirectTarget()) {
  268. $result['linked'] = 'internal';
  269. $result['internal_link'] = $document->getRedirectTarget()->getUuid();
  270. } elseif (RedirectType::EXTERNAL == $redirectType) {
  271. $result['linked'] = 'external';
  272. $result['external'] = $document->getRedirectExternal();
  273. }
  274. }
  275. if ($document instanceof WorkflowStageBehavior) {
  276. $result['publishedState'] = WorkflowStage::PUBLISHED === $document->getWorkflowStage();
  277. $result['published'] = $document->getPublished();
  278. }
  279. $result['navContexts'] = [];
  280. if ($document instanceof NavigationContextBehavior) {
  281. $result['navContexts'] = $document->getNavigationContexts();
  282. }
  283. if (null !== $this->getType()) {
  284. $result['type'] = $this->getType()->toArray();
  285. }
  286. if ($complete) {
  287. if ($document instanceof ShadowLocaleBehavior) {
  288. $result = \array_merge(
  289. $result,
  290. [
  291. 'shadowLocales' => $this->inspector->getShadowLocales($document),
  292. 'shadowOn' => $document->isShadowLocaleEnabled(),
  293. 'shadowBaseLanguage' => $document->getShadowLocale(),
  294. ]
  295. );
  296. }
  297. $result = \array_merge(
  298. $result,
  299. [
  300. 'template' => $this->structure->getName(),
  301. 'originTemplate' => $this->structure->getName(),
  302. 'creator' => $document->getCreator(),
  303. 'changer' => $document->getChanger(),
  304. 'created' => $document->getCreated(),
  305. 'changed' => $document->getChanged(),
  306. 'title' => $document->getTitle(),
  307. 'url' => null,
  308. ]
  309. );
  310. if ($document instanceof ResourceSegmentBehavior) {
  311. $result['url'] = $document->getResourceSegment();
  312. }
  313. if ($document instanceof ExtensionBehavior) {
  314. $result['ext'] = $document->getExtensionsData();
  315. }
  316. $result = \array_merge($this->getDocument()->getStructure()->toArray(), $result);
  317. return $result;
  318. }
  319. return $result;
  320. }
  321. #[\ReturnTypeWillChange]
  322. public function jsonSerialize()
  323. {
  324. }
  325. public function getPropertyByTagName($tagName, $highest = true)
  326. {
  327. return $this->createLegacyPropertyFromItem($this->structure->getPropertyByTagName($tagName, $highest));
  328. }
  329. public function getPropertiesByTagName($tagName)
  330. {
  331. $properties = [];
  332. foreach ($this->structure->getPropertiesByTagName($tagName) as $structureProperty) {
  333. $properties[] = $this->createLegacyPropertyFromItem($structureProperty);
  334. }
  335. return $properties;
  336. }
  337. public function getPropertyValueByTagName($tagName)
  338. {
  339. return $this->getPropertyByTagName($tagName)->getValue();
  340. }
  341. public function hasTag($tag)
  342. {
  343. return $this->structure->hasPropertyWithTagName($tag);
  344. }
  345. public function getNodeType()
  346. {
  347. if ($this->getDocument() instanceof RedirectTypeBehavior) {
  348. return $this->getDocument()->getRedirectType();
  349. }
  350. return RedirectType::NONE;
  351. }
  352. public function getNodeName()
  353. {
  354. if ($this->document instanceof RedirectTypeBehavior
  355. && RedirectType::INTERNAL == $this->document->getRedirectType()
  356. && null !== $this->document->getRedirectTarget()
  357. ) {
  358. return $this->getDocument()->getRedirectTarget()->getTitle();
  359. }
  360. return $this->getDocument()->getTitle();
  361. }
  362. public function getLocalizedTitle($languageCode)
  363. {
  364. return $this->structure->getTitle($languageCode);
  365. }
  366. public function getNodeState()
  367. {
  368. $document = $this->getDocument();
  369. if (!$document instanceof WorkflowStageBehavior) {
  370. return WorkflowStage::PUBLISHED;
  371. }
  372. return $this->getDocument()->getWorkflowStage();
  373. }
  374. public function getTitle()
  375. {
  376. return $this->getDocument()->getTitle();
  377. }
  378. public function getUrl()
  379. {
  380. return $this->getDocument()->getResourceSegment();
  381. }
  382. public function copyFrom(StructureInterface $structure)
  383. {
  384. foreach ($this->getProperties(true) as $property) {
  385. if ($structure->hasProperty($property->getName())) {
  386. $property->setValue($structure->getPropertyValue($property->getName()));
  387. }
  388. }
  389. $this->setDocument($structure->getDocument());
  390. }
  391. /**
  392. * Magic getter.
  393. *
  394. * @deprecated Do not use magic getters. Use ArrayAccess instead
  395. */
  396. public function __get($name)
  397. {
  398. return $this->getProperty($name)->getValue();
  399. }
  400. public function getShadowLocales()
  401. {
  402. return $this->inspector->getShadowLocales($this->getDocument());
  403. }
  404. public function getContentLocales()
  405. {
  406. return $this->inspector->getConcreteLocales($this->getDocument());
  407. }
  408. public function getIsShadow()
  409. {
  410. if (!$this->document) {
  411. return false;
  412. }
  413. $document = $this->getDocument();
  414. if (!$document instanceof ShadowLocaleBehavior) {
  415. return false;
  416. }
  417. return $document->isShadowLocaleEnabled();
  418. }
  419. public function getShadowBaseLanguage()
  420. {
  421. $document = $this->getDocument();
  422. if (!$document instanceof ShadowLocaleBehavior) {
  423. return;
  424. }
  425. return $document->getShadowLocale();
  426. }
  427. public function getResourceLocator()
  428. {
  429. $document = $this->getDocument();
  430. if (RedirectType::EXTERNAL == $document->getRedirectType()) {
  431. return $document->getRedirectExternal();
  432. }
  433. if (RedirectType::INTERNAL === $document->getRedirectType()) {
  434. $target = $document->getRedirectTarget();
  435. if (!$target) {
  436. throw new \RuntimeException('Document is an internal redirect, but no redirect target has been set.');
  437. }
  438. return $target->getResourceSegment();
  439. }
  440. return $document->getResourceSegment();
  441. }
  442. /**
  443. * Returns document.
  444. *
  445. * @return object
  446. */
  447. public function getDocument()
  448. {
  449. if (!$this->document) {
  450. throw new \RuntimeException(
  451. 'Document has not been applied to structure yet, cannot retrieve data from structure.'
  452. );
  453. }
  454. return $this->document;
  455. }
  456. /**
  457. * Returns structure metadata.
  458. *
  459. * @return StructureMetadata
  460. */
  461. public function getStructure()
  462. {
  463. return $this->structure;
  464. }
  465. protected function readOnlyException($method)
  466. {
  467. throw new \BadMethodCallException(
  468. \sprintf(
  469. 'Compatibility layer StructureBridge instances are readonly. Tried to call "%s"',
  470. $method
  471. )
  472. );
  473. }
  474. /**
  475. * @param StructureBehavior $document The document to convert
  476. *
  477. * @return $this
  478. */
  479. protected function documentToStructure(StructureBehavior $document)
  480. {
  481. return new $this(
  482. $this->inspector->getStructureMetadata($document),
  483. $this->inspector,
  484. $this->propertyFactory,
  485. $document
  486. );
  487. }
  488. private function getWorkflowDocument($method)
  489. {
  490. $document = $this->getDocument();
  491. if (!$document instanceof WorkflowStageBehavior) {
  492. throw new \BadMethodCallException(
  493. \sprintf(
  494. 'Cannot call "%s" on Document which does not implement PageInterface. Is "%s"',
  495. $method,
  496. \get_class($document)
  497. )
  498. );
  499. }
  500. return $document;
  501. }
  502. private function notImplemented($method)
  503. {
  504. throw new \InvalidArgumentException(
  505. \sprintf(
  506. 'Method "%s" is not yet implemented',
  507. $method
  508. )
  509. );
  510. }
  511. private function normalizeData(?array $data = null)
  512. {
  513. if (null === $data) {
  514. return;
  515. }
  516. if (false === \is_array($data)) {
  517. return $this->normalizeValue($data);
  518. }
  519. foreach ($data as &$value) {
  520. if (\is_array($value)) {
  521. foreach ($value as $childKey => $childValue) {
  522. $data[$childKey] = $this->normalizeData($childValue);
  523. }
  524. }
  525. $value = $this->normalizeValue($value);
  526. }
  527. return $data;
  528. }
  529. private function normalizeValue($value)
  530. {
  531. if ($value instanceof StructureBehavior) {
  532. return $this->documentToStructure($value);
  533. }
  534. return $value;
  535. }
  536. private function createLegacyPropertyFromItem($item)
  537. {
  538. $name = $item->getName();
  539. if (isset($this->loadedProperties[$name])) {
  540. return $this->loadedProperties[$name];
  541. }
  542. $propertyBridge = $this->propertyFactory->createProperty($item, $this);
  543. if ($this->document) {
  544. $property = $this->getDocument()->getStructure()->getProperty($name);
  545. $propertyBridge->setPropertyValue($property);
  546. }
  547. $this->loadedProperties[$name] = $propertyBridge;
  548. return $propertyBridge;
  549. }
  550. }