vendor/shopware/core/Framework/DataAbstractionLayer/Write/Validation/LockValidator.php line 41

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer\Write\Validation;
  3. use Doctrine\DBAL\ArrayParameterType;
  4. use Doctrine\DBAL\Connection;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityDefinitionQueryHelper;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\InsertCommand;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\WriteCommand;
  8. use Shopware\Core\Framework\Log\Package;
  9. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. use Symfony\Component\Validator\ConstraintViolation;
  12. use Symfony\Component\Validator\ConstraintViolationList;
  13. /**
  14.  * @internal
  15.  */
  16. #[Package('core')]
  17. class LockValidator implements EventSubscriberInterface
  18. {
  19.     final public const VIOLATION_LOCKED 'FRAMEWORK__ENTITY_IS_LOCKED';
  20.     /**
  21.      * @internal
  22.      */
  23.     public function __construct(private readonly Connection $connection)
  24.     {
  25.     }
  26.     public static function getSubscribedEvents(): array
  27.     {
  28.         return [
  29.             PreWriteValidationEvent::class => 'preValidate',
  30.         ];
  31.     }
  32.     /**
  33.      * @throws WriteConstraintViolationException
  34.      */
  35.     public function preValidate(PreWriteValidationEvent $event): void
  36.     {
  37.         $violations = new ConstraintViolationList();
  38.         $writeCommands $event->getCommands();
  39.         $lockedEntities $this->containsLockedEntities($writeCommands);
  40.         if (empty($lockedEntities)) {
  41.             return;
  42.         }
  43.         $message 'The %s entity is locked and can neither be modified nor deleted.';
  44.         foreach ($lockedEntities as $entity => $_isLocked) {
  45.             $violations->add(new ConstraintViolation(
  46.                 sprintf($message$entity),
  47.                 sprintf($message'{{ entity }}'),
  48.                 ['{{ entity }}' => $entity],
  49.                 null,
  50.                 '/',
  51.                 null,
  52.                 null,
  53.                 self::VIOLATION_LOCKED
  54.             ));
  55.         }
  56.         $event->getExceptions()->add(new WriteConstraintViolationException($violations));
  57.     }
  58.     /**
  59.      * @param WriteCommand[] $writeCommands
  60.      *
  61.      * @return array<string, bool>
  62.      */
  63.     private function containsLockedEntities(array $writeCommands): array
  64.     {
  65.         $ids = [];
  66.         $locked = [];
  67.         foreach ($writeCommands as $command) {
  68.             if ($command instanceof InsertCommand) {
  69.                 continue;
  70.             }
  71.             if (!$command->getDefinition()->isLockAware()) {
  72.                 continue;
  73.             }
  74.             $ids[$command->getDefinition()->getEntityName()][] = $command->getPrimaryKey()['id'];
  75.         }
  76.         /** @var string $entityName */
  77.         foreach ($ids as $entityName => $primaryKeys) {
  78.             $locked[$entityName] = $this->connection->createQueryBuilder()
  79.                 ->select('1')
  80.                 ->from(EntityDefinitionQueryHelper::escape($entityName))
  81.                 ->where('`id` IN (:ids) AND `locked` = 1')
  82.                 ->setParameter('ids'$primaryKeysArrayParameterType::STRING)
  83.                 ->executeQuery()
  84.                 ->rowCount() > 0;
  85.         }
  86.         return array_filter($locked);
  87.     }
  88. }