vendor/shopware/core/Content/Cms/Subscriber/CmsPageDefaultChangeSubscriber.php line 76

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Cms\Subscriber;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Content\Category\CategoryDefinition;
  5. use Shopware\Core\Content\Cms\CmsException;
  6. use Shopware\Core\Content\Cms\CmsPageDefinition;
  7. use Shopware\Core\Content\Cms\Exception\PageNotFoundException;
  8. use Shopware\Core\Content\Product\ProductDefinition;
  9. use Shopware\Core\Defaults;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Event\BeforeDeleteEvent;
  11. use Shopware\Core\Framework\Log\Package;
  12. use Shopware\Core\Framework\Uuid\Uuid;
  13. use Shopware\Core\System\SystemConfig\Event\BeforeSystemConfigChangedEvent;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. /**
  16. * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  17. */
  18. #[Package('content')]
  19. class CmsPageDefaultChangeSubscriber implements EventSubscriberInterface
  20. {
  21. /**
  22. * @var array<string>
  23. */
  24. public static array $defaultCmsPageConfigKeys = [
  25. ProductDefinition::CONFIG_KEY_DEFAULT_CMS_PAGE_PRODUCT,
  26. CategoryDefinition::CONFIG_KEY_DEFAULT_CMS_PAGE_CATEGORY,
  27. ];
  28. private Connection $connection;
  29. /**
  30. * @internal
  31. */
  32. public function __construct(
  33. Connection $connection
  34. ) {
  35. $this->connection = $connection;
  36. }
  37. public static function getSubscribedEvents(): array
  38. {
  39. return [
  40. BeforeSystemConfigChangedEvent::class => 'validateChangeOfDefaultCmsPage',
  41. BeforeDeleteEvent::class => 'beforeDeletion',
  42. ];
  43. }
  44. /**
  45. * @throws CmsException
  46. * @throws \JsonException
  47. */
  48. public function beforeDeletion(BeforeDeleteEvent $event): void
  49. {
  50. $cmsPageIds = $event->getIds(CmsPageDefinition::ENTITY_NAME);
  51. // no cms page is affected by this deletion event
  52. if (empty($cmsPageIds)) {
  53. return;
  54. }
  55. $defaultPages = $this->cmsPageIsDefault($cmsPageIds);
  56. // count !== 0 indicates that there are some cms pages which would be deleted but are currently a default
  57. if (\count($defaultPages) !== 0) {
  58. throw CmsException::deletionOfDefault($defaultPages);
  59. }
  60. }
  61. /**
  62. * @throws CmsException
  63. * @throws PageNotFoundException
  64. */
  65. public function validateChangeOfDefaultCmsPage(BeforeSystemConfigChangedEvent $event): void
  66. {
  67. $newDefaultCmsPageId = $event->getValue();
  68. $systemConfigKey = $event->getKey();
  69. $salesChannelId = $event->getSalesChannelId();
  70. if (!\in_array($systemConfigKey, self::$defaultCmsPageConfigKeys, true)) {
  71. return;
  72. }
  73. // prevent deleting the overall default (salesChannelId === null)
  74. // a sales channel specific default can still be deleted (salesChannelId !== null)
  75. if ($newDefaultCmsPageId === null && $salesChannelId === null) {
  76. $oldCmsPageId = $this->getCurrentOverallDefaultCmsPageId($systemConfigKey);
  77. throw CmsException::overallDefaultSystemConfigDeletion($oldCmsPageId);
  78. }
  79. if (!\is_string($newDefaultCmsPageId) && $newDefaultCmsPageId !== null) {
  80. throw new PageNotFoundException('invalid page');
  81. }
  82. // prevent changing the default to an invalid cms page id
  83. if (\is_string($newDefaultCmsPageId) && !$this->cmsPageExists($newDefaultCmsPageId)) {
  84. throw new PageNotFoundException($newDefaultCmsPageId);
  85. }
  86. }
  87. private function getCurrentOverallDefaultCmsPageId(string $systemConfigKey): string
  88. {
  89. $result = $this->connection->fetchOne(
  90. 'SELECT configuration_value FROM system_config WHERE configuration_key = :configKey AND sales_channel_id is NULL;',
  91. [
  92. 'configKey' => $systemConfigKey,
  93. ]
  94. );
  95. $config = json_decode($result, true);
  96. return $config['_value'];
  97. }
  98. /**
  99. * @param array<string> $cmsPageIds
  100. *
  101. * @return array<string>
  102. */
  103. private function cmsPageIsDefault(array $cmsPageIds): array
  104. {
  105. $configurations = $this->connection->fetchAllAssociative(
  106. 'SELECT DISTINCT configuration_value FROM system_config WHERE configuration_key IN (:configKeys);',
  107. [
  108. 'configKeys' => self::$defaultCmsPageConfigKeys,
  109. ],
  110. [
  111. 'configKeys' => Connection::PARAM_STR_ARRAY,
  112. ]
  113. );
  114. $defaultIds = [];
  115. foreach ($configurations as $configuration) {
  116. $configValue = $configuration['configuration_value'];
  117. $config = json_decode($configValue, true);
  118. $defaultIds[] = $config['_value'];
  119. }
  120. // returns from all provided cms pages the ones which are default
  121. return array_intersect($cmsPageIds, $defaultIds);
  122. }
  123. private function cmsPageExists(string $cmsPageId): bool
  124. {
  125. $count = $this->connection->fetchOne(
  126. 'SELECT count(*) FROM cms_page WHERE id = :cmsPageId AND version_id = :versionId LIMIT 1;',
  127. [
  128. 'cmsPageId' => Uuid::fromHexToBytes($cmsPageId),
  129. 'versionId' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION),
  130. ]
  131. );
  132. return $count === '1';
  133. }
  134. }