diff --git a/README.md b/README.md
index d4c892d..07a0d40 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ services.
* [Reference](#reference)
- [XML](#xml)
- [YAML](#yaml)
- - [Annotations](#annotations)
+ - [Annotations/Attributes](#annotations)
- [@Relation](#relation)
- [@Route](#route)
- [@Embedded](#embedded)
@@ -145,15 +145,19 @@ Resources](#embedding-resources) section.
A link is a relation which is identified by a `name` (e.g. `self`) and that
has an `href` parameter:
+
+
+Annotation (PHP < 8.1)
+
```php
use JMS\Serializer\Annotation as Serializer;
use Hateoas\Configuration\Annotation as Hateoas;
/**
- * @Serializer\XmlRoot("user")
- *
- * @Hateoas\Relation("self", href = "expr('/api/users/' ~ object.getId())")
- */
+* @Serializer\XmlRoot("user")
+*
+* @Hateoas\Relation("self", href = "expr('/api/users/' ~ object.getId())")
+*/
class User
{
/** @Serializer\XmlAttribute */
@@ -165,12 +169,38 @@ class User
}
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use JMS\Serializer\Annotation as Serializer;
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Serializer\XmlRoot('user')]
+#[Hateoas\Relation('self', href: "expr('/api/users/' ~ object.getId())")]
+class User
+{
+ #[Serializer\XmlAttribute]
+ private $id;
+ private $firstName;
+ private $lastName;
+
+ public function getId() {}
+}
+```
+
+
+
+
In the example above, we configure a `self` relation that is a link because of
the `href` parameter. Its value, which may look weird at first glance, will be
extensively covered in [The Expression Language](#the-expression-language)
section. This special value is used to generate a URI.
-In this section, [**annotations**](#annotations) are used to configure Hateoas.
+In this section, [**annotations/attributes**](#annotations) are used to configure Hateoas.
[**XML**](#xml) and [**YAML**](#yaml) formats are also supported. If you wish,
you can use plain PHP too.
@@ -241,6 +271,10 @@ fetch those resources.
An **embedded resource** is a named **relation** that contains data, represented
by the `embedded` parameter.
+
+
+Annotation (PHP < 8.1)
+
```php
use JMS\Serializer\Annotation as Serializer;
use Hateoas\Configuration\Annotation as Hateoas;
@@ -264,6 +298,33 @@ class User
}
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use JMS\Serializer\Annotation as Serializer;
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ 'manager',
+ href: "expr('/api/users/' ~ object.getManager().getId())",
+ embedded: "expr(object.getManager())",
+ exclusion: new Hateoas\Exclusion(excludeif: "expr(object.getManager() === null)"),
+ )]
+class User
+{
+ ...
+
+ #[Serializer\Exclude]
+ private $manager;
+}
+```
+
+
+
**Note:** You will need to exclude the manager property from the serialization,
otherwise both the serializer and Hateoas will serialize it.
You will also have to exclude the manager relation when the manager is `null`,
@@ -460,6 +521,10 @@ $xml = $hateoas->serialize($paginatedCollection, 'xml');
If you want to change the xml root name of the collection, create a new
class with the xml root configured and use the inline mechanism:
+
+
+Annotation (PHP < 8.1)
+
```php
use JMS\Serializer\Annotation as Serializer;
@@ -483,6 +548,33 @@ $paginatedCollection = ...;
$paginatedCollection = new UsersRepresentation($paginatedCollection);
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use JMS\Serializer\Annotation as Serializer;
+
+#[Serializer\XmlRoot('users')]
+class UsersRepresentation
+{
+ #[Serializer\Inline]
+ private $inline;
+
+ public function __construct($inline)
+ {
+ $this->inline = $inline;
+ }
+}
+
+$paginatedCollection = ...;
+$paginatedCollection = new UsersRepresentation($paginatedCollection);
+```
+
+
+
### Representations
As mentionned in the previous section, **representations** are classes configured
@@ -544,12 +636,32 @@ Each time you fill in a value (e.g. a Relation `href` in annotations or YAML),
you can either pass a **hardcoded value** or an **expression**.
In order to use the Expression Language, you have to use the `expr()` notation:
+
+
+Annotation (PHP < 8.1)
+
```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
/**
* @Hateoas\Relation("self", href = "expr('/api/users/' ~ object.getId())")
*/
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation('self', href: "expr('/api/users/' ~ object.getId())")]
+```
+
+
+
You can learn more about the Expression Syntax by reading the official
documentation: [The Expression
Syntax](http://symfony.com/doc/current/components/expression_language/syntax.html).
@@ -619,6 +731,10 @@ $hateoas = HateoasBuilder::create()
You will then be able to use the [@Route](#route) annotation:
+
+
+Annotation (PHP < 8.1)
+
```php
use Hateoas\Configuration\Annotation as Hateoas;
@@ -636,6 +752,29 @@ use Hateoas\Configuration\Annotation as Hateoas;
class User
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ 'self',
+ href: new Hateoas\Route(
+ 'user_get',
+ parameters: [
+ 'id' => 'expr(object.getId())',
+ ],
+ )
+)]
+class User
+```
+
+
+
```json
{
"id": 42,
@@ -688,6 +827,10 @@ The feature above is also available in your expressions (cf. [The Expression
Language](#the-expression-language)) through the `link(object, rel, absolute)`
**function**:
+
+
+Annotation (PHP < 8.1)
+
```php
/**
* @Hateoas\Relation(
@@ -727,6 +870,59 @@ class User
}
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+#[Hateoas\Relation(
+ 'self',
+ href: new Hateoas\Route(
+ 'post_get',
+ parameters: [
+ 'id' => 'expr(object.getId())',
+ ],
+ ),
+)]
+class Post {}
+
+#[Hateoas\Relation(
+ 'self',
+ href: new Hateoas\Route(
+ 'user_get',
+ parameters: [
+ 'id' => 'expr(object.getId())',
+ ],
+ ),
+)]
+#[Hateoas\Relation(
+ 'post',
+ href: "expr(link(object.getPost(), 'self', true))",
+)]
+#[Hateoas\Relation(
+ 'relative',
+ href: "expr(link(object.getRelativePost(), 'self'))",
+)]
+class User
+{
+ ...
+
+ public function getPost()
+ {
+ return new Post(456);
+ }
+
+ public function getRelativePost()
+ {
+ return new Post(789);
+ }
+}
+```
+
+
+
Pay attention to the `href` expressions for the `post` and `relative` relations,
as well as their corresponding values in the following JSON content:
@@ -965,9 +1161,9 @@ $hateoas = $builder
### Configuring Metadata Locations
Hateoas supports several metadata sources. By default, it uses Doctrine
-annotations, but you may also store metadata in XML, or YAML files. For the
-latter, it is necessary to configure a metadata directory where those files are
-located:
+annotations (PHP < 8.1) or native PHP attributes (PHP >= 8.1), but you may also
+store metadata in XML, or YAML files. For the latter, it is necessary to
+configure a metadata directory where those files are located:
```php
$hateoas = \Hateoas\HateoasBuilder::create()
@@ -1093,6 +1289,10 @@ Acme\Demo\Representation\User:
This annotation can be defined on a class.
+
+
+Annotation (PHP < 8.1)
+
```php
use Hateoas\Configuration\Annotation as Hateoas;
@@ -1107,6 +1307,26 @@ use Hateoas\Configuration\Annotation as Hateoas;
*/
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ name: 'self',
+ href: 'http://hello',
+ embedded: 'expr(object.getHello())',
+ attributes: ['foo' => 'bar'],
+ exclusion: '...',
+)]
+```
+
+
+
| Property | Required | Content | Expression language |
|------------|------------------------|---------------------------------|-----------------------|
| name | Yes | string | No |
@@ -1120,6 +1340,10 @@ with the `href` property, not with the `embedded` one).
#### @Route
+
+
+Annotation (PHP < 8.1)
+
```php
use Hateoas\Configuration\Annotation as Hateoas;
@@ -1136,6 +1360,28 @@ use Hateoas\Configuration\Annotation as Hateoas;
*/
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ name: 'self',
+ href: new Hateoas\Route(
+ 'user_get',
+ parameters: ['id' = 'expr(object.getId())'],
+ absolute: true,
+ generator: 'my_custom_generator',
+ ),
+)]
+```
+
+
+
This annotation can be defined in the **href** property of the
[@Relation](#relation) annotation. This is allows you to your URL generator,
if you have configured one.
@@ -1149,6 +1395,10 @@ if you have configured one.
#### @Embedded
+
+
+Annotation (PHP < 8.1)
+
```php
use Hateoas\Configuration\Annotation as Hateoas;
@@ -1164,6 +1414,27 @@ use Hateoas\Configuration\Annotation as Hateoas;
*/
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ name: 'friends',
+ embedded: new Hateoas\Embedded(
+ 'expr(object.getFriends())',
+ exclusion: '...',
+ xmlElementName: 'users',
+ ),
+)]
+```
+
+
+
This annotation can be defined in the **embedded** property of the
[@Relation](#relation) annotation. It is useful if you need configure the
`exclusion` or `xmlElementName` options for the embedded resource.
@@ -1194,7 +1465,13 @@ on the regular properties with the serializer.
under some circumstances. In this example, if the `getManager` method is `null`,
you should exclude it to prevent the URL generation from failing:
+
+
+Annotation (PHP < 8.1)
+
```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
/**
* @Hateoas\Relation(
* "manager",
@@ -1216,6 +1493,33 @@ class User
}
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\Relation(
+ name: 'manager',
+ href: new Hateoas\Route(
+ 'user_get',
+ parameters: ['id' => 'expr(object.getManager().getId())'],
+ ),
+ exclusion: new Hateoas\Exclusion(excludeIf: 'expr(null === object.getManager())')
+)]
+class User
+{
+ public function getId() {}
+
+ public function getManager(): ?User {}
+}
+```
+
+
+
#### @RelationProvider
This annotation can be defined on a class.
@@ -1246,6 +1550,10 @@ It can be "name":
Here and example using the expression language:
+
+
+Annotation (PHP < 8.1)
+
```php
use Hateoas\Configuration\Annotation as Hateoas;
@@ -1258,6 +1566,24 @@ class User
}
```
+
+
+
+
+Attribute (PHP 8.1 and greater)
+
+```php
+use Hateoas\Configuration\Annotation as Hateoas;
+
+#[Hateoas\RelationProvider("expr(service('user.rel_provider').getExtraRelations())")]
+class User
+{
+ ...
+}
+```
+
+
+
Here the `UserRelPrvider` class:
```php