Reousrce link
Resources can be linked to other resources. There are two types of links: external links 1, which link external resources, and internal links 2, which embed other resources in the resource itself.
Out-bound links
Specify links by rel
(relation) and href
of the link name. The href
can be a regular URI or RFC6570 URI template.
#[Link rel: 'profile', href: '/profile{?id}']
public function onGet($id): static
{
$this->body = [
'id' => 10
];
return $this;
}
In the above example, href
is represented by and $body['id']
is assigned to {?id}
. The output in HAL format is as follows
{
"id": 10,
"_links": {
"self": {
"href": "/test"
},
"profile": {
"href": "/profile?id=10"
}
}
}
Internal links
A resource can embed another resource. Specify the resource in the src
of #[Embed]
.
Internally linked resources may also internally link other resources. In that case, another internally linked resource is needed, and the process is repeated recursively to obtain a resource graph. The client can retrieve the desired set of resources at once without having to fetch the resources multiple times. 3 For example, instead of calling a customer resource and a product resource respectively, embed them both in an order resource.
use BEAR\Resource\Annotation\Embed;
class News extends ResourceObject
{
#[Embed(rel: 'sports', src: '/news/sports')]
#[Embed(rel: 'weather', src: '/news/weather')]
public function onGet(): static
It is the resource request that is embedded. It is executed at rendering time, but before that you can add arguments with the addQuery()
method or replace them with withQuery()
.
A URI template can be used for the src
, and request method arguments will be bound to it. (Unlike external links, it is not $body
)
use BEAR\Resource\Annotation\Embed;
class News extends ResourceObject
{
#[Embed(rel: 'website', src: '/website{?id}']
public function onGet(string $id): static
{
// ...
$this->body['website']->addQuery(['title' => $title]); // 引数追加
Self linking
Linking a relation as _self
in #[Embed]
copies the linked resource state to its own resource state.
namespace MyVendor\Weekday\ResourcePage;.
class Weekday extends ResourceObject
{
#[Embed(rel: '_self', src: 'app://self/weekday{?year,month,day}'])
public function onGet(string $id): static
{
In this example, the Page resource copies the state of the weekday
resource of the App resource to itself.
Internal links in HAL
Handled as _embedded
in the HAL renderer.
Link request
Clients can link resources connected by hyperlinks.
$blog = $this
->resource
->get
->uri('app://self/user')
->withQuery(['id' => 1])
->linkSelf("blog")
->eager
->request()
->body;
There are three types of links. The body
linked resource of the original resource is embedded using $rel
as the key.
linkSelf($rel)
which will be replaced with the link destination.linkNew($rel)
the linked resource is added to the original resourcelinkCrawl($rel)
crawl the link and create a resource graph.
crawl
Crawls are lists (arrays) of resources, and links can be traversed in sequence to compose complex resource graphs. Just as a crawler crawls a web page, the resource client crawls hyperlinks and generates a source graph.
Crawl Example
Consider a resource graph with author, post, meta, tag, and tag/name associated with each. Name this resource graph post-tree and specify a hyperreference href in the `#[Link]’ attribute of each resource.
The first starting point, the author resource, has a hyperlink to the post resource. 1:n relationship.
#[Link(crawl: "post-tree", rel: "post", href: "app://self/post?author_id={id}")]
public function onGet($id = null)
The post resource has hyperlinks to the meta and tag resources. 1:n relationship.
#[Link(crawl: "post-tree", rel: "meta", href: "app://self/meta?post_id={id}")]
#[Link(crawl: "post-tree", rel: "tag", href: "app://self/tag?post_id={id}")]
public function onGet($author_id)
{
A tag resource is just an ID with a hyperlink to the corresponding tag/name resource. 1:1 relationship.
#[Link(crawl:"post-tree", rel:"tag_name", href:"app://self/tag/name?tag_id={tag_id}")]
public function onGet($post_id)
Each is now connected. Request with a crawl name.
$graph = $resource
->get
->uri('app://self/marshal/author')
->linkCrawl('post-tree')
->eager
->request();
When a resource client finds a crawl name specified in the #[Link] attribute, it creates a resource graph by connecting resources by their rel names.
var_export($graph->body);
array (
0 =>
array (
'name' => 'Athos',
'post' =>
array (
0 =>
array (
'author_id' => '1',
'body' => 'Anna post #1',
'meta' =>
array (
0 =>
array (
'data' => 'meta 1',
),
),
'tag' =>
array (
0 =>
array (
'tag_name' =>
array (
0 =>
array (
'name' => 'zim',
),
),
),
...
-
out-bound links e.g.) html can link to other related html. ↩
-
embedded links Example: html can embed independent image resources. ↩
-
This is similar to an object graph where the dependency tree is a graph in DI. ↩