src/Core/Framework/DataAbstractionLayer/FieldSerializer/AbstractFieldSerializer.php line 51

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer;
  3. use Shopware\Core\Defaults;
  4. use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityTranslationDefinition;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Field\Field;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\AllowHtml;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Inherited;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Write\DataStack\KeyValuePair;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Write\EntityExistence;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Write\WriteParameterBag;
  13. use Shopware\Core\Framework\Log\Package;
  14. use Shopware\Core\Framework\Util\HtmlSanitizer;
  15. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  16. use Symfony\Component\Validator\Constraint;
  17. use Symfony\Component\Validator\ConstraintViolation;
  18. use Symfony\Component\Validator\ConstraintViolationList;
  19. use Symfony\Component\Validator\Validator\ValidatorInterface;
  20. /**
  21.  * @internal
  22.  */
  23. #[Package('core')]
  24. abstract class AbstractFieldSerializer implements FieldSerializerInterface
  25. {
  26.     /**
  27.      * @var array<Constraint[]>
  28.      */
  29.     private array $cachedConstraints = [];
  30.     public function __construct(protected ValidatorInterface $validator, protected DefinitionInstanceRegistry $definitionRegistry)
  31.     {
  32.     }
  33.     public function normalize(Field $field, array $dataWriteParameterBag $parameters): array
  34.     {
  35.         return $data;
  36.     }
  37.     protected function validate(
  38.         array $constraints,
  39.         KeyValuePair $data,
  40.         string $path
  41.     ): void {
  42.         $violationList = new ConstraintViolationList();
  43.         foreach ($constraints as $constraint) {
  44.             $violations $this->validator->validate($data->getValue(), $constraint);
  45.             /** @var ConstraintViolation $violation */
  46.             foreach ($violations as $violation) {
  47.                 $fieldName $data->getKey();
  48.                 // correct pointer for json fields with pre-defined structure
  49.                 if ($violation->getPropertyPath()) {
  50.                     $property str_replace('][''/'$violation->getPropertyPath());
  51.                     $property trim($property'][');
  52.                     $fieldName .= '/' $property;
  53.                 }
  54.                 $fieldName '/' $fieldName;
  55.                 $violationList->add(
  56.                     new ConstraintViolation(
  57.                         $violation->getMessage(),
  58.                         $violation->getMessageTemplate(),
  59.                         $violation->getParameters(),
  60.                         $violation->getRoot(),
  61.                         $fieldName,
  62.                         $violation->getInvalidValue(),
  63.                         $violation->getPlural(),
  64.                         $violation->getCode(),
  65.                         $violation->getConstraint(),
  66.                         $violation->getCause()
  67.                     )
  68.                 );
  69.             }
  70.         }
  71.         if (\count($violationList)) {
  72.             throw new WriteConstraintViolationException($violationList$path);
  73.         }
  74.     }
  75.     protected function requiresValidation(
  76.         Field $field,
  77.         EntityExistence $existence,
  78.         $value,
  79.         WriteParameterBag $parameters
  80.     ): bool {
  81.         if ($value !== null) {
  82.             return true;
  83.         }
  84.         if ($existence->isChild() && $this->isInherited($field$parameters)) {
  85.             return false;
  86.         }
  87.         if ($existence->hasEntityName()
  88.             && $this->definitionRegistry->getByEntityName($existence->getEntityName()) instanceof EntityTranslationDefinition
  89.             && $parameters->getCurrentWriteLanguageId() !== Defaults::LANGUAGE_SYSTEM
  90.         ) {
  91.             return false;
  92.         }
  93.         return $field->is(Required::class);
  94.     }
  95.     protected function isInherited(Field $fieldWriteParameterBag $parameters): bool
  96.     {
  97.         if ($parameters->getDefinition()->isInheritanceAware()) {
  98.             return $field->is(Inherited::class);
  99.         }
  100.         if (!$parameters->getDefinition() instanceof EntityTranslationDefinition) {
  101.             return false;
  102.         }
  103.         $parent $parameters->getDefinition()->getParentDefinition();
  104.         $field $parent->getFields()->get($field->getPropertyName());
  105.         return $field->is(Inherited::class);
  106.     }
  107.     protected function validateIfNeeded(Field $fieldEntityExistence $existenceKeyValuePair $dataWriteParameterBag $parameters): void
  108.     {
  109.         if (!$this->requiresValidation($field$existence$data->getValue(), $parameters)) {
  110.             return;
  111.         }
  112.         $constraints $this->getCachedConstraints($field);
  113.         $this->validate($constraints$data$parameters->getPath());
  114.     }
  115.     /**
  116.      * @return Constraint[]
  117.      */
  118.     protected function getConstraints(Field $field): array
  119.     {
  120.         return [];
  121.     }
  122.     /**
  123.      * @return Constraint[]
  124.      */
  125.     protected function getCachedConstraints(Field $field): array
  126.     {
  127.         $key $field->getPropertyName() . spl_object_id($field);
  128.         if (\array_key_exists($key$this->cachedConstraints)) {
  129.             return $this->cachedConstraints[$key];
  130.         }
  131.         return $this->cachedConstraints[$key] = $this->getConstraints($field);
  132.     }
  133.     protected function sanitize(HtmlSanitizer $sanitizerKeyValuePair $dataField $fieldEntityExistence $existence): ?string
  134.     {
  135.         if ($data->getValue() === null) {
  136.             return null;
  137.         }
  138.         if (!$field->is(AllowHtml::class)) {
  139.             return strip_tags((string) $data->getValue());
  140.         }
  141.         $flag $field->getFlag(AllowHtml::class);
  142.         if ($flag instanceof AllowHtml && $flag->isSanitized()) {
  143.             $fieldKey sprintf('%s.%s', (string) $existence->getEntityName(), $field->getPropertyName());
  144.             return $sanitizer->sanitize((string) $data->getValue(), [], false$fieldKey);
  145.         }
  146.         return (string) $data->getValue();
  147.     }
  148. }