Skip to content

Commit e613729

Browse files
authored
Merge pull request #313 from moufmouf/attributes
Adding support for PHP 8 attributes
2 parents 06dc826 + cd9e487 commit e613729

File tree

128 files changed

+2117
-146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+2117
-146
lines changed

.github/workflows/continuous_integration.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
- "7.2"
2020
- "7.3"
2121
- "7.4"
22+
- "8.0"
2223

2324
dependencies:
2425
- "highest"
@@ -32,6 +33,7 @@ jobs:
3233
with:
3334
coverage: "pcov"
3435
php-version: "${{ matrix.php-version }}"
36+
tools: composer:v2
3537

3638
- name: "Cache dependencies installed with composer"
3739
uses: "actions/cache@v1"
@@ -42,16 +44,23 @@ jobs:
4244

4345
- name: "Install dependencies with composer"
4446
run: "composer install --no-interaction"
47+
if: ${{ matrix.php-version != '8.0' }}
48+
49+
- name: "Install dependencies with composer. Ignoring platform reqs to bypass a problem with ecodev/graphql-upload available only with latest Webonyx on PHP8."
50+
run: "composer install --no-interaction --ignore-platform-reqs"
51+
if: ${{ matrix.php-version == '8.0' }}
4552

4653
- name: "Run tests with phpunit/phpunit"
4754
run: "vendor/bin/phpunit"
4855

4956
- name: "Run static code analysis with phpstan/phpstan"
5057
run: "composer phpstan"
51-
58+
if: ${{ matrix.php-version == '8.0' }}
59+
5260
- name: "Run coding standard checks with squizlabs/php_codesniffer"
5361
run: "composer cs-check"
54-
62+
if: ${{ matrix.php-version == '8.0' }}
63+
5564
- name: "Archive code coverage results"
5665
uses: "actions/upload-artifact@v1"
5766
with:

composer.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
"phpdocumentor/reflection-docblock": "^4.3 || ^5.0",
2121
"phpdocumentor/type-resolver": "^1.0.1",
2222
"psr/http-message": "^1",
23-
"ecodev/graphql-upload": "^4.0",
2423
"webmozart/assert": "^1.4",
2524
"symfony/cache": "^4.3 | ^5",
2625
"thecodingmachine/cache-utils": "^1",
@@ -32,20 +31,22 @@
3231
"psr/http-factory": "^1"
3332
},
3433
"require-dev": {
35-
"phpunit/phpunit": "^8.2.4",
34+
"phpunit/phpunit": "^8.2.4||^9.4",
3635
"php-coveralls/php-coveralls": "^2.1",
3736
"mouf/picotainer": "^1.1",
3837
"phpstan/phpstan": "^0.12.25",
3938
"beberlei/porpaginas": "^1.2",
4039
"myclabs/php-enum": "^1.6.6",
41-
"doctrine/coding-standard": "^7.0",
40+
"doctrine/coding-standard": "^8.2",
4241
"phpstan/phpstan-webmozart-assert": "^0.12",
4342
"phpstan/extension-installer": "^1.0",
4443
"thecodingmachine/phpstan-strict-rules": "^0.12",
45-
"laminas/laminas-diactoros": "^2"
44+
"laminas/laminas-diactoros": "^2",
45+
"ecodev/graphql-upload": "^4.0 || ^5.0 || ^6.0"
4646
},
4747
"suggest": {
48-
"beberlei/porpaginas": "If you want automatic pagination in your GraphQL types"
48+
"beberlei/porpaginas": "If you want automatic pagination in your GraphQL types",
49+
"ecodev/graphql-upload": "If you want to support file upload inside GraphQL input types"
4950
},
5051
"autoload": {
5152
"psr-4": {

docs/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ title: Changelog
44
sidebar_label: Changelog
55
---
66

7+
## 4.1
8+
9+
Breaking change:
10+
11+
There is one breaking change introduced in the minor version (this was important to allow PHP 8 compatibility).
12+
13+
- The **ecodev/graphql-upload** package (used to get support for file uploads in GraphQL input types) is now a "recommended" dependency only.
14+
If you are using GraphQL file uploads, you need to add this package to your `composer.json`.
15+
16+
New features:
17+
18+
- All annotations can now be accessed as PHP 8 attributes
19+
20+
721
## 4.0
822

923
This is a complete refactoring from 3.x. While existing annotations are kept compatible, the internals have completely

docs/annotations_reference.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ title: Annotations reference
44
sidebar_label: Annotations reference
55
---
66

7+
Note: all annotations are available both in a Doctrine annotation format (`@Query`) and in PHP 8 attribute format (`#[Query]`).
8+
See [Doctrine annotations vs PHP 8 attributes](doctrine_annotations_attributes.md) for more details.
9+
710
## @Query annotation
811

912
The `@Query` annotation is used to declare a GraphQL query.
@@ -74,7 +77,7 @@ Attribute | Compulsory | Type | Definition
7477
name | *yes* | string | The name of the field.
7578
[outputType](custom_types.md) | *no* | string | Forces the GraphQL output type of the field. Otherwise, return type is used.
7679
phpType | *no* | string | The PHP type of the field (as you would write it in a Docblock)
77-
annotations | *no* | array<Annotations> | A set of annotations that apply to this field. You would typically used a "@Logged" or "@Right" annotation here.
80+
annotations | *no* | array<Annotations> | A set of annotations that apply to this field. You would typically used a "@Logged" or "@Right" annotation here. Available in Doctrine annotations only (not available in the #SourceField PHP 8 attribute)
7881

7982
**Note**: `outputType` and `phpType` are mutually exclusive.
8083

@@ -89,7 +92,7 @@ Attribute | Compulsory | Type | Definition
8992
name | *yes* | string | The name of the field.
9093
[outputType](custom_types.md) | *no*(*) | string | The GraphQL output type of the field.
9194
phpType | *no*(*) | string | The PHP type of the field (as you would write it in a Docblock)
92-
annotations | *no* | array<Annotations> | A set of annotations that apply to this field. You would typically used a "@Logged" or "@Right" annotation here.
95+
annotations | *no* | array<Annotations> | A set of annotations that apply to this field. You would typically used a "@Logged" or "@Right" annotation here. Available in Doctrine annotations only (not available in the #MagicField PHP 8 attribute)
9396

9497
(*) **Note**: `outputType` and `phpType` are mutually exclusive. You MUST provide one of them.
9598

@@ -120,7 +123,7 @@ query / mutation / field (according to the `@Logged` and `@Right` annotations).
120123

121124
Attribute | Compulsory | Type | Definition
122125
---------------|------------|------|--------
123-
*default* | *yes* | mixed | The value to return if the user is not authorized.
126+
value | *yes* | mixed | The value to return if the user is not authorized.
124127

125128
## @HideIfUnauthorized annotation
126129

docs/argument_resolving.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ As an example, GraphQLite uses *parameter middlewares* internally to:
1515
- Inject the Webonyx GraphQL resolution object when you type-hint on the `ResolveInfo` object. For instance:
1616
```php
1717
/**
18-
* @Query
1918
* @return Product[]
2019
*/
20+
#[Query]
2121
public function products(ResolveInfo $info): array
2222
```
2323
In the query above, the `$info` argument is filled with the Webonyx `ResolveInfo` class thanks to the
@@ -58,14 +58,19 @@ If you plan to use annotations while resolving arguments, your annotation should
5858

5959
For instance, if we want GraphQLite to inject a service in an argument, we can use `@Autowire(for="myService")`.
6060

61+
For PHP 8 attributes, we only need to put declare the annotation can target parameters: `#[Attribute(Attribute::TARGET_PARAMETER)]`.
62+
6163
The annotation looks like this:
6264

6365
```php
66+
use Attribute;
67+
6468
/**
6569
* Use this annotation to autowire a service from the container into a given parameter of a field/query/mutation.
6670
*
6771
* @Annotation
6872
*/
73+
#[Attribute(Attribute::TARGET_PARAMETER)]
6974
class Autowire implements ParameterAnnotationInterface
7075
{
7176
/**

docs/authentication_authorization.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,30 @@ See <a href="implementing-security.md">Connecting GraphQLite to your framework's
2222
## `@Logged` and `@Right` annotations
2323

2424
GraphQLite exposes two annotations (`@Logged` and `@Right`) that you can use to restrict access to a resource.
25+
<!--DOCUSAURUS_CODE_TABS-->
26+
<!--PHP 8+-->
27+
```php
28+
namespace App\Controller;
2529

30+
use TheCodingMachine\GraphQLite\Annotations\Query;
31+
use TheCodingMachine\GraphQLite\Annotations\Logged;
32+
use TheCodingMachine\GraphQLite\Annotations\Right;
33+
34+
class UserController
35+
{
36+
/**
37+
* @return User[]
38+
*/
39+
#[Query]
40+
#[Logged]
41+
#[Right("CAN_VIEW_USER_LIST")]
42+
public function users(int $limit, int $offset): array
43+
{
44+
// ...
45+
}
46+
}
47+
```
48+
<!--PHP 7+-->
2649
```php
2750
namespace App\Controller;
2851

@@ -44,6 +67,8 @@ class UserController
4467
}
4568
}
4669
```
70+
<!--END_DOCUSAURUS_CODE_TABS-->
71+
4772

4873
In the example above, the query `users` will only be available if the user making the query is logged AND if he
4974
has the `CAN_VIEW_USER_LIST` right.
@@ -62,6 +87,28 @@ If you do not want an error to be thrown when a user attempts to query a field/q
6287

6388
The `@FailWith` annotation contains the value that will be returned for users with insufficient rights.
6489

90+
<!--DOCUSAURUS_CODE_TABS-->
91+
<!--PHP 8+-->
92+
```php
93+
class UserController
94+
{
95+
/**
96+
* If a user is not logged or if the user has not the right "CAN_VIEW_USER_LIST",
97+
* the value returned will be "null".
98+
*
99+
* @return User[]
100+
*/
101+
#[Query]
102+
#[Logged]
103+
#[Right("CAN_VIEW_USER_LIST")]
104+
#[FailWith(value: null)]
105+
public function users(int $limit, int $offset): array
106+
{
107+
// ...
108+
}
109+
}
110+
```
111+
<!--PHP 7+-->
65112
```php
66113
class UserController
67114
{
@@ -81,11 +128,37 @@ class UserController
81128
}
82129
}
83130
```
131+
<!--END_DOCUSAURUS_CODE_TABS-->
84132

85133
## Injecting the current user as a parameter
86134

87135
Use the `@InjectUser` annotation to get an instance of the current user logged in.
88136

137+
<!--DOCUSAURUS_CODE_TABS-->
138+
<!--PHP 8+-->
139+
```php
140+
namespace App\Controller;
141+
142+
use TheCodingMachine\GraphQLite\Annotations\Query;
143+
use TheCodingMachine\GraphQLite\Annotations\InjectUser;
144+
145+
class ProductController
146+
{
147+
/**
148+
* @Query
149+
* @return Product
150+
*/
151+
public function product(
152+
int $id,
153+
#[InjectUser]
154+
User $user
155+
): Product
156+
{
157+
// ...
158+
}
159+
}
160+
```
161+
<!--PHP 7+-->
89162
```php
90163
namespace App\Controller;
91164

@@ -105,6 +178,7 @@ class ProductController
105178
}
106179
}
107180
```
181+
<!--END_DOCUSAURUS_CODE_TABS-->
108182

109183
The `@InjectUser` annotation can be used next to:
110184

@@ -123,6 +197,29 @@ Some will be available to him and some won't.
123197
If you want to add an extra level of security (or if you want your schema to be kept secret to unauthorized users),
124198
you can use the `@HideIfUnauthorized` annotation.
125199

200+
<!--DOCUSAURUS_CODE_TABS-->
201+
<!--PHP 8+-->
202+
```php
203+
class UserController
204+
{
205+
/**
206+
* If a user is not logged or if the user has not the right "CAN_VIEW_USER_LIST",
207+
* the schema will NOT contain the "users" query at all (so trying to call the
208+
* "users" query will result in a GraphQL "query not found" error.
209+
*
210+
* @return User[]
211+
*/
212+
#[Query]
213+
#[Logged]
214+
#[Right("CAN_VIEW_USER_LIST")]
215+
#[HideIfUnauthorized]
216+
public function users(int $limit, int $offset): array
217+
{
218+
// ...
219+
}
220+
}
221+
```
222+
<!--PHP 7+-->
126223
```php
127224
class UserController
128225
{
@@ -143,6 +240,7 @@ class UserController
143240
}
144241
}
145242
```
243+
<!--END_DOCUSAURUS_CODE_TABS-->
146244

147245
While this is the most secured mode, it can have drawbacks when working with development tools
148246
(you need to be logged as admin to fetch the complete schema).

0 commit comments

Comments
 (0)