Skip to content

Commit 5eaa22b

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: Change secure.php.net link to php.net [Validator] Combine #13898 with recent changes [Serializer] Remove note about installing the FrameworkExtraBundle for using annotations [Validator] Unit Tests
2 parents 7f426b3 + afe07ab commit 5eaa22b

File tree

4 files changed

+90
-38
lines changed

4 files changed

+90
-38
lines changed

console.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ the console::
257257
'',
258258
]);
259259

260-
// the value returned by someMethod() can be an iterator (https://secure.php.net/iterator)
260+
// the value returned by someMethod() can be an iterator (https://php.net/iterator)
261261
// that generates and returns the messages with the 'yield' PHP keyword
262262
$output->writeln($this->someMethod());
263263

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
If the ``input`` option is set to ``string``, this option specifies the format
22
of the date. This must be a valid `PHP date format`_.
33

4-
.. _`PHP date format`: https://secure.php.net/manual/en/function.date.php
4+
.. _`PHP date format`: https://php.net/manual/en/function.date.php

reference/forms/types/time.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,4 @@ Form Variables
236236
| | | contains the input type to use (``datetime``, ``date`` or ``time``). |
237237
+--------------+-------------+----------------------------------------------------------------------+
238238

239-
.. _`PHP time format`: https://secure.php.net/manual/en/function.date.php
239+
.. _`PHP time format`: https://php.net/manual/en/function.date.php

validation/custom_constraint.rst

+87-35
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ First you need to create a Constraint class and extend :class:`Symfony\\Componen
2626
#[\Attribute]
2727
class ContainsAlphanumeric extends Constraint
2828
{
29-
public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.';
30-
public $mode = 'strict'; // If the constraint has configuration options, define them as public properties
29+
public string $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.';
30+
// If the constraint has configuration options, define them as public properties
31+
public string $mode = 'strict';
3132
}
3233
3334
Add ``@Annotation`` or ``#[\Attribute]`` to the constraint class if you want to
@@ -63,7 +64,7 @@ The validator class only has one required method ``validate()``::
6364

6465
class ContainsAlphanumericValidator extends ConstraintValidator
6566
{
66-
public function validate($value, Constraint $constraint)
67+
public function validate($value, Constraint $constraint): void
6768
{
6869
if (!$constraint instanceof ContainsAlphanumeric) {
6970
throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
@@ -97,7 +98,7 @@ The validator class only has one required method ``validate()``::
9798
}
9899
}
99100

100-
Inside ``validate``, you don't need to return a value. Instead, you add violations
101+
Inside ``validate()``, you don't need to return a value. Instead, you add violations
101102
to the validator's ``context`` property and a value will be considered valid
102103
if it causes no violations. The ``buildViolation()`` method takes the error
103104
message as its argument and returns an instance of
@@ -125,15 +126,15 @@ You can use custom validators like the ones provided by Symfony itself:
125126
126127
#[Assert\NotBlank]
127128
#[AcmeAssert\ContainsAlphanumeric(mode: 'loose')]
128-
protected $name;
129+
protected string $name;
129130
130131
// ...
131132
}
132133
133134
.. code-block:: yaml
134135
135136
# config/validator/validation.yaml
136-
App\Entity\AcmeEntity:
137+
App\Entity\User:
137138
properties:
138139
name:
139140
- NotBlank: ~
@@ -148,7 +149,7 @@ You can use custom validators like the ones provided by Symfony itself:
148149
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
149150
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
150151
151-
<class name="App\Entity\AcmeEntity">
152+
<class name="App\Entity\User">
152153
<property name="name">
153154
<constraint name="NotBlank"/>
154155
<constraint name="App\Validator\ContainsAlphanumeric">
@@ -160,18 +161,20 @@ You can use custom validators like the ones provided by Symfony itself:
160161
161162
.. code-block:: php
162163
163-
// src/Entity/AcmeEntity.php
164+
// src/Entity/User.php
164165
namespace App\Entity;
165166
166167
use App\Validator\ContainsAlphanumeric;
167168
use Symfony\Component\Validator\Constraints\NotBlank;
168169
use Symfony\Component\Validator\Mapping\ClassMetadata;
169170
170-
class AcmeEntity
171+
class User
171172
{
172-
public $name;
173+
protected string $name = '';
173174
174-
public static function loadValidatorMetadata(ClassMetadata $metadata)
175+
// ...
176+
177+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
175178
{
176179
$metadata->addPropertyConstraint('name', new NotBlank());
177180
$metadata->addPropertyConstraint('name', new ContainsAlphanumeric(['mode' => 'loose']));
@@ -200,22 +203,62 @@ Class Constraint Validator
200203
~~~~~~~~~~~~~~~~~~~~~~~~~~
201204

202205
Besides validating a single property, a constraint can have an entire class
203-
as its scope. You only need to add this to the ``Constraint`` class::
206+
as its scope.
207+
208+
For instance, imagine you also have a ``PaymentReceipt`` entity and you
209+
need to make sure the email of the receipt payload matches the user's
210+
email. First, create a constraint and override the ``getTargets()`` method::
211+
212+
// src/Validator/ConfirmedPaymentReceipt.php
213+
namespace App\Validator;
214+
215+
use Symfony\Component\Validator\Constraint;
204216

205-
public function getTargets()
217+
/**
218+
* @Annotation
219+
*/
220+
class ConfirmedPaymentReceipt extends Constraint
206221
{
207-
return self::CLASS_CONSTRAINT;
222+
public string $userDoesNotMatchMessage = 'User\'s e-mail address does not match that of the receipt';
223+
224+
public function getTargets(): string
225+
{
226+
return self::CLASS_CONSTRAINT;
227+
}
208228
}
209229

210-
With this, the validator's ``validate()`` method gets an object as its first argument::
230+
Now, the constraint validator will get an object as the first argument to
231+
``validate()``::
232+
233+
// src/Validator/ConfirmedPaymentReceiptValidator.php
234+
namespace App\Validator;
235+
236+
use Symfony\Component\Validator\Constraint;
237+
use Symfony\Component\Validator\ConstraintValidator;
238+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
211239

212-
class ProtocolClassValidator extends ConstraintValidator
240+
class ConfirmedPaymentReceiptValidator extends ConstraintValidator
213241
{
214-
public function validate($protocol, Constraint $constraint)
242+
/**
243+
* @param PaymentReceipt $receipt
244+
*/
245+
public function validate($receipt, Constraint $constraint): void
215246
{
216-
if ($protocol->getFoo() != $protocol->getBar()) {
217-
$this->context->buildViolation($constraint->message)
218-
->atPath('foo')
247+
if (!$receipt instanceof PaymentReceipt) {
248+
throw new UnexpectedValueException($receipt, PaymentReceipt::class);
249+
}
250+
251+
if (!$constraint instanceof ConfirmedPaymentReceipt) {
252+
throw new UnexpectedValueException($constraint, ConfirmedPaymentReceipt::class);
253+
}
254+
255+
$receiptEmail = $receipt->getPayload()['email'] ?? null;
256+
$userEmail = $receipt->getUser()->getEmail();
257+
258+
if ($userEmail !== $receiptEmail) {
259+
$this->context
260+
->buildViolation($constraint->userDoesNotMatchMessage)
261+
->atPath('user.email')
219262
->addViolation();
220263
}
221264
}
@@ -227,8 +270,7 @@ With this, the validator's ``validate()`` method gets an object as its first arg
227270
associated. Use any :doc:`valid PropertyAccess syntax </components/property_access>`
228271
to define that property.
229272

230-
A class constraint validator is applied to the class itself, and
231-
not to the property:
273+
A class constraint validator must be applied to the class itself:
232274

233275
.. configuration-block::
234276

@@ -248,44 +290,54 @@ not to the property:
248290
.. code-block:: yaml
249291
250292
# config/validator/validation.yaml
251-
App\Entity\AcmeEntity:
293+
App\Entity\PaymentReceipt:
252294
constraints:
253-
- App\Validator\ProtocolClass: ~
295+
- App\Validator\ConfirmedPaymentReceipt: ~
254296
255297
.. code-block:: xml
256298
257299
<!-- config/validator/validation.xml -->
258-
<class name="App\Entity\AcmeEntity">
259-
<constraint name="App\Validator\ProtocolClass"/>
260-
</class>
300+
<?xml version="1.0" encoding="UTF-8" ?>
301+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
302+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
303+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
304+
https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
305+
306+
<class name="App\Entity\PaymentReceipt">
307+
<constraint name="App\Validator\ConfirmedPaymentReceipt"/>
308+
</class>
309+
</constraint-mapping>
261310
262311
.. code-block:: php
263312
264-
// src/Entity/AcmeEntity.php
313+
// src/Entity/PaymentReceipt.php
265314
namespace App\Entity;
266315
267-
use App\Validator\ProtocolClass;
316+
use App\Validator\ConfirmedPaymentReceipt;
268317
use Symfony\Component\Validator\Mapping\ClassMetadata;
269318
270-
class AcmeEntity
319+
class PaymentReceipt
271320
{
272321
// ...
273322
274-
public static function loadValidatorMetadata(ClassMetadata $metadata)
323+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
275324
{
276-
$metadata->addConstraint(new ProtocolClass());
325+
$metadata->addConstraint(new ConfirmedPaymentReceipt());
277326
}
278327
}
279328
280329
Testing Custom Constraints
281330
--------------------------
282331

283-
Use the ``ConstraintValidatorTestCase`` utility to simplify the creation of
284-
unit tests for your custom constraints::
332+
Use the :class:`Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase``
333+
class to simplify writing unit tests for your custom constraints::
334+
335+
// tests/Validator/ContainsAlphanumericValidatorTest.php
336+
namespace App\Tests\Validator;
285337

286-
// ...
287338
use App\Validator\ContainsAlphanumeric;
288339
use App\Validator\ContainsAlphanumericValidator;
340+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
289341

290342
class ContainsAlphanumericValidatorTest extends ConstraintValidatorTestCase
291343
{

0 commit comments

Comments
 (0)