4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Validator;
14 use Doctrine\Common\Annotations\AnnotationReader;
15 use Doctrine\Common\Annotations\CachedReader;
16 use Doctrine\Common\Annotations\Reader;
17 use Doctrine\Common\Cache\ArrayCache;
18 use Symfony\Component\Translation\IdentityTranslator;
19 use Symfony\Component\Translation\TranslatorInterface;
20 use Symfony\Component\Validator\Context\ExecutionContextFactory;
21 use Symfony\Component\Validator\Exception\ValidatorException;
22 use Symfony\Component\Validator\Mapping\Cache\CacheInterface;
23 use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
24 use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
25 use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
26 use Symfony\Component\Validator\Mapping\Loader\LoaderChain;
27 use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
28 use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
29 use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader;
30 use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;
31 use Symfony\Component\Validator\Validator\RecursiveValidator;
34 * The default implementation of {@link ValidatorBuilderInterface}.
36 * @author Bernhard Schussek <bschussek@gmail.com>
38 class ValidatorBuilder implements ValidatorBuilderInterface
43 private $initializers = array();
48 private $xmlMappings = array();
53 private $yamlMappings = array();
58 private $methodMappings = array();
63 private $annotationReader;
66 * @var MetadataFactoryInterface|null
68 private $metadataFactory;
71 * @var ConstraintValidatorFactoryInterface|null
73 private $validatorFactory;
76 * @var CacheInterface|null
78 private $metadataCache;
81 * @var TranslatorInterface|null
88 private $translationDomain;
93 public function addObjectInitializer(ObjectInitializerInterface $initializer)
95 $this->initializers[] = $initializer;
103 public function addObjectInitializers(array $initializers)
105 $this->initializers = array_merge($this->initializers, $initializers);
113 public function addXmlMapping($path)
115 if (null !== $this->metadataFactory) {
116 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
119 $this->xmlMappings[] = $path;
127 public function addXmlMappings(array $paths)
129 if (null !== $this->metadataFactory) {
130 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
133 $this->xmlMappings = array_merge($this->xmlMappings, $paths);
141 public function addYamlMapping($path)
143 if (null !== $this->metadataFactory) {
144 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
147 $this->yamlMappings[] = $path;
155 public function addYamlMappings(array $paths)
157 if (null !== $this->metadataFactory) {
158 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
161 $this->yamlMappings = array_merge($this->yamlMappings, $paths);
169 public function addMethodMapping($methodName)
171 if (null !== $this->metadataFactory) {
172 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
175 $this->methodMappings[] = $methodName;
183 public function addMethodMappings(array $methodNames)
185 if (null !== $this->metadataFactory) {
186 throw new ValidatorException('You cannot add custom mappings after setting a custom metadata factory. Configure your metadata factory instead.');
189 $this->methodMappings = array_merge($this->methodMappings, $methodNames);
197 public function enableAnnotationMapping(Reader $annotationReader = null)
199 if (null !== $this->metadataFactory) {
200 throw new ValidatorException('You cannot enable annotation mapping after setting a custom metadata factory. Configure your metadata factory instead.');
203 if (null === $annotationReader) {
204 if (!class_exists('Doctrine\Common\Annotations\AnnotationReader') || !class_exists('Doctrine\Common\Cache\ArrayCache')) {
205 throw new \RuntimeException('Enabling annotation based constraint mapping requires the packages doctrine/annotations and doctrine/cache to be installed.');
208 $annotationReader = new CachedReader(new AnnotationReader(), new ArrayCache());
211 $this->annotationReader = $annotationReader;
219 public function disableAnnotationMapping()
221 $this->annotationReader = null;
229 public function setMetadataFactory(MetadataFactoryInterface $metadataFactory)
231 if (count($this->xmlMappings) > 0 || count($this->yamlMappings) > 0 || count($this->methodMappings) > 0 || null !== $this->annotationReader) {
232 throw new ValidatorException('You cannot set a custom metadata factory after adding custom mappings. You should do either of both.');
235 $this->metadataFactory = $metadataFactory;
243 public function setMetadataCache(CacheInterface $cache)
245 if (null !== $this->metadataFactory) {
246 throw new ValidatorException('You cannot set a custom metadata cache after setting a custom metadata factory. Configure your metadata factory instead.');
249 $this->metadataCache = $cache;
257 public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory)
259 $this->validatorFactory = $validatorFactory;
267 public function setTranslator(TranslatorInterface $translator)
269 $this->translator = $translator;
277 public function setTranslationDomain($translationDomain)
279 $this->translationDomain = $translationDomain;
285 * @return LoaderInterface[]
287 public function getLoaders()
291 foreach ($this->xmlMappings as $xmlMapping) {
292 $loaders[] = new XmlFileLoader($xmlMapping);
295 foreach ($this->yamlMappings as $yamlMappings) {
296 $loaders[] = new YamlFileLoader($yamlMappings);
299 foreach ($this->methodMappings as $methodName) {
300 $loaders[] = new StaticMethodLoader($methodName);
303 if ($this->annotationReader) {
304 $loaders[] = new AnnotationLoader($this->annotationReader);
313 public function getValidator()
315 $metadataFactory = $this->metadataFactory;
317 if (!$metadataFactory) {
318 $loaders = $this->getLoaders();
321 if (count($loaders) > 1) {
322 $loader = new LoaderChain($loaders);
323 } elseif (1 === count($loaders)) {
324 $loader = $loaders[0];
327 $metadataFactory = new LazyLoadingMetadataFactory($loader, $this->metadataCache);
330 $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory();
331 $translator = $this->translator;
333 if (null === $translator) {
334 $translator = new IdentityTranslator();
335 // Force the locale to be 'en' when no translator is provided rather than relying on the Intl default locale
336 // This avoids depending on Intl or the stub implementation being available. It also ensures that Symfony
337 // validation messages are pluralized properly even when the default locale gets changed because they are in
339 $translator->setLocale('en');
342 $contextFactory = new ExecutionContextFactory($translator, $this->translationDomain);
344 return new RecursiveValidator($contextFactory, $metadataFactory, $validatorFactory, $this->initializers);