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

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