Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Validator; Chris@0: Chris@0: use Doctrine\Common\Annotations\AnnotationReader; Chris@0: use Doctrine\Common\Annotations\CachedReader; Chris@0: use Doctrine\Common\Annotations\Reader; Chris@0: use Doctrine\Common\Cache\ArrayCache; Chris@0: use Symfony\Component\Translation\IdentityTranslator; Chris@0: use Symfony\Component\Translation\TranslatorInterface; Chris@0: use Symfony\Component\Validator\Context\ExecutionContextFactory; Chris@0: use Symfony\Component\Validator\Exception\ValidatorException; Chris@0: use Symfony\Component\Validator\Mapping\Cache\CacheInterface; Chris@0: use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory; Chris@0: use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; Chris@0: use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; Chris@0: use Symfony\Component\Validator\Mapping\Loader\LoaderChain; Chris@0: use Symfony\Component\Validator\Mapping\Loader\LoaderInterface; Chris@0: use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader; Chris@0: use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader; Chris@0: use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader; Chris@0: use Symfony\Component\Validator\Validator\RecursiveValidator; Chris@0: Chris@0: /** Chris@0: * The default implementation of {@link ValidatorBuilderInterface}. Chris@0: * Chris@0: * @author Bernhard Schussek Chris@0: */ Chris@0: class ValidatorBuilder implements ValidatorBuilderInterface Chris@0: { Chris@17: private $initializers = []; Chris@17: private $xmlMappings = []; Chris@17: private $yamlMappings = []; Chris@17: private $methodMappings = []; Chris@0: Chris@0: /** Chris@0: * @var Reader|null Chris@0: */ Chris@0: private $annotationReader; Chris@0: Chris@0: /** Chris@0: * @var MetadataFactoryInterface|null Chris@0: */ Chris@0: private $metadataFactory; Chris@0: Chris@0: /** Chris@0: * @var ConstraintValidatorFactoryInterface|null Chris@0: */ Chris@0: private $validatorFactory; Chris@0: Chris@0: /** Chris@0: * @var CacheInterface|null Chris@0: */ Chris@0: private $metadataCache; Chris@0: Chris@0: /** Chris@0: * @var TranslatorInterface|null Chris@0: */ Chris@0: private $translator; Chris@0: Chris@0: /** Chris@17: * @var string|null Chris@0: */ Chris@0: private $translationDomain; Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addObjectInitializer(ObjectInitializerInterface $initializer) Chris@0: { Chris@0: $this->initializers[] = $initializer; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addObjectInitializers(array $initializers) Chris@0: { Chris@0: $this->initializers = array_merge($this->initializers, $initializers); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addXmlMapping($path) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->xmlMappings[] = $path; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addXmlMappings(array $paths) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->xmlMappings = array_merge($this->xmlMappings, $paths); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addYamlMapping($path) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->yamlMappings[] = $path; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addYamlMappings(array $paths) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->yamlMappings = array_merge($this->yamlMappings, $paths); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addMethodMapping($methodName) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->methodMappings[] = $methodName; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addMethodMappings(array $methodNames) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->methodMappings = array_merge($this->methodMappings, $methodNames); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function enableAnnotationMapping(Reader $annotationReader = null) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot enable annotation mapping after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: if (null === $annotationReader) { Chris@0: if (!class_exists('Doctrine\Common\Annotations\AnnotationReader') || !class_exists('Doctrine\Common\Cache\ArrayCache')) { Chris@0: throw new \RuntimeException('Enabling annotation based constraint mapping requires the packages doctrine/annotations and doctrine/cache to be installed.'); Chris@0: } Chris@0: Chris@0: $annotationReader = new CachedReader(new AnnotationReader(), new ArrayCache()); Chris@0: } Chris@0: Chris@0: $this->annotationReader = $annotationReader; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function disableAnnotationMapping() Chris@0: { Chris@0: $this->annotationReader = null; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setMetadataFactory(MetadataFactoryInterface $metadataFactory) Chris@0: { Chris@17: if (\count($this->xmlMappings) > 0 || \count($this->yamlMappings) > 0 || \count($this->methodMappings) > 0 || null !== $this->annotationReader) { Chris@0: throw new ValidatorException('You cannot set a custom metadata factory after adding custom mappings. You should do either of both.'); Chris@0: } Chris@0: Chris@0: $this->metadataFactory = $metadataFactory; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setMetadataCache(CacheInterface $cache) Chris@0: { Chris@0: if (null !== $this->metadataFactory) { Chris@0: throw new ValidatorException('You cannot set a custom metadata cache after setting a custom metadata factory. Configure your metadata factory instead.'); Chris@0: } Chris@0: Chris@0: $this->metadataCache = $cache; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory) Chris@0: { Chris@0: $this->validatorFactory = $validatorFactory; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setTranslator(TranslatorInterface $translator) Chris@0: { Chris@0: $this->translator = $translator; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setTranslationDomain($translationDomain) Chris@0: { Chris@0: $this->translationDomain = $translationDomain; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * @return LoaderInterface[] Chris@0: */ Chris@0: public function getLoaders() Chris@0: { Chris@17: $loaders = []; Chris@0: Chris@0: foreach ($this->xmlMappings as $xmlMapping) { Chris@0: $loaders[] = new XmlFileLoader($xmlMapping); Chris@0: } Chris@0: Chris@0: foreach ($this->yamlMappings as $yamlMappings) { Chris@0: $loaders[] = new YamlFileLoader($yamlMappings); Chris@0: } Chris@0: Chris@0: foreach ($this->methodMappings as $methodName) { Chris@0: $loaders[] = new StaticMethodLoader($methodName); Chris@0: } Chris@0: Chris@0: if ($this->annotationReader) { Chris@0: $loaders[] = new AnnotationLoader($this->annotationReader); Chris@0: } Chris@0: Chris@0: return $loaders; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getValidator() Chris@0: { Chris@0: $metadataFactory = $this->metadataFactory; Chris@0: Chris@0: if (!$metadataFactory) { Chris@0: $loaders = $this->getLoaders(); Chris@0: $loader = null; Chris@0: Chris@17: if (\count($loaders) > 1) { Chris@0: $loader = new LoaderChain($loaders); Chris@17: } elseif (1 === \count($loaders)) { Chris@0: $loader = $loaders[0]; Chris@0: } Chris@0: Chris@0: $metadataFactory = new LazyLoadingMetadataFactory($loader, $this->metadataCache); Chris@0: } Chris@0: Chris@0: $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory(); Chris@0: $translator = $this->translator; Chris@0: Chris@0: if (null === $translator) { Chris@0: $translator = new IdentityTranslator(); Chris@0: // Force the locale to be 'en' when no translator is provided rather than relying on the Intl default locale Chris@0: // This avoids depending on Intl or the stub implementation being available. It also ensures that Symfony Chris@0: // validation messages are pluralized properly even when the default locale gets changed because they are in Chris@0: // English. Chris@0: $translator->setLocale('en'); Chris@0: } Chris@0: Chris@0: $contextFactory = new ExecutionContextFactory($translator, $this->translationDomain); Chris@0: Chris@0: return new RecursiveValidator($contextFactory, $metadataFactory, $validatorFactory, $this->initializers); Chris@0: } Chris@0: }