vendor/shopware/core/Checkout/Shipping/Validator/ShippingMethodValidator.php line 48

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Checkout\Shipping\Validator;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Checkout\Shipping\ShippingMethodDefinition;
  5. use Shopware\Core\Checkout\Shipping\ShippingMethodEntity;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\InsertCommand;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\UpdateCommand;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
  9. use Shopware\Core\Framework\Log\Package;
  10. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\Validator\ConstraintViolation;
  13. use Symfony\Component\Validator\ConstraintViolationInterface;
  14. use Symfony\Component\Validator\ConstraintViolationList;
  15. /**
  16.  * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  17.  */
  18. #[Package('checkout')]
  19. class ShippingMethodValidator implements EventSubscriberInterface
  20. {
  21.     public const VIOLATION_TAX_TYPE_INVALID 'tax_type_invalid';
  22.     public const VIOLATION_TAX_ID_REQUIRED 'c1051bb4-d103-4f74-8988-acbcafc7fdc3';
  23.     private Connection $connection;
  24.     /**
  25.      * @internal
  26.      */
  27.     public function __construct(Connection $connection)
  28.     {
  29.         $this->connection $connection;
  30.     }
  31.     /**
  32.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  33.      */
  34.     public static function getSubscribedEvents()
  35.     {
  36.         return [
  37.             PreWriteValidationEvent::class => 'preValidate',
  38.         ];
  39.     }
  40.     public function preValidate(PreWriteValidationEvent $event): void
  41.     {
  42.         $allowTypes = [
  43.             ShippingMethodEntity::TAX_TYPE_FIXED,
  44.             ShippingMethodEntity::TAX_TYPE_AUTO,
  45.             ShippingMethodEntity::TAX_TYPE_HIGHEST,
  46.         ];
  47.         $writeCommands $event->getCommands();
  48.         foreach ($writeCommands as $command) {
  49.             $violations = new ConstraintViolationList();
  50.             if (!$command instanceof InsertCommand && !$command instanceof UpdateCommand) {
  51.                 continue;
  52.             }
  53.             if ($command->getDefinition()->getClass() !== ShippingMethodDefinition::class) {
  54.                 continue;
  55.             }
  56.             $shippingMethod $this->findShippingMethod($command->getPrimaryKey()['id']);
  57.             $payload $command->getPayload();
  58.             /** @var string|null $taxType */
  59.             $taxType $this->getValue($payload'tax_type'$shippingMethod);
  60.             /** @var string|null $taxId */
  61.             $taxId $this->getValue($payload'tax_id'$shippingMethod);
  62.             if ($taxType && !\in_array($taxType$allowTypestrue)) {
  63.                 $violations->add(
  64.                     $this->buildViolation(
  65.                         'The selected tax type {{ type }} is invalid.',
  66.                         ['{{ type }}' => $taxType],
  67.                         '/taxType',
  68.                         $taxType,
  69.                         self::VIOLATION_TAX_TYPE_INVALID
  70.                     )
  71.                 );
  72.             }
  73.             if ($taxType === ShippingMethodEntity::TAX_TYPE_FIXED && !$taxId) {
  74.                 $violations->add(
  75.                     $this->buildViolation(
  76.                         'The defined tax rate is required when fixed tax present',
  77.                         ['{{ taxId }}' => null],
  78.                         '/taxId',
  79.                         $taxType,
  80.                         self::VIOLATION_TAX_ID_REQUIRED
  81.                     )
  82.                 );
  83.             }
  84.             if ($violations->count() > 0) {
  85.                 $event->getExceptions()->add(new WriteConstraintViolationException($violations$command->getPath()));
  86.             }
  87.         }
  88.     }
  89.     /**
  90.      * @return array<string, mixed>
  91.      */
  92.     private function findShippingMethod(string $shippingMethodId): array
  93.     {
  94.         $shippingMethod $this->connection->executeQuery(
  95.             'SELECT `tax_type`, `tax_id` FROM `shipping_method` WHERE `id` = :id',
  96.             ['id' => $shippingMethodId]
  97.         );
  98.         return $shippingMethod->fetchAssociative() ?: [];
  99.     }
  100.     /**
  101.      * @param array<string, mixed> $parameters
  102.      */
  103.     private function buildViolation(
  104.         string $messageTemplate,
  105.         array $parameters,
  106.         string $propertyPath,
  107.         string $invalidValue,
  108.         string $code
  109.     ): ConstraintViolationInterface {
  110.         return new ConstraintViolation(
  111.             str_replace(array_keys($parameters), array_values($parameters), $messageTemplate),
  112.             $messageTemplate,
  113.             $parameters,
  114.             null,
  115.             $propertyPath,
  116.             $invalidValue,
  117.             null,
  118.             $code
  119.         );
  120.     }
  121.     /**
  122.      * Gets a value from an array. It also does clean checks if
  123.      * the key is set, and also provides the option for default values.
  124.      *
  125.      * @param array<string, mixed> $data  the data array
  126.      * @param string               $key   the requested key in the array
  127.      * @param array<string, mixed> $dbRow the db row of from the database
  128.      *
  129.      * @return mixed the object found in the key, or the default value
  130.      */
  131.     private function getValue(array $datastring $key, array $dbRow)
  132.     {
  133.         // try in our actual data set
  134.         if (isset($data[$key])) {
  135.             return $data[$key];
  136.         }
  137.         // try in our db row fallback
  138.         if (isset($dbRow[$key])) {
  139.             return $dbRow[$key];
  140.         }
  141.         // use default
  142.         return null;
  143.     }
  144. }