vendor/shopware/platform/src/Core/Checkout/Shipping/Validator/ShippingMethodValidator.php line 40

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