vendor/symfony/validator/ValidatorBuilder.php line 232

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;
  11. use Doctrine\Common\Annotations\AnnotationReader;
  12. use Doctrine\Common\Annotations\CachedReader;
  13. use Doctrine\Common\Annotations\Reader;
  14. use Doctrine\Common\Cache\ArrayCache;
  15. use Psr\Cache\CacheItemPoolInterface;
  16. use Symfony\Component\Cache\Adapter\ArrayAdapter;
  17. use Symfony\Component\Cache\DoctrineProvider;
  18. use Symfony\Component\Validator\Context\ExecutionContextFactory;
  19. use Symfony\Component\Validator\Exception\ValidatorException;
  20. use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
  21. use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
  22. use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
  23. use Symfony\Component\Validator\Mapping\Loader\LoaderChain;
  24. use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
  25. use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
  26. use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader;
  27. use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;
  28. use Symfony\Component\Validator\Validator\RecursiveValidator;
  29. use Symfony\Component\Validator\Validator\ValidatorInterface;
  30. use Symfony\Contracts\Translation\LocaleAwareInterface;
  31. use Symfony\Contracts\Translation\TranslatorInterface;
  32. use Symfony\Contracts\Translation\TranslatorTrait;
  33. // Help opcache.preload discover always-needed symbols
  34. class_exists(TranslatorInterface::class);
  35. class_exists(LocaleAwareInterface::class);
  36. class_exists(TranslatorTrait::class);
  37. /**
  38.  * @author Bernhard Schussek <bschussek@gmail.com>
  39.  */
  40. class ValidatorBuilder
  41. {
  42.     private $initializers = [];
  43.     private $loaders = [];
  44.     private $xmlMappings = [];
  45.     private $yamlMappings = [];
  46.     private $methodMappings = [];
  47.     /**
  48.      * @var Reader|null
  49.      */
  50.     private $annotationReader;
  51.     private $enableAnnotationMapping false;
  52.     /**
  53.      * @var MetadataFactoryInterface|null
  54.      */
  55.     private $metadataFactory;
  56.     /**
  57.      * @var ConstraintValidatorFactoryInterface|null
  58.      */
  59.     private $validatorFactory;
  60.     /**
  61.      * @var CacheItemPoolInterface|null
  62.      */
  63.     private $mappingCache;
  64.     /**
  65.      * @var TranslatorInterface|null
  66.      */
  67.     private $translator;
  68.     /**
  69.      * @var string|null
  70.      */
  71.     private $translationDomain;
  72.     /**
  73.      * Adds an object initializer to the validator.
  74.      *
  75.      * @return $this
  76.      */
  77.     public function addObjectInitializer(ObjectInitializerInterface $initializer)
  78.     {
  79.         $this->initializers[] = $initializer;
  80.         return $this;
  81.     }
  82.     /**
  83.      * Adds a list of object initializers to the validator.
  84.      *
  85.      * @param ObjectInitializerInterface[] $initializers
  86.      *
  87.      * @return $this
  88.      */
  89.     public function addObjectInitializers(array $initializers)
  90.     {
  91.         $this->initializers array_merge($this->initializers$initializers);
  92.         return $this;
  93.     }
  94.     /**
  95.      * Adds an XML constraint mapping file to the validator.
  96.      *
  97.      * @return $this
  98.      */
  99.     public function addXmlMapping($path)
  100.     {
  101.         if (null !== $this->metadataFactory) {
  102.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  103.         }
  104.         $this->xmlMappings[] = $path;
  105.         return $this;
  106.     }
  107.     /**
  108.      * Adds a list of XML constraint mapping files to the validator.
  109.      *
  110.      * @param string[] $paths The paths to the mapping files
  111.      *
  112.      * @return $this
  113.      */
  114.     public function addXmlMappings(array $paths)
  115.     {
  116.         if (null !== $this->metadataFactory) {
  117.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  118.         }
  119.         $this->xmlMappings array_merge($this->xmlMappings$paths);
  120.         return $this;
  121.     }
  122.     /**
  123.      * Adds a YAML constraint mapping file to the validator.
  124.      *
  125.      * @param string $path The path to the mapping file
  126.      *
  127.      * @return $this
  128.      */
  129.     public function addYamlMapping($path)
  130.     {
  131.         if (null !== $this->metadataFactory) {
  132.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  133.         }
  134.         $this->yamlMappings[] = $path;
  135.         return $this;
  136.     }
  137.     /**
  138.      * Adds a list of YAML constraint mappings file to the validator.
  139.      *
  140.      * @param string[] $paths The paths to the mapping files
  141.      *
  142.      * @return $this
  143.      */
  144.     public function addYamlMappings(array $paths)
  145.     {
  146.         if (null !== $this->metadataFactory) {
  147.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  148.         }
  149.         $this->yamlMappings array_merge($this->yamlMappings$paths);
  150.         return $this;
  151.     }
  152.     /**
  153.      * Enables constraint mapping using the given static method.
  154.      *
  155.      * @return $this
  156.      */
  157.     public function addMethodMapping($methodName)
  158.     {
  159.         if (null !== $this->metadataFactory) {
  160.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  161.         }
  162.         $this->methodMappings[] = $methodName;
  163.         return $this;
  164.     }
  165.     /**
  166.      * Enables constraint mapping using the given static methods.
  167.      *
  168.      * @param string[] $methodNames The names of the methods
  169.      *
  170.      * @return $this
  171.      */
  172.     public function addMethodMappings(array $methodNames)
  173.     {
  174.         if (null !== $this->metadataFactory) {
  175.             throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
  176.         }
  177.         $this->methodMappings array_merge($this->methodMappings$methodNames);
  178.         return $this;
  179.     }
  180.     /**
  181.      * Enables annotation based constraint mapping.
  182.      *
  183.      * @param bool $skipDoctrineAnnotations
  184.      *
  185.      * @return $this
  186.      */
  187.     public function enableAnnotationMapping(/* bool $skipDoctrineAnnotations = true */)
  188.     {
  189.         if (null !== $this->metadataFactory) {
  190.             throw new ValidatorException('You cannot enable annotation mapping after setting a custom metadata factory. Configure your metadata factory instead.');
  191.         }
  192.         $skipDoctrineAnnotations > \func_num_args() ? false func_get_arg(0);
  193.         if (false === $skipDoctrineAnnotations || null === $skipDoctrineAnnotations) {
  194.             trigger_deprecation('symfony/validator''5.2''Not passing true as first argument to "%s" is deprecated. Pass true and call "addDefaultDoctrineAnnotationReader()" if you want to enable annotation mapping with Doctrine Annotations.'__METHOD__);
  195.             $this->addDefaultDoctrineAnnotationReader();
  196.         } elseif ($skipDoctrineAnnotations instanceof Reader) {
  197.             trigger_deprecation('symfony/validator''5.2''Passing an instance of "%s" as first argument to "%s" is deprecated. Pass true instead and call setDoctrineAnnotationReader() if you want to enable annotation mapping with Doctrine Annotations.'get_debug_type($skipDoctrineAnnotations), __METHOD__);
  198.             $this->setDoctrineAnnotationReader($skipDoctrineAnnotations);
  199.         } elseif (true !== $skipDoctrineAnnotations) {
  200.             throw new \TypeError(sprintf('"%s": Argument 1 is expected to be a boolean, "%s" given.'__METHOD__get_debug_type($skipDoctrineAnnotations)));
  201.         }
  202.         $this->enableAnnotationMapping true;
  203.         return $this;
  204.     }
  205.     /**
  206.      * Disables annotation based constraint mapping.
  207.      *
  208.      * @return $this
  209.      */
  210.     public function disableAnnotationMapping()
  211.     {
  212.         $this->enableAnnotationMapping false;
  213.         $this->annotationReader null;
  214.         return $this;
  215.     }
  216.     /**
  217.      * @return $this
  218.      */
  219.     public function setDoctrineAnnotationReader(?Reader $reader): self
  220.     {
  221.         $this->annotationReader $reader;
  222.         return $this;
  223.     }
  224.     /**
  225.      * @return $this
  226.      */
  227.     public function addDefaultDoctrineAnnotationReader(): self
  228.     {
  229.         if (class_exists(ArrayAdapter::class)) {
  230.             $this->annotationReader = new CachedReader(new AnnotationReader(), new DoctrineProvider(new ArrayAdapter()));
  231.         } else {
  232.             $this->annotationReader = new CachedReader(new AnnotationReader(), new ArrayCache());
  233.         }
  234.         return $this;
  235.     }
  236.     /**
  237.      * Sets the class metadata factory used by the validator.
  238.      *
  239.      * @return $this
  240.      */
  241.     public function setMetadataFactory(MetadataFactoryInterface $metadataFactory)
  242.     {
  243.         if (\count($this->xmlMappings) > || \count($this->yamlMappings) > || \count($this->methodMappings) > || $this->enableAnnotationMapping) {
  244.             throw new ValidatorException('You cannot set a custom metadata factory after adding custom mappings. You should do either of both.');
  245.         }
  246.         $this->metadataFactory $metadataFactory;
  247.         return $this;
  248.     }
  249.     /**
  250.      * Sets the cache for caching class metadata.
  251.      *
  252.      * @return $this
  253.      */
  254.     public function setMappingCache(CacheItemPoolInterface $cache)
  255.     {
  256.         if (null !== $this->metadataFactory) {
  257.             throw new ValidatorException('You cannot set a custom mapping cache after setting a custom metadata factory. Configure your metadata factory instead.');
  258.         }
  259.         $this->mappingCache $cache;
  260.         return $this;
  261.     }
  262.     /**
  263.      * Sets the constraint validator factory used by the validator.
  264.      *
  265.      * @return $this
  266.      */
  267.     public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory)
  268.     {
  269.         $this->validatorFactory $validatorFactory;
  270.         return $this;
  271.     }
  272.     /**
  273.      * Sets the translator used for translating violation messages.
  274.      *
  275.      * @return $this
  276.      */
  277.     public function setTranslator(TranslatorInterface $translator)
  278.     {
  279.         $this->translator $translator;
  280.         return $this;
  281.     }
  282.     /**
  283.      * Sets the default translation domain of violation messages.
  284.      *
  285.      * The same message can have different translations in different domains.
  286.      * Pass the domain that is used for violation messages by default to this
  287.      * method.
  288.      *
  289.      * @return $this
  290.      */
  291.     public function setTranslationDomain($translationDomain)
  292.     {
  293.         $this->translationDomain $translationDomain;
  294.         return $this;
  295.     }
  296.     /**
  297.      * @return $this
  298.      */
  299.     public function addLoader(LoaderInterface $loader)
  300.     {
  301.         $this->loaders[] = $loader;
  302.         return $this;
  303.     }
  304.     /**
  305.      * @return LoaderInterface[]
  306.      */
  307.     public function getLoaders()
  308.     {
  309.         $loaders = [];
  310.         foreach ($this->xmlMappings as $xmlMapping) {
  311.             $loaders[] = new XmlFileLoader($xmlMapping);
  312.         }
  313.         foreach ($this->yamlMappings as $yamlMappings) {
  314.             $loaders[] = new YamlFileLoader($yamlMappings);
  315.         }
  316.         foreach ($this->methodMappings as $methodName) {
  317.             $loaders[] = new StaticMethodLoader($methodName);
  318.         }
  319.         if ($this->enableAnnotationMapping) {
  320.             $loaders[] = new AnnotationLoader($this->annotationReader);
  321.         }
  322.         return array_merge($loaders$this->loaders);
  323.     }
  324.     /**
  325.      * Builds and returns a new validator object.
  326.      *
  327.      * @return ValidatorInterface
  328.      */
  329.     public function getValidator()
  330.     {
  331.         $metadataFactory $this->metadataFactory;
  332.         if (!$metadataFactory) {
  333.             $loaders $this->getLoaders();
  334.             $loader null;
  335.             if (\count($loaders) > 1) {
  336.                 $loader = new LoaderChain($loaders);
  337.             } elseif (=== \count($loaders)) {
  338.                 $loader $loaders[0];
  339.             }
  340.             $metadataFactory = new LazyLoadingMetadataFactory($loader$this->mappingCache);
  341.         }
  342.         $validatorFactory $this->validatorFactory ?: new ConstraintValidatorFactory();
  343.         $translator $this->translator;
  344.         if (null === $translator) {
  345.             $translator = new class() implements TranslatorInterfaceLocaleAwareInterface {
  346.                 use TranslatorTrait;
  347.             };
  348.             // Force the locale to be 'en' when no translator is provided rather than relying on the Intl default locale
  349.             // This avoids depending on Intl or the stub implementation being available. It also ensures that Symfony
  350.             // validation messages are pluralized properly even when the default locale gets changed because they are in
  351.             // English.
  352.             $translator->setLocale('en');
  353.         }
  354.         $contextFactory = new ExecutionContextFactory($translator$this->translationDomain);
  355.         return new RecursiveValidator($contextFactory$metadataFactory$validatorFactory$this->initializers);
  356.     }
  357. }