Skip to content

Commit afe07ab

Browse files
committed
Merge branch '4.4' into 5.4
* 4.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 576e20a + 6392428 commit afe07ab

File tree

5 files changed

+98
-52
lines changed

5 files changed

+98
-52
lines changed

console.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ the console::
280280
'',
281281
]);
282282

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

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

serializer.rst

+1-7
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,7 @@ configuration:
177177
Using Serialization Groups Annotations
178178
--------------------------------------
179179

180-
To use annotations, first add support for them via the SensioFrameworkExtraBundle:
181-
182-
.. code-block:: terminal
183-
184-
$ composer require sensio/framework-extra-bundle
185-
186-
Next, add the :ref:`@Groups annotations <component-serializer-attributes-groups-annotations>`
180+
You can add the :ref:`@Groups annotations <component-serializer-attributes-groups-annotations>`
187181
to your class::
188182

189183
// src/Entity/Product.php

validation/custom_constraint.rst

+94-42
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ First you need to create a Constraint class and extend :class:`Symfony\\Componen
2828
*/
2929
class ContainsAlphanumeric extends Constraint
3030
{
31-
public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.';
32-
public $mode = 'strict'; // If the constraint has configuration options, define them as public properties
31+
public string $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.';
32+
// If the constraint has configuration options, define them as public properties
33+
public string $mode = 'strict';
3334
}
3435
3536
.. code-block:: php-attributes
@@ -85,7 +86,7 @@ The validator class only has one required method ``validate()``::
8586

8687
class ContainsAlphanumericValidator extends ConstraintValidator
8788
{
88-
public function validate($value, Constraint $constraint)
89+
public function validate($value, Constraint $constraint): void
8990
{
9091
if (!$constraint instanceof ContainsAlphanumeric) {
9192
throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
@@ -119,7 +120,7 @@ The validator class only has one required method ``validate()``::
119120
}
120121
}
121122

122-
Inside ``validate``, you don't need to return a value. Instead, you add violations
123+
Inside ``validate()``, you don't need to return a value. Instead, you add violations
123124
to the validator's ``context`` property and a value will be considered valid
124125
if it causes no violations. The ``buildViolation()`` method takes the error
125126
message as its argument and returns an instance of
@@ -135,21 +136,21 @@ You can use custom validators like the ones provided by Symfony itself:
135136

136137
.. code-block:: php-annotations
137138
138-
// src/Entity/AcmeEntity.php
139+
// src/Entity/User.php
139140
namespace App\Entity;
140141
141142
use App\Validator as AcmeAssert;
142143
use Symfony\Component\Validator\Constraints as Assert;
143144
144-
class AcmeEntity
145+
class User
145146
{
146147
// ...
147148
148149
/**
149150
* @Assert\NotBlank
150151
* @AcmeAssert\ContainsAlphanumeric(mode="loose")
151152
*/
152-
protected $name;
153+
protected string $name = '';
153154
154155
// ...
155156
}
@@ -176,7 +177,7 @@ You can use custom validators like the ones provided by Symfony itself:
176177
.. code-block:: yaml
177178
178179
# config/validator/validation.yaml
179-
App\Entity\AcmeEntity:
180+
App\Entity\User:
180181
properties:
181182
name:
182183
- NotBlank: ~
@@ -191,7 +192,7 @@ You can use custom validators like the ones provided by Symfony itself:
191192
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
192193
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
193194
194-
<class name="App\Entity\AcmeEntity">
195+
<class name="App\Entity\User">
195196
<property name="name">
196197
<constraint name="NotBlank"/>
197198
<constraint name="App\Validator\ContainsAlphanumeric">
@@ -203,18 +204,20 @@ You can use custom validators like the ones provided by Symfony itself:
203204
204205
.. code-block:: php
205206
206-
// src/Entity/AcmeEntity.php
207+
// src/Entity/User.php
207208
namespace App\Entity;
208209
209210
use App\Validator\ContainsAlphanumeric;
210211
use Symfony\Component\Validator\Constraints\NotBlank;
211212
use Symfony\Component\Validator\Mapping\ClassMetadata;
212213
213-
class AcmeEntity
214+
class User
214215
{
215-
public $name;
216+
protected string $name = '';
217+
218+
// ...
216219
217-
public static function loadValidatorMetadata(ClassMetadata $metadata)
220+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
218221
{
219222
$metadata->addPropertyConstraint('name', new NotBlank());
220223
$metadata->addPropertyConstraint('name', new ContainsAlphanumeric(['mode' => 'loose']));
@@ -247,22 +250,62 @@ Class Constraint Validator
247250
~~~~~~~~~~~~~~~~~~~~~~~~~~
248251

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

252-
public function getTargets()
264+
/**
265+
* @Annotation
266+
*/
267+
class ConfirmedPaymentReceipt extends Constraint
253268
{
254-
return self::CLASS_CONSTRAINT;
269+
public string $userDoesNotMatchMessage = 'User\'s e-mail address does not match that of the receipt';
270+
271+
public function getTargets(): string
272+
{
273+
return self::CLASS_CONSTRAINT;
274+
}
255275
}
256276

257-
With this, the validator's ``validate()`` method gets an object as its first argument::
277+
Now, the constraint validator will get an object as the first argument to
278+
``validate()``::
279+
280+
// src/Validator/ConfirmedPaymentReceiptValidator.php
281+
namespace App\Validator;
282+
283+
use Symfony\Component\Validator\Constraint;
284+
use Symfony\Component\Validator\ConstraintValidator;
285+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
258286

259-
class ProtocolClassValidator extends ConstraintValidator
287+
class ConfirmedPaymentReceiptValidator extends ConstraintValidator
260288
{
261-
public function validate($protocol, Constraint $constraint)
289+
/**
290+
* @param PaymentReceipt $receipt
291+
*/
292+
public function validate($receipt, Constraint $constraint): void
262293
{
263-
if ($protocol->getFoo() != $protocol->getBar()) {
264-
$this->context->buildViolation($constraint->message)
265-
->atPath('foo')
294+
if (!$receipt instanceof PaymentReceipt) {
295+
throw new UnexpectedValueException($receipt, PaymentReceipt::class);
296+
}
297+
298+
if (!$constraint instanceof ConfirmedPaymentReceipt) {
299+
throw new UnexpectedValueException($constraint, ConfirmedPaymentReceipt::class);
300+
}
301+
302+
$receiptEmail = $receipt->getPayload()['email'] ?? null;
303+
$userEmail = $receipt->getUser()->getEmail();
304+
305+
if ($userEmail !== $receiptEmail) {
306+
$this->context
307+
->buildViolation($constraint->userDoesNotMatchMessage)
308+
->atPath('user.email')
266309
->addViolation();
267310
}
268311
}
@@ -274,22 +317,21 @@ With this, the validator's ``validate()`` method gets an object as its first arg
274317
associated. Use any :doc:`valid PropertyAccess syntax </components/property_access>`
275318
to define that property.
276319

277-
A class constraint validator is applied to the class itself, and
278-
not to the property:
320+
A class constraint validator must be applied to the class itself:
279321

280322
.. configuration-block::
281323

282324
.. code-block:: php-annotations
283325
284-
// src/Entity/AcmeEntity.php
326+
// src/Entity/PaymentReceipt.php
285327
namespace App\Entity;
286328
287-
use App\Validator as AcmeAssert;
288-
329+
use App\Validator\ConfirmedPaymentReceipt;
330+
289331
/**
290-
* @AcmeAssert\ProtocolClass
332+
* @ConfirmedPaymentReceipt
291333
*/
292-
class AcmeEntity
334+
class PaymentReceipt
293335
{
294336
// ...
295337
}
@@ -310,44 +352,54 @@ not to the property:
310352
.. code-block:: yaml
311353
312354
# config/validator/validation.yaml
313-
App\Entity\AcmeEntity:
355+
App\Entity\PaymentReceipt:
314356
constraints:
315-
- App\Validator\ProtocolClass: ~
357+
- App\Validator\ConfirmedPaymentReceipt: ~
316358
317359
.. code-block:: xml
318360
319361
<!-- config/validator/validation.xml -->
320-
<class name="App\Entity\AcmeEntity">
321-
<constraint name="App\Validator\ProtocolClass"/>
322-
</class>
362+
<?xml version="1.0" encoding="UTF-8" ?>
363+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
364+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
365+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
366+
https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
367+
368+
<class name="App\Entity\PaymentReceipt">
369+
<constraint name="App\Validator\ConfirmedPaymentReceipt"/>
370+
</class>
371+
</constraint-mapping>
323372
324373
.. code-block:: php
325374
326-
// src/Entity/AcmeEntity.php
375+
// src/Entity/PaymentReceipt.php
327376
namespace App\Entity;
328377
329-
use App\Validator\ProtocolClass;
378+
use App\Validator\ConfirmedPaymentReceipt;
330379
use Symfony\Component\Validator\Mapping\ClassMetadata;
331380
332-
class AcmeEntity
381+
class PaymentReceipt
333382
{
334383
// ...
335384
336-
public static function loadValidatorMetadata(ClassMetadata $metadata)
385+
public static function loadValidatorMetadata(ClassMetadata $metadata): void
337386
{
338-
$metadata->addConstraint(new ProtocolClass());
387+
$metadata->addConstraint(new ConfirmedPaymentReceipt());
339388
}
340389
}
341390
342391
Testing Custom Constraints
343392
--------------------------
344393

345-
Use the ``ConstraintValidatorTestCase`` utility to simplify the creation of
346-
unit tests for your custom constraints::
394+
Use the :class:`Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase``
395+
class to simplify writing unit tests for your custom constraints::
396+
397+
// tests/Validator/ContainsAlphanumericValidatorTest.php
398+
namespace App\Tests\Validator;
347399

348-
// ...
349400
use App\Validator\ContainsAlphanumeric;
350401
use App\Validator\ContainsAlphanumericValidator;
402+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
351403

352404
class ContainsAlphanumericValidatorTest extends ConstraintValidatorTestCase
353405
{

0 commit comments

Comments
 (0)