Skip to content

Commit 9762db6

Browse files
committed
Merge branch '6.1' into 6.2
* 6.1: 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 793c3cb + 7f8c5f8 commit 9762db6

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
@@ -264,7 +264,7 @@ the console::
264264
'',
265265
]);
266266

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

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
@@ -116,7 +117,7 @@ The validator class only has one required method ``validate()``::
116117

117118
class ContainsAlphanumericValidator extends ConstraintValidator
118119
{
119-
public function validate($value, Constraint $constraint)
120+
public function validate($value, Constraint $constraint): void
120121
{
121122
if (!$constraint instanceof ContainsAlphanumeric) {
122123
throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
@@ -150,7 +151,7 @@ The validator class only has one required method ``validate()``::
150151
}
151152
}
152153

153-
Inside ``validate``, you don't need to return a value. Instead, you add violations
154+
Inside ``validate()``, you don't need to return a value. Instead, you add violations
154155
to the validator's ``context`` property and a value will be considered valid
155156
if it causes no violations. The ``buildViolation()`` method takes the error
156157
message as its argument and returns an instance of
@@ -178,15 +179,15 @@ You can use custom validators like the ones provided by Symfony itself:
178179
179180
#[Assert\NotBlank]
180181
#[AcmeAssert\ContainsAlphanumeric(mode: 'loose')]
181-
protected $name;
182+
protected string $name;
182183
183184
// ...
184185
}
185186
186187
.. code-block:: yaml
187188
188189
# config/validator/validation.yaml
189-
App\Entity\AcmeEntity:
190+
App\Entity\User:
190191
properties:
191192
name:
192193
- NotBlank: ~
@@ -201,7 +202,7 @@ You can use custom validators like the ones provided by Symfony itself:
201202
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
202203
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
203204
204-
<class name="App\Entity\AcmeEntity">
205+
<class name="App\Entity\User">
205206
<property name="name">
206207
<constraint name="NotBlank"/>
207208
<constraint name="App\Validator\ContainsAlphanumeric">
@@ -213,18 +214,20 @@ You can use custom validators like the ones provided by Symfony itself:
213214
214215
.. code-block:: php
215216
216-
// src/Entity/AcmeEntity.php
217+
// src/Entity/User.php
217218
namespace App\Entity;
218219
219220
use App\Validator\ContainsAlphanumeric;
220221
use Symfony\Component\Validator\Constraints\NotBlank;
221222
use Symfony\Component\Validator\Mapping\ClassMetadata;
222223
223-
class AcmeEntity
224+
class User
224225
{
225-
public $name;
226+
protected string $name = '';
227+
228+
// ...
226229
227-
public static function loadValidatorMetadata(ClassMetadata $metadata)
230+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
228231
{
229232
$metadata->addPropertyConstraint('name', new NotBlank());
230233
$metadata->addPropertyConstraint('name', new ContainsAlphanumeric(['mode' => 'loose']));
@@ -253,22 +256,62 @@ Class Constraint Validator
253256
~~~~~~~~~~~~~~~~~~~~~~~~~~
254257

255258
Besides validating a single property, a constraint can have an entire class
256-
as its scope. You only need to add this to the ``Constraint`` class::
259+
as its scope.
260+
261+
For instance, imagine you also have a ``PaymentReceipt`` entity and you
262+
need to make sure the email of the receipt payload matches the user's
263+
email. First, create a constraint and override the ``getTargets()`` method::
264+
265+
// src/Validator/ConfirmedPaymentReceipt.php
266+
namespace App\Validator;
267+
268+
use Symfony\Component\Validator\Constraint;
257269

258-
public function getTargets()
270+
/**
271+
* @Annotation
272+
*/
273+
class ConfirmedPaymentReceipt extends Constraint
259274
{
260-
return self::CLASS_CONSTRAINT;
275+
public string $userDoesNotMatchMessage = 'User\'s e-mail address does not match that of the receipt';
276+
277+
public function getTargets(): string
278+
{
279+
return self::CLASS_CONSTRAINT;
280+
}
261281
}
262282

263-
With this, the validator's ``validate()`` method gets an object as its first argument::
283+
Now, the constraint validator will get an object as the first argument to
284+
``validate()``::
285+
286+
// src/Validator/ConfirmedPaymentReceiptValidator.php
287+
namespace App\Validator;
288+
289+
use Symfony\Component\Validator\Constraint;
290+
use Symfony\Component\Validator\ConstraintValidator;
291+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
264292

265-
class ProtocolClassValidator extends ConstraintValidator
293+
class ConfirmedPaymentReceiptValidator extends ConstraintValidator
266294
{
267-
public function validate($protocol, Constraint $constraint)
295+
/**
296+
* @param PaymentReceipt $receipt
297+
*/
298+
public function validate($receipt, Constraint $constraint): void
268299
{
269-
if ($protocol->getFoo() != $protocol->getBar()) {
270-
$this->context->buildViolation($constraint->message)
271-
->atPath('foo')
300+
if (!$receipt instanceof PaymentReceipt) {
301+
throw new UnexpectedValueException($receipt, PaymentReceipt::class);
302+
}
303+
304+
if (!$constraint instanceof ConfirmedPaymentReceipt) {
305+
throw new UnexpectedValueException($constraint, ConfirmedPaymentReceipt::class);
306+
}
307+
308+
$receiptEmail = $receipt->getPayload()['email'] ?? null;
309+
$userEmail = $receipt->getUser()->getEmail();
310+
311+
if ($userEmail !== $receiptEmail) {
312+
$this->context
313+
->buildViolation($constraint->userDoesNotMatchMessage)
314+
->atPath('user.email')
272315
->addViolation();
273316
}
274317
}
@@ -280,8 +323,7 @@ With this, the validator's ``validate()`` method gets an object as its first arg
280323
associated. Use any :doc:`valid PropertyAccess syntax </components/property_access>`
281324
to define that property.
282325

283-
A class constraint validator is applied to the class itself, and
284-
not to the property:
326+
A class constraint validator must be applied to the class itself:
285327

286328
.. configuration-block::
287329

@@ -301,44 +343,54 @@ not to the property:
301343
.. code-block:: yaml
302344
303345
# config/validator/validation.yaml
304-
App\Entity\AcmeEntity:
346+
App\Entity\PaymentReceipt:
305347
constraints:
306-
- App\Validator\ProtocolClass: ~
348+
- App\Validator\ConfirmedPaymentReceipt: ~
307349
308350
.. code-block:: xml
309351
310352
<!-- config/validator/validation.xml -->
311-
<class name="App\Entity\AcmeEntity">
312-
<constraint name="App\Validator\ProtocolClass"/>
313-
</class>
353+
<?xml version="1.0" encoding="UTF-8" ?>
354+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
355+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
356+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
357+
https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
358+
359+
<class name="App\Entity\PaymentReceipt">
360+
<constraint name="App\Validator\ConfirmedPaymentReceipt"/>
361+
</class>
362+
</constraint-mapping>
314363
315364
.. code-block:: php
316365
317-
// src/Entity/AcmeEntity.php
366+
// src/Entity/PaymentReceipt.php
318367
namespace App\Entity;
319368
320-
use App\Validator\ProtocolClass;
369+
use App\Validator\ConfirmedPaymentReceipt;
321370
use Symfony\Component\Validator\Mapping\ClassMetadata;
322371
323-
class AcmeEntity
372+
class PaymentReceipt
324373
{
325374
// ...
326375
327-
public static function loadValidatorMetadata(ClassMetadata $metadata)
376+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
328377
{
329-
$metadata->addConstraint(new ProtocolClass());
378+
$metadata->addConstraint(new ConfirmedPaymentReceipt());
330379
}
331380
}
332381
333382
Testing Custom Constraints
334383
--------------------------
335384

336-
Use the ``ConstraintValidatorTestCase`` utility to simplify the creation of
337-
unit tests for your custom constraints::
385+
Use the :class:`Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase``
386+
class to simplify writing unit tests for your custom constraints::
387+
388+
// tests/Validator/ContainsAlphanumericValidatorTest.php
389+
namespace App\Tests\Validator;
338390

339-
// ...
340391
use App\Validator\ContainsAlphanumeric;
341392
use App\Validator\ContainsAlphanumericValidator;
393+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
342394

343395
class ContainsAlphanumericValidatorTest extends ConstraintValidatorTestCase
344396
{

0 commit comments

Comments
 (0)