Skip to content

Commit

Permalink
feature #4233 2.5 Validation API changes (nicolassing, lashae, Rootie…
Browse files Browse the repository at this point in the history
…, weaverryan)

This PR was merged into the 2.5 branch.

Discussion
----------

2.5 Validation API changes

| Q             | A
| ------------- | ---
| Doc fix?      | no
| New docs?     | yes
| Applies to    | 2.5
| Fixed tickets | #4094

Hi guys!

This takes the work in #4056, #4105 and #4161 and extends it based on some feedback. Basically, the whole validation stuff is quite difficult, because:

A) We want to show the non-deprecated methods so people use the new stuff
B) We don't want to confuse users on the 2.4 API (even though this number of users should be very small, as it would require you to have started a project in the past and be using 5.3.9 and lower #4105 (comment))

This solution is to show the new way, but always show the old way in comments. This would check of A and B in #4094.

Thanks!

Commits
-------

9874d8e [#4233][#4094] Making validateValue and validate changes
94fc520 Minor tweaks and a missing location thanks to xabbuh and WouterJ
f97ba7a Fixes thanks to @xabbuh
279d8d6 Adding a section about keeping BC in a re-usable bundle
280440e Adding details about the 2.4 API as comments
e658b56 added a versionadded comment to Callback.rst
70c5ca1 Update custom_contraint.rst to meet the new 2.5 api
5dfe499 Don't use deprecated functions in Callback.rst
f4380ed Update Callback.rst
042dcf9 Replace addViolationAt (deprecated) by buildViolation
  • Loading branch information
weaverryan committed Oct 18, 2014
2 parents d618fd0 + 9874d8e commit 86c67e8
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 23 deletions.
21 changes: 17 additions & 4 deletions book/validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,13 @@ With this configuration, there are three validation groups:
fields only.

To tell the validator to use a specific group, pass one or more group names
as the second argument to the ``validate()`` method::
as the third argument to the ``validate()`` method::

$errors = $validator->validate($author, array('registration'));
// If you're using the new 2.5 validation API (you probably are!)
$errors = $validator->validate($author, null, array('registration'));

// If you're using the old 2.4 validation API
// $errors = $validator->validate($author, array('registration'));

If no groups are specified, all constraints that belong in group ``Default``
will be applied.
Expand Down Expand Up @@ -1189,10 +1193,19 @@ it looks like this::
$emailConstraint->message = 'Invalid email address';

// use the validator to validate the value
// If you're using the new 2.5 validation API (you probably are!)
$errorList = $this->get('validator')->validate(
$email,
$emailConstraint
);

// If you're using the old 2.4 validation API
/*
$errorList = $this->get('validator')->validateValue(
$email,
$emailConstraint
);
*/

if (count($errorList) == 0) {
// this IS a valid email address, do something
Expand All @@ -1206,13 +1219,13 @@ it looks like this::
// ...
}

By calling ``validateValue`` on the validator, you can pass in a raw value and
By calling ``validate`` on the validator, you can pass in a raw value and
the constraint object that you want to validate that value against. A full
list of the available constraints - as well as the full class name for each
constraint - is available in the :doc:`constraints reference </reference/constraints>`
section .

The ``validateValue`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList`
The ``validate`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList`
object, which acts just like an array of errors. Each error in the collection
is a :class:`Symfony\\Component\\Validator\\ConstraintViolation` object,
which holds the error message on its ``getMessage`` method.
Expand Down
42 changes: 42 additions & 0 deletions cookbook/bundles/best_practices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,48 @@ semantic configuration described in the cookbook.
If you are defining services, they should also be prefixed with the bundle
alias.

Custom Validation Constraints
-----------------------------

Starting with Symfony 2.5, a new Validation API was introduced. In fact,
there are 3 modes, which the user can configure in their project:

* 2.4: the original 2.4 and earlier validation API;
* 2.5: the new 2.5 and later validation API;
* 2.5-BC: the new 2.5 API with a backwards-compatible layer so that the
2.4 API still works. This is only available in PHP 5.3.9+.

As a bundle author, you'll want to support *both* API's, since some users
may still be using the 2.4 API. Specifically, if your bundle adds a violation
directly to the :class:`Symfony\\Component\\Validator\\Context\\ExecutionContext`
(e.g. like in a custom validation constraint), you'll need to check for which
API is being used. The following code, would work for *all* users::

use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
// ...

class ContainsAlphanumericValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if ($this->context instanceof ExecutionContextInterface) {
// the 2.5 API
$this->context->buildViolation($constraint->message)
->setParameter('%string%', $value)
->addViolation();
);
} else {
// the 2.4 API
$this->context->addViolation(
$constraint->message,
array('%string%' => $value)
);
}
}
}

Learn more from the Cookbook
----------------------------

Expand Down
2 changes: 1 addition & 1 deletion cookbook/form/unit_testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ on other extensions. You need add those extensions to the factory object::
{
parent::setUp();
$validator = $this->getMock('\Symfony\Component\Validator\ValidatorInterface');
$validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface');
$validator->method('validate')->will($this->returnValue(new ConstraintViolationList()));

$this->factory = Forms::createFormFactoryBuilder()
Expand Down
28 changes: 20 additions & 8 deletions cookbook/validation/custom_constraint.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,34 @@ The validator class is also simple, and only has one required method ``validate(
public function validate($value, Constraint $constraint)
{
if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
// If you're using the new 2.5 validation API (you probably are!)
$this->context->buildViolation($constraint->message)
->setParameter('%string%', $value)
->addViolation();
);

// If you're using the old 2.4 validation API
/*
$this->context->addViolation(
$constraint->message,
array('%string%' => $value)
);
*/
}
}
}

.. note::

The ``validate`` method does not return a value; instead, it adds violations
to the validator's ``context`` property with an ``addViolation`` method
call if there are validation failures. Therefore, a value could be considered
as being valid if it causes no violations to be added to the context.
The first parameter of the ``addViolation`` call is the error message to
use for that violation.
Inside ``validate``, you don't need to return a value. Instead, you add violations
to the validator's ``context`` property and a value will be considered valid
if it causes no violations. The ``buildViolation`` method takes the error
message as its argument and returns an instance of
:class:`Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface`.
The ``addViolation`` method call finally adds the violation to the context.

.. versionadded:: 2.5
The ``buildViolation`` method was added in Symfony 2.5. For usage examples
with older Symfony versions, see the corresponding versions of this documentation
page.

Using the new Validator
-----------------------
Expand Down
42 changes: 32 additions & 10 deletions reference/constraints/Callback.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ Configuration
namespace Acme\BlogBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\ExecutionContextInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
// if you're using the older 2.4 validation API, you'll need this instead
// use Symfony\Component\Validator\ExecutionContextInterface;
class Author
{
Expand Down Expand Up @@ -100,7 +102,9 @@ can set "violations" directly on this object and determine to which field
those errors should be attributed::

// ...
use Symfony\Component\Validator\ExecutionContextInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
// if you're using the older 2.4 validation API, you'll need this instead
// use Symfony\Component\Validator\ExecutionContextInterface;

class Author
{
Expand All @@ -114,16 +118,27 @@ those errors should be attributed::

// check if the name is actually a fake name
if (in_array($this->getFirstName(), $fakeNames)) {
// If you're using the new 2.5 validation API (you probably are!)
$context->buildViolation('This name sounds totally fake!')
->atPath('firstName')
->addViolation();

// If you're using the old 2.4 validation API
/*
$context->addViolationAt(
'firstName',
'This name sounds totally fake!',
array(),
null
'This name sounds totally fake!'
);
*/
}
}
}

.. versionadded:: 2.5
The ``buildViolation`` method was added in Symfony 2.5. For usage examples
with older Symfony versions, see the corresponding versions of this documentation
page.

Static Callbacks
----------------

Expand All @@ -137,11 +152,16 @@ have access to the object instance, they receive the object as the first argumen

// check if the name is actually a fake name
if (in_array($object->getFirstName(), $fakeNames)) {
// If you're using the new 2.5 validation API (you probably are!)
$context->buildViolation('This name sounds totally fake!')
->atPath('firstName')
->addViolation()
;

// If you're using the old 2.4 validation API
$context->addViolationAt(
'firstName',
'This name sounds totally fake!',
array(),
null
'This name sounds totally fake!'
);
}
}
Expand All @@ -156,7 +176,9 @@ your validation function is ``Vendor\Package\Validator::validate()``::

namespace Vendor\Package;

use Symfony\Component\Validator\ExecutionContextInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
// if you're using the older 2.4 validation API, you'll need this instead
// use Symfony\Component\Validator\ExecutionContextInterface;

class Validator
{
Expand Down Expand Up @@ -274,7 +296,7 @@ callback method:

* A closure.

Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\ExecutionContextInterface`
Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\Context\\ExecutionContextInterface`
instance as only argument.

Static or closure callbacks receive the validated object as the first argument
Expand Down

0 comments on commit 86c67e8

Please sign in to comment.