Skip to content

Added Validator component documentation #6584

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The Components
stopwatch
templating/index
translation/index
validator/index
yaml/index

.. include:: /components/map.rst.inc
5 changes: 5 additions & 0 deletions components/map.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@
* :doc:`/components/translation/usage`
* :doc:`/components/translation/custom_formats`

* :doc:`/components/validator/index`

* :doc:`/components/validator/introduction`
* :doc:`/components/validator/resources`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing the metadata file here


* :doc:`/components/yaml/index`

* :doc:`/components/yaml/introduction`
Expand Down
9 changes: 9 additions & 0 deletions components/validator/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Validator
=========

.. toctree::
:maxdepth: 2

introduction
resources
metadata
78 changes: 78 additions & 0 deletions components/validator/introduction.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
.. 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 2 different ways:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two


* :doc:`Install it via Composer </components/using_components>` (``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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing trailing comma

));

if (0 !== count($violations)) {
// there are errors, now you can show them
foreach ($violations as $violation) {
echo $violation->getMessage().'<br>';
}
}

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, use the
:class:`Symfony\\Component\\Validator\\ValidatorBuilder` class to configure the
``Validator`` class::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph looks weird to me. What is the goal behind it and the following code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, but the paragraph tries to say: "if you want to validate objects, don't use the createValidator() method. You have to build a validator with the builder class". How would you reword it or improve it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I see with this right now is that the code that is shown after the sentence is the same that is already executed in the background when using Validation::createValidator(). I would then instead just write that you need to configure the validator and link to the resources chapter instead.


use Symfony\Component\Validator\Validation;

$validator = Validation::createValidatorBuilder()
// ... build a custom instance of the Validator
->getValidator();

In the next sections, you'll learn about all the validator features that you
can configure:

* :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
79 changes: 79 additions & 0 deletions components/validator/metadata.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.. 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',
)));
}
}

.. note::

The keen-eyed among you will have noticed that the prefix of the getter
(``get`` or ``is``) is omitted in the mapping. This allows you to move the
constraint to a property with the same name later (or vice versa) without
changing your validation logic.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this (you will later have to use addPropertyConstraint() instead of addGetterConstraint() nonetheless, don't you?).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove this note then?


Classes
-------

Some constraints allow to validate the entire object. For example, the
:doc:`Callback </reference/constraints/Callback>` constraint is a generic
constraint that's applied to the class itself.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use cases misses an example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't add this example ... but I've created an issue to not forget about this: #6738

201 changes: 201 additions & 0 deletions components/validator/resources.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
.. 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 retrieves that metadata using a set of loaders.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"collects" instead of "retrieves"


.. 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::

You can call this method multiple times to add several method names. You can
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] call addMethodMapping() multiple [...]

also use :method:`Symfony\\Component\\Validator\\ValidatorBuilder::addMethodMappings`
to set an array of supported method names.

The FileLoaders
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 </components/yaml/introduction>`.

.. 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;
// ...

/**
* @Assert\NotBlank()
*/
protected $name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add the class here:

class USer
{
    /**
     *@Assert\NotBlank
     */
    private $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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 to a :class:`Symfony\\Component\\Validator\\Mapping\\ClassMetadata`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] converted into a [...]

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