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

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