Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a016c49

Browse files
authoredJul 11, 2021
refactor: drop annotation support and prepare for Symfony 6 (#7)
1 parent c419a39 commit a016c49

File tree

11 files changed

+257
-53
lines changed

11 files changed

+257
-53
lines changed
 
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: phpunit-symfony6
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ${{ matrix.os }}
8+
strategy:
9+
fail-fast: true
10+
matrix:
11+
os:
12+
- ubuntu-latest
13+
php:
14+
- 8.0
15+
16+
name: php${{ matrix.php }} - symfony 6
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v2
21+
22+
- name: Setup PHP
23+
uses: shivammathur/setup-php@v2
24+
with:
25+
php-version: ${{ matrix.php }}
26+
coverage: xdebug
27+
28+
- name: Setup Problem Matches
29+
run: |
30+
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
31+
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
32+
33+
- name: Install dependencies
34+
run: composer require symfony/validator:6.0.x-dev && composer update
35+
36+
- name: Execute tests
37+
run: vendor/bin/phpunit -v

‎.github/workflows/phpunit.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ jobs:
1111
os:
1212
- ubuntu-latest
1313
php:
14-
- 7.4
1514
- 8.0
1615
dependency-version: [prefer-lowest, prefer-stable]
1716

18-
name: P${{ matrix.php }} - ${{ matrix.dependency-version }}
17+
name: php${{ matrix.php }} - ${{ matrix.dependency-version }}
1918

2019
steps:
2120
- name: Checkout code

‎CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## v2.0.0 - 2021-07-XX
4+
5+
- drop php 7.4 support
6+
- drop primary `doctrine/annotations` support for model validation
7+
- require `dogado/json-api-common:^2.0`
8+
- prepare support for `symfony/validator:^6.0`
9+
10+
See [UPGRADE-2.0.md](UPGRADE-2.0.md) for more details.
11+
312
## v1.0.0 - 2021-05-21
413

514
- initial release

‎UPGRADE-2.0.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# UPGRADE to v2.0.0
2+
3+
## Migrating JSON API model definitions from Doctrine annotations to php 8 attributes
4+
5+
In `v2.0.0` the support for JSON API model definitions via Doctrine annotations has been removed and moved to native
6+
php 8 attributes. The annotation classes have been moved from the namespace `Dogado\JsonApi\Annotations` to
7+
`Dogado\JsonApi\Attribute`. The attributes are basically the same. The only change is that the `value` property
8+
in the `Type` and `Attribute` classes has been renamed to `name`.
9+
10+
Your models have to be changed like this:
11+
```php
12+
// OLD
13+
use Dogado\JsonApi\Annotations\Attribute;
14+
use Dogado\JsonApi\Annotations\Id;
15+
use Dogado\JsonApi\Annotations\Type;
16+
17+
/**
18+
* @Type("dummy-model")
19+
*/
20+
class Model
21+
{
22+
/**
23+
* @Id()
24+
*/
25+
private ?int $id = 123456;
26+
27+
/**
28+
* @Attribute(value="name-alias", ignoreOnNull=true)
29+
*/
30+
private ?string $name = 'loremIpsum';
31+
}
32+
```
33+
```php
34+
// NEW
35+
use Dogado\JsonApi\Attribute\Attribute;
36+
use Dogado\JsonApi\Attribute\Id;
37+
use Dogado\JsonApi\Attribute\Type;
38+
39+
#[Type('dummy-model')]
40+
class Model
41+
{
42+
#[Id]
43+
private ?int $id = 123456;
44+
45+
#[Attribute(name: 'name-alias', ignoreOnNull: true)]
46+
private ?string $name = 'loremIpsum';
47+
}
48+
```
49+
50+
## Migrate to attribute constraint based Symfony model validation
51+
52+
Symfony added php 8 attribute constraint based validation in
53+
[`symfony/validator:v5.2.0`](https://symfony.com/blog/new-in-symfony-5-2-constraints-as-php-attributes). It works just
54+
like with Doctrine annotations, with one exception: The following validation constraints are not totally compatible to
55+
php 8 attributes:
56+
57+
* All
58+
* AtLeastOneOf
59+
* Collection
60+
* Compound (abstract)
61+
* Existence (abstract)
62+
** Required
63+
** Optional
64+
* Sequentially
65+
66+
[They are missing nested attributes](https://github.com/symfony/symfony/issues/38503) which is a feature that will
67+
probably be added in php 8.1.
68+
69+
Although this package suggests using php 8 attribute constraints with release `v2.0.0`, feel free to continue to
70+
use doctrine based annotations for validation. Symfony will continue to support them in Symfony 6.
71+
72+
Either way, you should pay attention to the way how you initialize the Symfony Validator.
73+
74+
### Validator initialization for php 8 attributes
75+
76+
```php
77+
use Symfony\Component\Validator\ValidatorBuilder;
78+
79+
$validatorBuilder = new ValidatorBuilder();
80+
81+
// Symfony ^5.2
82+
$validator = $validatorBuilder->enableAnnotationMapping(true)->getValidator();
83+
84+
// Symfony ^6.0
85+
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();
86+
```
87+
88+
php 8 validation constraints in combination with the new json api attribute definitions are a real benefit. Not only
89+
is it faster, since php 8 attributes are a native php implementation, but you also do no longer need extra Doctrine
90+
packages that analyze phpdocs. Here is an example how good both go together:
91+
92+
```php
93+
use Dogado\JsonApi\Attribute\Attribute;
94+
use Dogado\JsonApi\Attribute\Id;
95+
use Dogado\JsonApi\Attribute\Type;
96+
use Symfony\Component\Validator\Constraints as Assert;
97+
98+
#[Type('user')]
99+
class User
100+
{
101+
#[
102+
Id,
103+
Assert\Positive
104+
]
105+
private ?int $id = 123456;
106+
107+
#[
108+
Attribute,
109+
Assert\NotBlank,
110+
Assert\Length(min: 3, max: 32)
111+
]
112+
private ?string $name = 'John Doe';
113+
114+
#[
115+
Attribute,
116+
Assert\NotBlank,
117+
Assert\Email
118+
]
119+
private ?string $email = null;
120+
}
121+
```
122+
123+
### Validator initialization for Doctrine annotations
124+
125+
The following change is not really necessary for `symfony/validator:^5.0`, but that change is the syntax that will still
126+
be working in `symfony/validator:^6.0` and is already supported in `^5.2`.
127+
128+
```php
129+
use Symfony\Component\Validator\ValidatorBuilder;
130+
131+
$validatorBuilder = new ValidatorBuilder();
132+
133+
// OLD
134+
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();
135+
136+
// NEW
137+
$validator = $validatorBuilder->enableAnnotationMapping()->addDefaultDoctrineAnnotationReader()->getValidator();
138+
```

‎composer.json

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@
99
"license": "MIT",
1010
"homepage": "https://github.com/dogado-group/json-api-server",
1111
"require": {
12-
"php": "^7.4 || ^8.0",
12+
"php": "^8.0",
1313
"ext-json": "*",
14-
"dogado/json-api-common": "^1.0",
15-
"symfony/validator": "^5.1",
16-
"doctrine/annotations": "^1.11",
17-
"doctrine/cache": "^1.10"
14+
"dogado/json-api-common": "^2.0",
15+
"symfony/validator": "^5.2"
1816
},
1917
"require-dev": {
2018
"phpunit/phpunit": "^9.5",
2119
"fakerphp/faker": "^1.15",
22-
"phpstan/phpstan": "^0.12.49",
20+
"phpstan/phpstan": "^0.12.92",
2321
"guzzlehttp/psr7": "^1.7",
24-
"squizlabs/php_codesniffer": "^3.5"
22+
"squizlabs/php_codesniffer": "^3.6"
2523
},
2624
"autoload": {
2725
"psr-4": {

‎docs/05-validator-for-data-models.md

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,31 @@
33
# Validator for data models
44

55
The `dogado/json-api-common` package allows the conversion from resource instances to data models. It's usually the case, that we need some sort of validation on the JSON API data that is coming in.
6-
The `Dogado\JsonApi\Server\Validator\Validator` class offers the possibility to validate any model in it the current state, based on `symfony/validator`.
6+
The `Dogado\JsonApi\Server\Validator\ModelValidator` class offers the possibility to validate any model in it the current state, based on `symfony/validator`.
77

8-
Usually, you can use any validation you like. Although this validator will throw a custom JSON API compatible `\Dogado\JsonApi\Exception\JsonApi\ValidationException` containing error objects representing the Symfony Validator violations.
8+
Usually, you can use any validation you like. Although this validator will throw a custom JSON API compatible `Dogado\JsonApi\Exception\JsonApi\ValidationException` containing error objects representing the Symfony Validator violations.
99

1010
## Code example
1111

1212
### Model class definition
1313
```php
14-
use Dogado\JsonApi\Annotations\Attribute;
15-
use Dogado\JsonApi\Annotations\Type;
14+
use Dogado\JsonApi\Attribute\Attribute;
15+
use Dogado\JsonApi\Attribute\Type;
1616
use Symfony\Component\Validator\Constraints as Assert;
1717

18-
/**
19-
* @Type("validation-test")
20-
*/
18+
#[Type('validation-test')]
2119
class Model
2220
{
23-
/**
24-
* @Attribute()
25-
* @Assert\Email()
26-
*/
21+
#[
22+
Attribute,
23+
Assert\Email
24+
]
2725
private string $email = 'noValidEmail';
2826

29-
/**
30-
* @Attribute("jsonApiValueObject")
31-
* @Assert\Valid()
32-
*/
27+
#[
28+
Attribute('jsonApiValueObject'),
29+
Assert\Valid
30+
]
3331
private ValueObjectModel $valueObject;
3432

3533
public function __construct()
@@ -39,7 +37,7 @@ class Model
3937
}
4038
```
4139

42-
It is also possible to validate value objects. To do that, you need to add the `@Assert\Valid()` annotation to the object property. Within the value object, you can continue to use the regular assertions.
40+
It is also possible to validate value objects. To do that, you need to add the `Assert\Valid` attribute to the object property. Within the value object, you can continue to use the regular assertions.
4341

4442
### Execute validation
4543

@@ -51,7 +49,7 @@ use Symfony\Component\Validator\ValidatorBuilder;
5149

5250
$model = new Model();
5351
$validatorBuilder = new ValidatorBuilder();
54-
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();
52+
$validator = $validatorBuilder->enableAnnotationMapping(true)->getValidator();
5553

5654
$jsonApiValidator = new ModelValidator($validator);
5755
/** @throws JsonApiException */
@@ -60,6 +58,23 @@ $jsonApiValidator->validate($model);
6058

6159
In the above example we are using the annotation mapping that Symfony Validator offers by default. Feel free to use a different way of defining your validation rules. More details and validation examples can be found in the [Symfony documentation](https://symfony.com/doc/current/validation.html).
6260

61+
## php 8 validation limitations and Doctrine annotation support
62+
63+
Symfony added the php 8 attribute support for the assertion constraints in
64+
[`symfony/validator:5.2.0`](https://symfony.com/blog/new-in-symfony-5-2-constraints-as-php-attributes), but the
65+
alternative Doctrine annotation support is still given, even in Symfony 6. You can activate it like this:
66+
67+
```php
68+
$validatorBuilder = new ValidatorBuilder();
69+
$validator = $validatorBuilder->enableAnnotationMapping(true)->addDefaultDoctrineAnnotationReader()->getValidator();
70+
```
71+
72+
The benefit of using the php 8 attributes instead is that you don't have to require doctrine packages as dependencies.
73+
Attributes are a php 8 natively implemented feature and therefore faster to use. However, there
74+
are a few Symfony Constraints
75+
[that are not compatible to attributes yet](https://github.com/symfony/symfony/issues/38503), but that will probably
76+
change with php 8.1.
77+
6378
## Custom violation converter
6479

6580
The Symfony validator creates violations for each failing assertion rule. The JSON API server validator will send all violations against a `Dogado\JsonApi\Server\Validator\ViolationConverterInterface`. There already is a default `ViolationConverter` which will be used, but feel free to create a custom one and pass that one as parameter to the Validator instantiation.

‎src/JsonApiServer.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public function addHandler(string $type, RequestHandlerInterface $handler): self
5151
}
5252

5353
/**
54-
* @return RequestHandlerInterface
5554
* @throws UnsupportedTypeException
5655
*/
5756
private function getHandler(string $type): RequestHandlerInterface

‎src/Validator/ModelValidator.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,28 @@
1616

1717
class ModelValidator
1818
{
19-
protected ValidatorInterface $validator;
2019
protected ViolationConverterInterface $violationConverter;
2120

2221
public function __construct(
23-
ValidatorInterface $validator,
22+
protected ValidatorInterface $validator,
2423
ViolationConverterInterface $violationConverter = null
2524
) {
26-
$this->validator = $validator;
2725
$this->violationConverter = $violationConverter ?? new ViolationConverter();
2826
}
2927

3028
/**
3129
* @param Constraint|Constraint[]|null $constraints The constraint(s) to validate against
32-
* @param string|GroupSequence|(string|GroupSequence)[]|null $groups
30+
* @param string|GroupSequence|string[]|GroupSequence[]|null $groups
3331
* @param string|null $documentPath The path to the resource within the JSON API document
3432
* @throws ValidationException
3533
* @throws ReflectionException
3634
*/
37-
public function validate(object $model, $constraints = null, $groups = null, string $documentPath = null): void
38-
{
35+
public function validate(
36+
object $model,
37+
mixed $constraints = null,
38+
mixed $groups = null,
39+
string $documentPath = null
40+
): void {
3941
$documentPath ??= '/data';
4042
/** @var ConstraintViolationListInterface|ConstraintViolationInterface[] $violationList */
4143
$violationList = $this->validator->validate($model, $constraints, $groups);

‎tests/Stubs/Validator/Model.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@
33

44
namespace Dogado\JsonApi\Server\Tests\Stubs\Validator;
55

6-
use Dogado\JsonApi\Annotations\Attribute;
7-
use Dogado\JsonApi\Annotations\Type;
6+
use Dogado\JsonApi\Attribute\Attribute;
7+
use Dogado\JsonApi\Attribute\Type;
88
use Symfony\Component\Validator\Constraints as Assert;
99

10-
/**
11-
* @Type("validation-test")
12-
*/
10+
#[Type('validation-test')]
1311
class Model
1412
{
15-
/**
16-
* @Attribute("jsonApiValueObject")
17-
* @Assert\Valid()
18-
*/
13+
#[
14+
Attribute('jsonApiValueObject'),
15+
Assert\Valid
16+
]
1917
private ValueObjectModel $valueObject;
2018

2119
public function __construct()
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.