diff --git a/components/index.rst b/components/index.rst index 739b9e84f9c..3079cc63867 100644 --- a/components/index.rst +++ b/components/index.rst @@ -28,6 +28,7 @@ The Components stopwatch templating/index translation/index + validator/index yaml/index .. include:: /components/map.rst.inc diff --git a/components/map.rst.inc b/components/map.rst.inc index 38bf2e07748..4237ef3b679 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -135,6 +135,12 @@ * :doc:`/components/translation/usage` * :doc:`/components/translation/custom_formats` +* :doc:`/components/validator/index` + + * :doc:`/components/validator/introduction` + * :doc:`/components/validator/resources` + * :doc:`/components/validator/metadata` + * :doc:`/components/yaml/index` * :doc:`/components/yaml/introduction` diff --git a/components/validator/index.rst b/components/validator/index.rst new file mode 100644 index 00000000000..22cabeeaae6 --- /dev/null +++ b/components/validator/index.rst @@ -0,0 +1,9 @@ +Validator +========= + +.. toctree:: + :maxdepth: 2 + + introduction + resources + metadata diff --git a/components/validator/introduction.rst b/components/validator/introduction.rst new file mode 100644 index 00000000000..37915f170ed --- /dev/null +++ b/components/validator/introduction.rst @@ -0,0 +1,68 @@ +.. index:: + single: Validator + single: Components; Validator + +The Validator Component +======================= + + The Validator component provides tools to validate values following the + `JSR-303 Bean Validation specification`_. + +Installation +------------ + +You can install the component in two different ways: + +* :doc:`Install it via Composer ` (``symfony/validator`` on `Packagist`_); +* Use the official Git repository (https://github.com/symfony/Validator). + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +The Validator component behavior is based on two concepts: + +* Contraints, which define the rules to be validated; +* Validators, which are the classes that contain the actual validation logic. + +The following example shows how to validate that a string is at least 10 +characters long:: + + use Symfony\Component\Validator\Validation; + use Symfony\Component\Validator\Constraints\Length; + use Symfony\Component\Validator\Constraints\NotBlank; + + $validator = Validation::createValidator(); + $violations = $validator->validate('Bernhard', array( + new Length(array('min' => 10)), + new NotBlank(), + )); + + if (0 !== count($violations)) { + // there are errors, now you can show them + foreach ($violations as $violation) { + echo $violation->getMessage().'
'; + } + } + +Retrieving a Validator Instance +------------------------------- + +The :class:`Symfony\\Component\\Validator\\Validator` class is the main access +point of the Validator component. To create a new instance of this class, it's +recommended to use the :class:`Symfony\\Component\\Validator\\Validation` class:: + + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidator(); + +This ``$validator`` object can validate simple variables such as strings, numbers +and arrays, but it can't validate objects. To do so, configure the +``Validator`` class as explained in the next sections: + +* :doc:`/components/validator/resources` +* :doc:`/components/validator/metadata` + +.. _`JSR-303 Bean Validation specification`: http://jcp.org/en/jsr/detail?id=303 +.. _Packagist: https://packagist.org/packages/symfony/validator diff --git a/components/validator/metadata.rst b/components/validator/metadata.rst new file mode 100755 index 00000000000..645ab9f0ac9 --- /dev/null +++ b/components/validator/metadata.rst @@ -0,0 +1,72 @@ +.. index:: + single: Validator; Metadata + +Metadata +======== + +The :class:`Symfony\\Component\\Validator\\Mapping\\ClassMetadata` class +represents and manages all the configured constraints on a given class. + +Properties +---------- + +The Validator component can validate public, protected or private properties. +The following example shows how to validate that the ``$firstName`` property of +the ``Author`` class has at least 3 characters:: + + // ... + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + private $firstName; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('firstName', new Assert\NotBlank()); + $metadata->addPropertyConstraint( + 'firstName', + new Assert\Length(array("min" => 3)) + ); + } + } + +Getters +------- + +Constraints can also be applied to the value returned by any public *getter* +method, which are the methods whose names start with ``get`` or ``is``. This +feature allows to validate your objects dynamically. + +Suppose that, for security reasons, you want to validate that a password field +doesn't match the first name of the user. First, create a public method called +``isPasswordSafe`` to define this custom validation logic:: + + public function isPasswordSafe() + { + return $this->firstName !== $this->password; + } + +Then, add the Validator component configuration to the class:: + + // ... + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addGetterConstraint('passwordSafe', new Assert\True(array( + 'message' => 'The password cannot match your first name', + ))); + } + } + +Classes +------- + +Some constraints allow to validate the entire object. For example, the +:doc:`Callback ` constraint is a generic +constraint that's applied to the class itself. diff --git a/components/validator/resources.rst b/components/validator/resources.rst new file mode 100644 index 00000000000..b5251eb630c --- /dev/null +++ b/components/validator/resources.rst @@ -0,0 +1,205 @@ +.. index:: + single: Validator; Loading Resources + +Loading Resources +================= + +The Validator component uses metadata to validate a value. This metadata defines +how a class, array or any other value should be validated. When validating a +class, the metadata is defined by the class itself. When validating simple values, +the metadata must be passed to the validation methods. + +Class metadata can be defined in a configuration file or in the class itself. +The Validator component collects that metadata using a set of loaders. + +.. seealso:: + + You'll learn how to define the metadata in :doc:`metadata`. + +The StaticMethodLoader +---------------------- + +The most basic loader is the +:class:`Symfony\\Component\\Validator\\Mapping\\Loader\\StaticMethodLoader`. +This loader gets the metadata by calling a static method of the class. The name +of the method is configured using the +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::addMethodMapping` +method of the validator builder:: + + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidatorBuilder() + ->addMethodMapping('loadValidatorMetadata') + ->getValidator(); + +In this example, the validation metadata is retrieved executing the +``loadValidatorMetadata()`` method of the class:: + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + protected $name; + + public static function loadValidatorMatadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('name', new Assert\NotBlank()); + $metadata->addPropertyConstraint('name', new Asert\Length(array( + 'min' => 5, + 'max' => 20, + ))); + } + } + +.. tip:: + + Instead of calling ``addMethodMapping()`` multiple times to add several + method names, you can also use + :method:`Symfony\\Component\\Validator\\ValidatorBuilder::addMethodMappings` + to set an array of supported method names. + +The File Loaders +---------------- + +The component also provides two file loaders, one to load YAML files and one to +load XML files. Use +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::addYamlMapping` or +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::addXmlMapping` to +configure the locations of these files:: + + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidatorBuilder() + ->addYamlMapping('config/validation.yml') + ->getValidator(); + +.. note:: + + If you want to load YAML mapping files then you will also need to install + :doc:`the Yaml component `. + +.. tip:: + + Just like with the method mappings, you can also use + :method:`Symfony\\Component\\Validator\\ValidatorBuilder::addYamlMappings` and + :method:`Symfony\\Component\\Validator\\ValidatorBuilder::addXmlMappings` + to configure an array of file paths. + +The AnnotationLoader +-------------------- + +At last, the component provides an +:class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader` to get +the metadata from the annotations of the class. Annotations are defined as ``@`` +prefixed classes included in doc block comments (``/** ... */``). For example:: + + use Symfony\Component\Validator\Constraints as Assert; + // ... + + class User + { + /** + * @Assert\NotBlank() + */ + protected $name; + } + +To enable the annotation loader, call the +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` +method. It takes an optional annotation reader instance, which defaults to +``Doctrine\Common\Annotations\AnnotationReader``:: + + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->getValidator(); + +To disable the annotation loader after it was enabled, call +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::disableAnnotationMapping`. + +.. note:: + + In order to use the annotation loader, you should have installed the + ``doctrine/annotations`` and ``doctrine/cache`` packages from `Packagist`_. + +Using Multiple Loaders +---------------------- + +The component provides a +:class:`Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderChain` class to +execute several loaders sequentially in the same order they were defined: + +The ``ValidatorBuilder`` will already take care of this when you configure +multiple mappings:: + + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->addMethodMapping('loadValidatorMetadata') + ->addXmlMapping('config/validation.xml') + ->getValidator(); + +Caching +------- + +Using many loaders to load metadata from different places is convenient, but it +can slow down your application because each file needs to be parsed, validated +and converted into a :class:`Symfony\\Component\\Validator\\Mapping\\ClassMetadata` +instance. To solve this problem, you can cache the ``ClassMetadata`` information. + +The Validator component comes with an +:class:`Symfony\\Component\\Validator\\Mapping\\Cache\\ApcCache` +implementation. You can easily create other cachers by creating a class which +implements :class:`Symfony\\Component\\Validator\\Mapping\\Cache\\CacheInterface`. + +.. note:: + + The loaders already use a singleton load mechanism. That means that the + loaders will only load and parse a file once and put that in a property, + which will then be used the next time it is asked for metadata. However, + the Validator still needs to merge all metadata of one class from every + loader when it is requested. + +Enable the cache calling the +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::setMetadataCache` +method of the Validator builder:: + + use Symfony\Component\Validator\Validation; + use Symfony\Component\Validator\Mapping\Cache\ApcCache; + + $validator = Validation::createValidatorBuilder() + // ... add loaders + ->setMetadataCache(new ApcCache('some_apc_prefix')); + ->getValidator(); + +Using a Custom MetadataFactory +------------------------------ + +All the loaders and the cache are passed to an instance of +:class:`Symfony\\Component\\Validator\\Mapping\\ClassMetadataFactory`. This +class is responsible for creating a ``ClassMetadata`` instance from all the +configured resources. + +You can also use a custom metadata factory implementation by creating a class +which implements +:class:`Symfony\\Component\\Validator\\MetadataFactoryInterface`. You can set +this custom implementation using +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::setMetadataFactory`:: + + use Acme\Validation\CustomMetadataFactory; + use Symfony\Component\Validator\Validation; + + $validator = Validation::createValidatorBuilder() + ->setMetadataFactory(new CustomMetadataFactory(...)); + ->getValidator(); + +.. caution:: + + Since you are using a custom metadata factory, you can't configure loaders + and caches using the ``add*Mapping()`` methods anymore. You now have to + inject them into your custom metadata factory yourself. + +.. _`Packagist`: https://packagist.org