vendor/shopware/core/System/Language/TranslationValidator.php line 35

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\System\Language;
  3. use Shopware\Core\Defaults;
  4. use Shopware\Core\Framework\DataAbstractionLayer\EntityTranslationDefinition;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\CascadeDeleteCommand;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\DeleteCommand;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\WriteCommand;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
  10. use Shopware\Core\Framework\Log\Package;
  11. use Shopware\Core\Framework\Uuid\Uuid;
  12. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use Symfony\Component\Validator\ConstraintViolation;
  15. use Symfony\Component\Validator\ConstraintViolationInterface;
  16. use Symfony\Component\Validator\ConstraintViolationList;
  17. /**
  18. * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  19. */
  20. #[Package('core')]
  21. class TranslationValidator implements EventSubscriberInterface
  22. {
  23. public const VIOLATION_DELETE_SYSTEM_TRANSLATION = 'delete-system-translation-violation';
  24. public static function getSubscribedEvents(): array
  25. {
  26. return [
  27. PreWriteValidationEvent::class => 'preValidate',
  28. ];
  29. }
  30. public function preValidate(PreWriteValidationEvent $event): void
  31. {
  32. if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
  33. return;
  34. }
  35. $violations = new ConstraintViolationList();
  36. $violations->addAll($this->getDeletedSystemTranslationViolations($event->getCommands()));
  37. if ($violations->count()) {
  38. $event->getExceptions()->add(new WriteConstraintViolationException($violations));
  39. }
  40. }
  41. /**
  42. * @param list<WriteCommand> $writeCommands
  43. */
  44. private function getDeletedSystemTranslationViolations(array $writeCommands): ConstraintViolationList
  45. {
  46. $violations = new ConstraintViolationList();
  47. foreach ($writeCommands as $writeCommand) {
  48. if (!$writeCommand instanceof DeleteCommand || $writeCommand instanceof CascadeDeleteCommand) {
  49. continue;
  50. }
  51. $pk = $writeCommand->getPrimaryKey();
  52. if (!isset($pk['language_id'])) {
  53. continue;
  54. }
  55. $def = $writeCommand->getDefinition();
  56. if (!$def instanceof EntityTranslationDefinition) {
  57. continue;
  58. }
  59. if (Uuid::fromBytesToHex($pk['language_id']) !== Defaults::LANGUAGE_SYSTEM) {
  60. continue;
  61. }
  62. $fks = $this->getFkFields($def);
  63. $id = Uuid::fromBytesToHex($pk[$fks['id']->getStorageName()]);
  64. $violations->add(
  65. $this->buildViolation(
  66. 'Cannot delete system translation',
  67. ['{{ id }}' => $id],
  68. '/' . $id . '/translations/' . Defaults::LANGUAGE_SYSTEM,
  69. [$id, Defaults::LANGUAGE_SYSTEM],
  70. self::VIOLATION_DELETE_SYSTEM_TRANSLATION
  71. )
  72. );
  73. }
  74. return $violations;
  75. }
  76. /**
  77. * @return FkField[]
  78. */
  79. private function getFkFields(EntityTranslationDefinition $definition): array
  80. {
  81. $rootEntity = $definition->getParentDefinition();
  82. $idStorageName = $rootEntity->getEntityName() . '_id';
  83. $versionIdStorageName = $rootEntity->getEntityName() . '_version_id';
  84. $pks = $definition->getPrimaryKeys();
  85. $idField = $pks->getByStorageName($idStorageName);
  86. if (!$idField || !$idField instanceof FkField) {
  87. throw new \RuntimeException(sprintf('`%s` primary key should have column `%s`', $definition->getEntityName(), $idStorageName));
  88. }
  89. $fields = [
  90. 'id' => $idField,
  91. ];
  92. $versionIdField = $pks->getByStorageName($versionIdStorageName);
  93. if ($versionIdField && $versionIdField instanceof FkField) {
  94. $fields['version'] = $versionIdField;
  95. }
  96. return $fields;
  97. }
  98. /**
  99. * @param array<string, string> $parameters
  100. * @param array<mixed>|null $invalidValue
  101. */
  102. private function buildViolation(
  103. string $messageTemplate,
  104. array $parameters,
  105. ?string $propertyPath = null,
  106. ?array $invalidValue = null,
  107. ?string $code = null
  108. ): ConstraintViolationInterface {
  109. return new ConstraintViolation(
  110. str_replace(array_keys($parameters), array_values($parameters), $messageTemplate),
  111. $messageTemplate,
  112. $parameters,
  113. null,
  114. $propertyPath,
  115. $invalidValue,
  116. null,
  117. $code
  118. );
  119. }
  120. }