Skip to content

Commit 86c67e8

Browse files
committed
feature #4233 2.5 Validation API changes (nicolassing, lashae, Rootie, 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
2 parents d618fd0 + 9874d8e commit 86c67e8

File tree

5 files changed

+112
-23
lines changed

5 files changed

+112
-23
lines changed

book/validation.rst

+17-4
Original file line numberDiff line numberDiff line change
@@ -822,9 +822,13 @@ With this configuration, there are three validation groups:
822822
fields only.
823823

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

827-
$errors = $validator->validate($author, array('registration'));
827+
// If you're using the new 2.5 validation API (you probably are!)
828+
$errors = $validator->validate($author, null, array('registration'));
829+
830+
// If you're using the old 2.4 validation API
831+
// $errors = $validator->validate($author, array('registration'));
828832

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

11911195
// use the validator to validate the value
1196+
// If you're using the new 2.5 validation API (you probably are!)
1197+
$errorList = $this->get('validator')->validate(
1198+
$email,
1199+
$emailConstraint
1200+
);
1201+
1202+
// If you're using the old 2.4 validation API
1203+
/*
11921204
$errorList = $this->get('validator')->validateValue(
11931205
$email,
11941206
$emailConstraint
11951207
);
1208+
*/
11961209

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

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

1215-
The ``validateValue`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList`
1228+
The ``validate`` method returns a :class:`Symfony\\Component\\Validator\\ConstraintViolationList`
12161229
object, which acts just like an array of errors. Each error in the collection
12171230
is a :class:`Symfony\\Component\\Validator\\ConstraintViolation` object,
12181231
which holds the error message on its ``getMessage`` method.

cookbook/bundles/best_practices.rst

+42
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,48 @@ semantic configuration described in the cookbook.
335335
If you are defining services, they should also be prefixed with the bundle
336336
alias.
337337

338+
Custom Validation Constraints
339+
-----------------------------
340+
341+
Starting with Symfony 2.5, a new Validation API was introduced. In fact,
342+
there are 3 modes, which the user can configure in their project:
343+
344+
* 2.4: the original 2.4 and earlier validation API;
345+
* 2.5: the new 2.5 and later validation API;
346+
* 2.5-BC: the new 2.5 API with a backwards-compatible layer so that the
347+
2.4 API still works. This is only available in PHP 5.3.9+.
348+
349+
As a bundle author, you'll want to support *both* API's, since some users
350+
may still be using the 2.4 API. Specifically, if your bundle adds a violation
351+
directly to the :class:`Symfony\\Component\\Validator\\Context\\ExecutionContext`
352+
(e.g. like in a custom validation constraint), you'll need to check for which
353+
API is being used. The following code, would work for *all* users::
354+
355+
use Symfony\Component\Validator\ConstraintValidator;
356+
use Symfony\Component\Validator\Constraint;
357+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
358+
// ...
359+
360+
class ContainsAlphanumericValidator extends ConstraintValidator
361+
{
362+
public function validate($value, Constraint $constraint)
363+
{
364+
if ($this->context instanceof ExecutionContextInterface) {
365+
// the 2.5 API
366+
$this->context->buildViolation($constraint->message)
367+
->setParameter('%string%', $value)
368+
->addViolation();
369+
);
370+
} else {
371+
// the 2.4 API
372+
$this->context->addViolation(
373+
$constraint->message,
374+
array('%string%' => $value)
375+
);
376+
}
377+
}
378+
}
379+
338380
Learn more from the Cookbook
339381
----------------------------
340382

cookbook/form/unit_testing.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ on other extensions. You need add those extensions to the factory object::
185185
{
186186
parent::setUp();
187187
188-
$validator = $this->getMock('\Symfony\Component\Validator\ValidatorInterface');
188+
$validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface');
189189
$validator->method('validate')->will($this->returnValue(new ConstraintViolationList()));
190190

191191
$this->factory = Forms::createFormFactoryBuilder()

cookbook/validation/custom_constraint.rst

+20-8
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,34 @@ The validator class is also simple, and only has one required method ``validate(
6565
public function validate($value, Constraint $constraint)
6666
{
6767
if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
68+
// If you're using the new 2.5 validation API (you probably are!)
69+
$this->context->buildViolation($constraint->message)
70+
->setParameter('%string%', $value)
71+
->addViolation();
72+
);
73+
74+
// If you're using the old 2.4 validation API
75+
/*
6876
$this->context->addViolation(
6977
$constraint->message,
7078
array('%string%' => $value)
7179
);
80+
*/
7281
}
7382
}
7483
}
7584

76-
.. note::
77-
78-
The ``validate`` method does not return a value; instead, it adds violations
79-
to the validator's ``context`` property with an ``addViolation`` method
80-
call if there are validation failures. Therefore, a value could be considered
81-
as being valid if it causes no violations to be added to the context.
82-
The first parameter of the ``addViolation`` call is the error message to
83-
use for that violation.
85+
Inside ``validate``, you don't need to return a value. Instead, you add violations
86+
to the validator's ``context`` property and a value will be considered valid
87+
if it causes no violations. The ``buildViolation`` method takes the error
88+
message as its argument and returns an instance of
89+
:class:`Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface`.
90+
The ``addViolation`` method call finally adds the violation to the context.
91+
92+
.. versionadded:: 2.5
93+
The ``buildViolation`` method was added in Symfony 2.5. For usage examples
94+
with older Symfony versions, see the corresponding versions of this documentation
95+
page.
8496

8597
Using the new Validator
8698
-----------------------

reference/constraints/Callback.rst

+32-10
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ Configuration
5050
namespace Acme\BlogBundle\Entity;
5151
5252
use Symfony\Component\Validator\Constraints as Assert;
53-
use Symfony\Component\Validator\ExecutionContextInterface;
53+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
54+
// if you're using the older 2.4 validation API, you'll need this instead
55+
// use Symfony\Component\Validator\ExecutionContextInterface;
5456
5557
class Author
5658
{
@@ -100,7 +102,9 @@ can set "violations" directly on this object and determine to which field
100102
those errors should be attributed::
101103

102104
// ...
103-
use Symfony\Component\Validator\ExecutionContextInterface;
105+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
106+
// if you're using the older 2.4 validation API, you'll need this instead
107+
// use Symfony\Component\Validator\ExecutionContextInterface;
104108

105109
class Author
106110
{
@@ -114,16 +118,27 @@ those errors should be attributed::
114118

115119
// check if the name is actually a fake name
116120
if (in_array($this->getFirstName(), $fakeNames)) {
121+
// If you're using the new 2.5 validation API (you probably are!)
122+
$context->buildViolation('This name sounds totally fake!')
123+
->atPath('firstName')
124+
->addViolation();
125+
126+
// If you're using the old 2.4 validation API
127+
/*
117128
$context->addViolationAt(
118129
'firstName',
119-
'This name sounds totally fake!',
120-
array(),
121-
null
130+
'This name sounds totally fake!'
122131
);
132+
*/
123133
}
124134
}
125135
}
126136

137+
.. versionadded:: 2.5
138+
The ``buildViolation`` method was added in Symfony 2.5. For usage examples
139+
with older Symfony versions, see the corresponding versions of this documentation
140+
page.
141+
127142
Static Callbacks
128143
----------------
129144

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

138153
// check if the name is actually a fake name
139154
if (in_array($object->getFirstName(), $fakeNames)) {
155+
// If you're using the new 2.5 validation API (you probably are!)
156+
$context->buildViolation('This name sounds totally fake!')
157+
->atPath('firstName')
158+
->addViolation()
159+
;
160+
161+
// If you're using the old 2.4 validation API
140162
$context->addViolationAt(
141163
'firstName',
142-
'This name sounds totally fake!',
143-
array(),
144-
null
164+
'This name sounds totally fake!'
145165
);
146166
}
147167
}
@@ -156,7 +176,9 @@ your validation function is ``Vendor\Package\Validator::validate()``::
156176

157177
namespace Vendor\Package;
158178

159-
use Symfony\Component\Validator\ExecutionContextInterface;
179+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
180+
// if you're using the older 2.4 validation API, you'll need this instead
181+
// use Symfony\Component\Validator\ExecutionContextInterface;
160182

161183
class Validator
162184
{
@@ -274,7 +296,7 @@ callback method:
274296

275297
* A closure.
276298

277-
Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\ExecutionContextInterface`
299+
Concrete callbacks receive an :class:`Symfony\\Component\\Validator\\Context\\ExecutionContextInterface`
278300
instance as only argument.
279301

280302
Static or closure callbacks receive the validated object as the first argument

0 commit comments

Comments
 (0)