vendor/shopware/core/Content/Category/Validation/EntryPointValidator.php line 49

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Category\Validation;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Content\Category\CategoryDefinition;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\InsertCommand;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\UpdateCommand;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\WriteCommand;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PostWriteValidationEvent;
  9. use Shopware\Core\Framework\Log\Package;
  10. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  11. use Shopware\Core\System\SalesChannel\SalesChannelDefinition;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\Validator\ConstraintViolation;
  14. use Symfony\Component\Validator\ConstraintViolationList;
  15. use Symfony\Component\Validator\ConstraintViolationListInterface;
  16. /**
  17. * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  18. */
  19. #[Package('content')]
  20. class EntryPointValidator implements EventSubscriberInterface
  21. {
  22. private const ERROR_CODE = 'CONTENT__INVALID_CATEGORY_TYPE_AS_ENTRY_POINT';
  23. private const ALLOWED_TYPE_CHANGE = [
  24. CategoryDefinition::TYPE_PAGE,
  25. CategoryDefinition::TYPE_FOLDER,
  26. ];
  27. private Connection $connection;
  28. /**
  29. * @internal
  30. */
  31. public function __construct(Connection $connection)
  32. {
  33. $this->connection = $connection;
  34. }
  35. public static function getSubscribedEvents(): array
  36. {
  37. return [
  38. PostWriteValidationEvent::class => 'postValidate',
  39. ];
  40. }
  41. public function postValidate(PostWriteValidationEvent $event): void
  42. {
  43. $violationList = new ConstraintViolationList();
  44. foreach ($event->getCommands() as $command) {
  45. if (!($command instanceof InsertCommand || $command instanceof UpdateCommand)) {
  46. continue;
  47. }
  48. if ($command->getDefinition()->getClass() !== CategoryDefinition::class) {
  49. continue;
  50. }
  51. if (!isset($command->getPayload()['type'])) {
  52. continue;
  53. }
  54. $violationList->addAll($this->checkTypeChange($command, $event));
  55. }
  56. if ($violationList->count() > 0) {
  57. $event->getExceptions()->add(new WriteConstraintViolationException($violationList));
  58. return;
  59. }
  60. }
  61. private function checkTypeChange(WriteCommand $command, PostWriteValidationEvent $event): ConstraintViolationListInterface
  62. {
  63. $violationList = new ConstraintViolationList();
  64. $payload = $command->getPayload();
  65. if (\in_array($payload['type'], self::ALLOWED_TYPE_CHANGE, true)) {
  66. return $violationList;
  67. }
  68. if ($this->isCategoryEntryPoint($command->getPrimaryKey()['id'], $event)) {
  69. return $violationList;
  70. }
  71. $messageTemplate = 'The type can not be assigned while category is entry point.';
  72. $parameters = ['{{ value }}' => $payload['type']];
  73. $violationList->add(new ConstraintViolation(
  74. str_replace(array_keys($parameters), $parameters, $messageTemplate),
  75. $messageTemplate,
  76. $parameters,
  77. null,
  78. sprintf('%s/type', $command->getPath()),
  79. $payload['type'],
  80. null,
  81. self::ERROR_CODE
  82. ));
  83. return $violationList;
  84. }
  85. private function isCategoryEntryPoint(string $categoryId, PostWriteValidationEvent $event): bool
  86. {
  87. foreach ($event->getCommands() as $salesChannelCommand) {
  88. if ($salesChannelCommand->getDefinition()->getClass() !== SalesChannelDefinition::class) {
  89. continue;
  90. }
  91. $payload = $salesChannelCommand->getPayload();
  92. if ((isset($payload['navigation_category_id']) && $payload['navigation_category_id'] === $categoryId)
  93. || (isset($payload['footer_category_id']) && $payload['footer_category_id'] === $categoryId)
  94. || (isset($payload['service_category_id']) && $payload['service_category_id'] === $categoryId)
  95. ) {
  96. return false;
  97. }
  98. }
  99. $result = $this->connection->createQueryBuilder()
  100. ->select('id')
  101. ->from(SalesChannelDefinition::ENTITY_NAME)
  102. ->where('navigation_category_id = :navigation_id')
  103. ->orWhere('footer_category_id = :footer_id')
  104. ->orWhere('service_category_id = :service_id')
  105. ->setParameter('navigation_id', $categoryId)
  106. ->setParameter('footer_id', $categoryId)
  107. ->setParameter('service_id', $categoryId)
  108. ->setMaxResults(1)
  109. ->executeQuery();
  110. return !$result->fetchOne();
  111. }
  112. }