vendor/symfony/validator/Mapping/Loader/PropertyInfoLoader.php line 50

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Validator\Mapping\Loader;
  11. use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
  12. use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
  13. use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
  14. use Symfony\Component\PropertyInfo\Type as PropertyInfoType;
  15. use Symfony\Component\Validator\Constraints\All;
  16. use Symfony\Component\Validator\Constraints\NotBlank;
  17. use Symfony\Component\Validator\Constraints\NotNull;
  18. use Symfony\Component\Validator\Constraints\Type;
  19. use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
  20. use Symfony\Component\Validator\Mapping\ClassMetadata;
  21. /**
  22.  * Guesses and loads the appropriate constraints using PropertyInfo.
  23.  *
  24.  * @author Kévin Dunglas <dunglas@gmail.com>
  25.  */
  26. final class PropertyInfoLoader implements LoaderInterface
  27. {
  28.     use AutoMappingTrait;
  29.     private $listExtractor;
  30.     private $typeExtractor;
  31.     private $accessExtractor;
  32.     private $classValidatorRegexp;
  33.     public function __construct(PropertyListExtractorInterface $listExtractorPropertyTypeExtractorInterface $typeExtractorPropertyAccessExtractorInterface $accessExtractorstring $classValidatorRegexp null)
  34.     {
  35.         $this->listExtractor $listExtractor;
  36.         $this->typeExtractor $typeExtractor;
  37.         $this->accessExtractor $accessExtractor;
  38.         $this->classValidatorRegexp $classValidatorRegexp;
  39.     }
  40.     /**
  41.      * {@inheritdoc}
  42.      */
  43.     public function loadClassMetadata(ClassMetadata $metadata): bool
  44.     {
  45.         $className $metadata->getClassName();
  46.         if (!$properties $this->listExtractor->getProperties($className)) {
  47.             return false;
  48.         }
  49.         $loaded false;
  50.         $enabledForClass $this->isAutoMappingEnabledForClass($metadata$this->classValidatorRegexp);
  51.         foreach ($properties as $property) {
  52.             if (false === $this->accessExtractor->isWritable($className$property)) {
  53.                 continue;
  54.             }
  55.             if (!property_exists($className$property)) {
  56.                 continue;
  57.             }
  58.             $types $this->typeExtractor->getTypes($className$property);
  59.             if (null === $types) {
  60.                 continue;
  61.             }
  62.             $enabledForProperty $enabledForClass;
  63.             $hasTypeConstraint false;
  64.             $hasNotNullConstraint false;
  65.             $hasNotBlankConstraint false;
  66.             $allConstraint null;
  67.             foreach ($metadata->getPropertyMetadata($property) as $propertyMetadata) {
  68.                 // Enabling or disabling auto-mapping explicitly always takes precedence
  69.                 if (AutoMappingStrategy::DISABLED === $propertyMetadata->getAutoMappingStrategy()) {
  70.                     continue 2;
  71.                 }
  72.                 if (AutoMappingStrategy::ENABLED === $propertyMetadata->getAutoMappingStrategy()) {
  73.                     $enabledForProperty true;
  74.                 }
  75.                 foreach ($propertyMetadata->getConstraints() as $constraint) {
  76.                     if ($constraint instanceof Type) {
  77.                         $hasTypeConstraint true;
  78.                     } elseif ($constraint instanceof NotNull) {
  79.                         $hasNotNullConstraint true;
  80.                     } elseif ($constraint instanceof NotBlank) {
  81.                         $hasNotBlankConstraint true;
  82.                     } elseif ($constraint instanceof All) {
  83.                         $allConstraint $constraint;
  84.                     }
  85.                 }
  86.             }
  87.             if (!$enabledForProperty) {
  88.                 continue;
  89.             }
  90.             $loaded true;
  91.             $builtinTypes = [];
  92.             $nullable false;
  93.             $scalar true;
  94.             foreach ($types as $type) {
  95.                 $builtinTypes[] = $type->getBuiltinType();
  96.                 if ($scalar && !\in_array($type->getBuiltinType(), [PropertyInfoType::BUILTIN_TYPE_INTPropertyInfoType::BUILTIN_TYPE_FLOATPropertyInfoType::BUILTIN_TYPE_STRINGPropertyInfoType::BUILTIN_TYPE_BOOL], true)) {
  97.                     $scalar false;
  98.                 }
  99.                 if (!$nullable && $type->isNullable()) {
  100.                     $nullable true;
  101.                 }
  102.             }
  103.             if (!$hasTypeConstraint) {
  104.                 if (=== \count($builtinTypes)) {
  105.                     if ($types[0]->isCollection() && (null !== $collectionValueType $types[0]->getCollectionValueType())) {
  106.                         $this->handleAllConstraint($property$allConstraint$collectionValueType$metadata);
  107.                     }
  108.                     $metadata->addPropertyConstraint($property$this->getTypeConstraint($builtinTypes[0], $types[0]));
  109.                 } elseif ($scalar) {
  110.                     $metadata->addPropertyConstraint($property, new Type(['type' => 'scalar']));
  111.                 }
  112.             }
  113.             if (!$nullable && !$hasNotBlankConstraint && !$hasNotNullConstraint) {
  114.                 $metadata->addPropertyConstraint($property, new NotNull());
  115.             }
  116.         }
  117.         return $loaded;
  118.     }
  119.     private function getTypeConstraint(string $builtinTypePropertyInfoType $type): Type
  120.     {
  121.         if (PropertyInfoType::BUILTIN_TYPE_OBJECT === $builtinType && null !== $className $type->getClassName()) {
  122.             return new Type(['type' => $className]);
  123.         }
  124.         return new Type(['type' => $builtinType]);
  125.     }
  126.     private function handleAllConstraint(string $property, ?All $allConstraintPropertyInfoType $propertyInfoTypeClassMetadata $metadata)
  127.     {
  128.         $containsTypeConstraint false;
  129.         $containsNotNullConstraint false;
  130.         if (null !== $allConstraint) {
  131.             foreach ($allConstraint->constraints as $constraint) {
  132.                 if ($constraint instanceof Type) {
  133.                     $containsTypeConstraint true;
  134.                 } elseif ($constraint instanceof NotNull) {
  135.                     $containsNotNullConstraint true;
  136.                 }
  137.             }
  138.         }
  139.         $constraints = [];
  140.         if (!$containsNotNullConstraint && !$propertyInfoType->isNullable()) {
  141.             $constraints[] = new NotNull();
  142.         }
  143.         if (!$containsTypeConstraint) {
  144.             $constraints[] = $this->getTypeConstraint($propertyInfoType->getBuiltinType(), $propertyInfoType);
  145.         }
  146.         if (null === $allConstraint) {
  147.             $metadata->addPropertyConstraint($property, new All(['constraints' => $constraints]));
  148.         } else {
  149.             $allConstraint->constraints array_merge($allConstraint->constraints$constraints);
  150.         }
  151.     }
  152. }