HATEOAS REST Web サービスの表現の実装をサポートする PHP ライブラリ。
Hateoas をインストールする推奨される方法は、Composer を使用することです。次のコマンドを実行して、 willdurand/hateoas
パッケージを要求します。
composer require willdurand/hateoas
これにより、最新の安定バージョンが解決されます。
それ以外の場合は、ライブラリをインストールし、オートローダーを自分でセットアップします。
設定にアノテーションを使用したい場合は、 doctrine/annotations
パッケージをインストールする必要があります。
composer require doctrine/annotations
アプリが PHP 8.1 以降を使用している場合は、ネイティブ PHP 属性を使用することをお勧めします。この場合、Doctrine パッケージをインストールする必要はありません。
そのためのバンドルがあります! BazingaHateoasBundle をインストールしてお楽しみください。
重要:
バージョン
1.0
を使用している場合は、このドキュメント ページにジャンプできます。
2.0
バージョンを使用している場合は、このドキュメント ページにジャンプできます。次のドキュメントは、 Hateoas 3.0以降向けに作成されています。
HATEOAS はSerializer ライブラリを活用して、HATEOAS REST Web サービスを構築する優れた方法を提供します。 HATEOAS は、 Hypermedia as the Engine of Application Stateの略で、表現(つまり API 応答) にハイパーメディア リンクを追加します。 HATEOAS は、リソースに対するアクションの発見可能性に関するものです。
たとえば、次のように単一ユーザーの表現を返すユーザー API があるとします。
{
"user" : {
"id" : 123 ,
"first_name" : " John " ,
"last_name" : " Doe "
}
}
この特定のユーザーのデータを取得する方法を API コンシューマーに伝えるには、この表現に最初のリンクを追加する必要があります。この特定のユーザーの URI であるため、これをself
呼びます。
{
"user" : {
"id" : 123 ,
"first_name" : " John " ,
"last_name" : " Doe " ,
"_links" : {
"self" : { "href" : " http://example.com/api/users/123 " }
}
}
}
では、ハテオアスについて詳しく見ていきましょう。
Hateoas の用語では、リンクはリソースに追加される関係とみなされます。リレーションは埋め込みリソースも参照することに注意してください。ただし、このトピックについては「リソースの埋め込み」セクションで説明します。
リンクは、 name
(例: self
) で識別され、 href
パラメーターを持つ関係です。
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 () {}
}
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 () {}
}
上記の例では、 href
パラメーターによりリンクであるself
関係を構成します。一見すると奇妙に見えるかもしれないその値については、「式言語」セクションで詳しく説明します。この特別な値は、URI の生成に使用されます。
このセクションでは、Hateoas を構成するためにアノテーション/属性が使用されます。 XMLおよびYAML形式もサポートされています。必要に応じて、プレーンな PHP も使用できます。
重要: Serializer と Hateoas の両方を同じ方法で構成する必要があります。たとえば、シリアライザーの構成に YAML を使用する場合は、Hateoas の構成にも YAML を使用します。
HATEOAS を試す最も簡単な方法は、 HateoasBuilder
を使用することです。ビルダーには、Hateoas シリアライザーを構成するための多数のメソッドがありますが、ここでは詳しく説明しません (「HateoasBuilder」を参照)。箱から出してすぐにすべてが正常に動作します。
use Hateoas HateoasBuilder ;
$ hateoas = HateoasBuilder:: create ()-> build ();
$ user = new User ( 42 , ' Adrien ' , ' Brault ' );
$ json = $ hateoas -> serialize ( $ user , ' json ' );
$ xml = $ hateoas -> serialize ( $ user , ' xml ' );
$hateoas
オブジェクトはJMSSerializerSerializerInterface
のインスタンスであり、Serializer ライブラリから取得されます。 Hateoas には独自のシリアライザーは付属しておらず、JMS シリアライザーにフックされます。
デフォルトでは、Hateoas は JSON シリアル化にハイパーテキスト アプリケーション言語 (HAL) を使用します。これは、応答の構造を指定します (たとえば、「リンク」は_links
キーの下に存在する必要があります)。
{
"id" : 42 ,
"first_name" : " Adrien " ,
"last_name" : " Brault " ,
"_links" : {
"self" : {
"href" : " /api/users/42 "
}
}
}
XML の場合、デフォルトで Atom Links が使用されます。
< user id = " 42 " >
< first_name > <![CDATA[ Adrien ]]> </ first_name >
< last_name > <![CDATA[ Brault ]]> </ last_name >
< link rel = " self " href = " /api/users/42 " />
</ user >
これらの形式はデフォルトの形式であり、使用可能な唯一の形式ではないことに注意してください。さまざまなシリアライザーを通じてさまざまな形式を使用したり、独自の形式を追加したりすることもできます。
リンクを追加する方法がわかったので、埋め込みリソースを追加する方法を見てみましょう。
場合によっては、関連リソースにリンクするよりも埋め込んだ方が、クライアントがそれらのリソースを取得するために追加のリクエストを行う必要がなくなるため、より効率的です。
埋め込みリソースは、 embedded
パラメータで表されるデータを含む名前付きリレーションです。
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 = @ Hateoas Exclusion ( excludeIf = "expr(object.getManager() === null)" )
* )
* /
class User
{
...
/ * * @ Serializer Exclude * /
private $ manager ;
}
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 ;
}
注:シリアル化からマネージャー プロパティを除外する必要があります。除外しないと、シリアライザーと Hateoas の両方がそれをシリアル化します。また、manager がnull
の場合は、manager リレーションを除外する必要があります。除外しないと、 href
リンクの作成時に ( null
でgetId()
を呼び出して) エラーが発生します。
ヒント:マネージャー プロパティがすでに_self
リンクを持つオブジェクトである場合は、ここで繰り返す代わりに、その値をhref
に再利用できます。 「リンクヘルパー」を参照してください。
$ hateoas = HateoasBuilder:: create ()-> build ();
$ user = new User ( 42 , ' Adrien ' , ' Brault ' , new User ( 23 , ' Will ' , ' Durand ' ));
$ json = $ hateoas -> serialize ( $ user , ' json ' );
$ xml = $ hateoas -> serialize ( $ user , ' xml ' );
json
の場合、HAL 表現はこれらの埋め込みリレーションを_embedded
キー内に配置します。
{
"id" : 42 ,
"first_name" : " Adrien " ,
"last_name" : " Brault " ,
"_links" : {
"self" : {
"href" : " /api/users/42 "
},
"manager" : {
"href" : " /api/users/23 "
}
},
"_embedded" : {
"manager" : {
"id" : 23 ,
"first_name" : " Will " ,
"last_name" : " Durand " ,
"_links" : {
"self" : {
"href" : " /api/users/23 "
}
}
}
}
}
XML では、 embedded
リレーションをシリアル化すると、新しい要素が作成されます。
< user id = " 42 " >
< first_name > <![CDATA[ Adrien ]]> </ first_name >
< last_name > <![CDATA[ Brault ]]> </ last_name >
< link rel = " self " href = " /api/users/42 " />
< link rel = " manager " href = " /api/users/23 " />
< manager rel = " manager " id = " 23 " >
< first_name > <![CDATA[ Will ]]> </ first_name >
< last_name > <![CDATA[ Durand ]]> </ last_name >
< link rel = " self " href = " /api/users/23 " />
</ manager >
</ user >
埋め込みリソースのタグ名は、シリアライザー構成からの@XmlRoot
アノテーション (YAML ではxml_root_name
、XML ではxml-root-name
) から推測されます。
このライブラリは、一般的なタスクを支援するためにHateoasRepresentation*
名前空間にいくつかのクラスを提供します。これらは、ライブラリのアノテーションを使用して構成された単純なクラスです。
PaginatedRepresentation
、 OffsetRepresentation
、およびCollectionRepresentation
クラスはおそらく最も興味深いクラスです。これらは、リソースが実際にリソースのコレクションである場合 (たとえば、 /users
ユーザーのコレクションである場合) に役立ちます。これらは、コレクションを表現し、ページネーションと制限を追加するのに役立ちます。
use Hateoas Representation PaginatedRepresentation ;
use Hateoas Representation CollectionRepresentation ;
$ paginatedCollection = new PaginatedRepresentation (
new CollectionRepresentation ( array ( $ user1 , $ user2 , ...)),
' user_list ' , // route
array (), // route parameters
1 , // page number
20 , // limit
4 , // total pages
' page ' , // page route parameter name , optional , defaults to 'page'
' limit ' , // limit route parameter name , optional , defaults to 'limit'
false , // generate relative URIs , optional , defaults to `false`
75 // total collection size , optional , defaults to `null`
);
$ json = $ hateoas -> serialize ( $ paginatedCollection , ' json ' );
$ xml = $ hateoas -> serialize ( $ paginatedCollection , ' xml ' );
CollectionRepresentation
埋め込みコレクションの基本的な表現を提供します。
PaginatedRepresentation
は、 self
、 first
、および可能な場合はlast
、 next
、およびprevious
リンクを追加するように設計されています。
OffsetRepresentation
PaginatedRepresentation
と同じように機能しますが、ページネーションがoffset
、 limit
、 total
で表される場合に便利です。
RouteAwareRepresentation
指定されたルートに基づいてself
関係を追加します。
PaginatedRepresentation
とRouteAwareRepresentation
の両方でabsolute
パラメータをtrue
に設定することで、絶対 URI を生成できます。
Hateoas ライブラリは、Pagerfanta インスタンスからPaginatedRepresentation
簡単に構築するためのPagerfantaFactory
も提供します。 Pagerfanta ライブラリを使用する場合、これはコレクション表現を作成する簡単な方法です。
use Hateoas Configuration Route ;
use Hateoas Representation Factory PagerfantaFactory ;
$ pagerfantaFactory = new PagerfantaFactory (); // you can pass the page ,
// and limit parameters name
$ paginatedCollection = $ pagerfantaFactory -> createRepresentation (
$ pager ,
new Route ( ' user_list ' , array ())
);
$ json = $ hateoas -> serialize ( $ paginatedCollection , ' json ' );
$ xml = $ hateoas -> serialize ( $ paginatedCollection , ' xml ' );
次の JSON コンテンツが得られます。
{
"page" : 1 ,
"limit" : 10 ,
"pages" : 1 ,
"_links" : {
"self" : {
"href" : " /api/users?page=1&limit=10 "
},
"first" : {
"href" : " /api/users?page=1&limit=10 "
},
"last" : {
"href" : " /api/users?page=1&limit=10 "
}
},
"_embedded" : {
"items" : [
{ "id" : 123 },
{ "id" : 456 }
]
}
}
そして次の XML コンテンツ:
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< collection page = " 1 " limit = " 10 " pages = " 1 " >
< entry id = " 123 " ></ entry >
< entry id = " 456 " ></ entry >
< link rel = " self " href = " /api/users?page=1 & limit=10 " />
< link rel = " first " href = " /api/users?page=1 & limit=10 " />
< link rel = " last " href = " /api/users?page=1 & limit=10 " />
</ collection >
インライン化されたCollectionRepresentation
カスタマイズする場合は、 createRepresentation()
メソッドの 3 番目の引数として 1 つを渡します。
use Hateoas Representation Factory PagerfantaFactory ;
$ pagerfantaFactory = new PagerfantaFactory (); // you can pass the page and limit parameters name
$ paginatedCollection = $ pagerfantaFactory -> createRepresentation (
$ pager ,
new Route ( ' user_list ' , array ()),
new CollectionRepresentation ( $ pager -> getCurrentPageResults ())
);
$ json = $ hateoas -> serialize ( $ paginatedCollection , ' json ' );
$ xml = $ hateoas -> serialize ( $ paginatedCollection , ' xml ' );
コレクションの XML ルート名を変更する場合は、XML ルートが構成された新しいクラスを作成し、インライン メカニズムを使用します。
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 );
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 );
前のセクションで説明したように、表現は、一般的なタスクを支援するためにライブラリのアノテーションを使用して構成されたクラスです。コレクションの表現については、 「コレクションの処理」で説明されています。
VndErrorRepresentation
使用すると、 vnd.error
仕様に従ってエラー応答を記述することができます。
$ error = new VndErrorRepresentation (
' Validation failed ' ,
42 ,
' http://.../ ' ,
' http://.../ '
);
このような表現を XML および JSON でシリアル化すると、次の出力が得られます。
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< resource logref = " 42 " >
< message > <![CDATA[ Validation failed ]]> </ message >
< link rel = " help " href = " http://.../ " />
< link rel = " describes " href = " http://.../ " />
</ resource >
{
"message" : " Validation failed " ,
"logref" : 42 ,
"_links" : {
"help" : {
"href" : " http://.../ "
},
"describes" : {
"href" : " http://.../ "
}
}
}
ヒント: VndErrorRepresentation
クラスを拡張する独自のエラー クラスを作成することをお勧めします。
Hateoas は、強力な Symfony ExpressionLanguage コンポーネントを利用して、埋め込むリンク、ID、オブジェクトなどの値を取得します。
値 (アノテーションまたは YAML の Relation href
など) を入力するたびに、ハードコードされた値または式のいずれかを渡すことができます。式言語を使用するには、 expr()
表記を使用する必要があります。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation ( "self" , href = "expr('/api/users/' ~ object.getId())" )
* /
use Hateoas Configuration Annotation as Hateoas ;
#[ Hateoas Relation( ' self ' , href: " expr('/api/users/' ~ object.getId()) " )]
式構文の詳細については、公式ドキュメント「式構文」を参照してください。
ネイティブでは、 object
という名前の特別な変数が各式で使用でき、現在のオブジェクトを表します。
expr(object.getId())
このような変数をコンテキスト変数と呼びます。
独自のコンテキスト変数を式エバリュエーターに追加することで、式言語コンテキストに追加できます。
HateoasBuilder
を使用して、 setExpressionContextVariable()
メソッドを呼び出して、新しいコンテキスト変数を追加します。
use Hateoas HateoasBuilder ;
$ hateoas = HateoasBuilder:: create ()
-> setExpressionContextVariable ( ' foo ' , new Foo ())
-> build ();
foo
変数が使用できるようになりました。
expr(foo !== null)
式言語に関数を追加する方法の詳細については、https://symfony.com/doc/current/components/expression_ language/extending.html を参照してください。
式言語を使用して関係リンク ( href
キー) を定義できるため、デフォルトで多くのことができます。ただし、フレームワークを使用している場合は、ルートを使用してリンクを構築する可能性があります。
まずビルダーでUrlGenerator
構成する必要があります。 HateoasUrlGeneratorUrlGeneratorInterface
を実装することも、 HateoasUrlGeneratorCallableUrlGenerator
を使用することもできます。
use Hateoas UrlGenerator CallableUrlGenerator ;
$ hateoas = HateoasBuilder:: create ()
-> setUrlGenerator (
null , // By default all links uses the generator configured with the null name
new CallableUrlGenerator ( function ( $ route , array $ parameters , $ absolute ) use ( $ myFramework ) {
return $ myFramework -> generateTheUrl ( $ route , $ parameters , $ absolute );
})
)
-> build ()
;
これで、 @Route アノテーションを使用できるようになります。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation (
* "self" ,
* href = @ Hateoas Route (
* "user_get" ,
* parameters = {
* "id" = "expr(object.getId())"
* }
* )
* )
* /
class User
use Hateoas Configuration Annotation as Hateoas ;
#[ Hateoas Relation(
' self ' ,
href: new Hateoas Route (
' user_get ' ,
parameters: [
' id ' => ' expr(object.getId()) ' ,
],
)
)]
class User
{
"id" : 42 ,
"first_name" : " Adrien " ,
"last_name" : " Brault " ,
"_links" : {
"self" : {
"href" : " /api/users/42 "
}
}
}
このライブラリにはSymfonyUrlGenerator
が付属していることに注意してください。たとえば、Silex で使用するには:
use Hateoas UrlGenerator SymfonyUrlGenerator ;
$ hateoas = HateoasBuilder:: create ()
-> setUrlGenerator ( null , new SymfonyUrlGenerator ( $ app [ ' url_generator ' ]))
-> build ()
;
Hateoas は、API の構築プロセスを容易にする一連のヘルパーを提供します。
LinkHelper
クラスはgetLinkHref($object, $rel, $absolute = false)
メソッドを提供します。このメソッドを使用すると、任意のオブジェクトのhref値を、任意の指定されたリレーション名に対して取得できます。任意のリンク関係から URI (絶対または相対) を生成できます。
$ user = new User ( 123 , ' William ' , ' Durand ' );
$ linkHelper -> getLinkHref ( $ user , ' self ' );
// / api / users / 123
$ linkHelper -> getLinkHref ( $ user , ' self ' , true );
// http : // example . com / api / users / 123
link
機能上記の機能はlink(object, rel, absolute)
関数を使用して式 (式言語を参照) でも利用できます。
/ * *
* @ Hateoas Relation (
* "self" ,
* href = @ Hateoas Route ( "post_get" , parameters = { "id" = "expr(object.getId())" })
* )
* /
class Post {}
/ * *
* @ Hateoas Relation (
* "self" ,
* href = @ 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 );
}
}
#[ 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 );
}
}
post
およびrelative
関係のhref
式と、次の JSON コンテンツ内の対応する値に注意してください。
{
"user" : {
"id" : 123 ,
"first_name" : " William " ,
"last_name" : " Durand " ,
"_links" : {
"self" : { "href" : " http://example.com/api/users/123 " },
"post" : { "href" : " http://example.com/api/posts/456 " },
"relative" : { "href" : " /api/posts/789 " }
}
}
}
getLinkHref()
メソッドとlink
関数の両方で 3 番目の引数を使用すると、絶対 URI と相対 URI のどちらを使用するかを強制できることに注意してください。
重要:デフォルトでは、設定で絶対として定義されている URI も含め、すべての URI は相対になります。
$ linkHelper -> getLinkHref ( $ user , ' post ' );
// / api / posts / 456
$ linkHelper -> getLinkHref ( $ user , ' post ' , true );
// http : // example . com / api / posts / 456
$ linkHelper -> getLinkHref ( $ user , ' relative ' );
// / api / posts / 789
$ linkHelper -> getLinkHref ( $ user , ' relative ' , true );
// http : // example . com / api / posts / 789
Hateoas は Twig 拡張機能のセットも提供します。
LinkExtension
使用すると、Twig テンプレートで LinkHelper を使用できるため、たとえば HTML テンプレートでリンクを生成できます。
この拡張機能は、 link_href
Twig 関数を通じてgetLinkHref()
ヘルパーのメソッドを公開します。
{{ link_href(user, 'self') }}
{# will generate: /users/123 #}
{{ link_href(will, 'self', false) }}
{# will generate: /users/123 #}
{{ link_href(will, 'self', true) }}
{# will generate: http://example.com/users/123 #}
Hateoas はシリアライザーのセットを提供します。各シリアライザーを使用すると、HAL や Atom Links などの特定の形式に従って XML または JSON コンテンツを生成できます。
JsonHalSerializer
使用すると、JSON で HAL 準拠の関係を生成できます。これは、Hateoas のデフォルトの JSON シリアライザーです。
HAL は、リソース オブジェクトには_links
と呼ばれる予約されたプロパティがあるという規約でリンク機能を提供します。このプロパティは、リンクを含むオブジェクトです。これらのリンクは、リンク関係によってキー設定されます。
HAL では、リソースが_embedded
という名前の別の予約プロパティを持つことができるという別の規則も説明しています。このプロパティは、埋め込みリソースが関係名によってキー設定されるという点で_links
に似ています。主な違いは、値がリンクではなくリソース オブジェクトであることです。
{
"message" : " Hello, World! " ,
"_links" : {
"self" : {
"href" : " /notes/0 "
}
},
"_embedded" : {
"associated_events" : [
{
"name" : " SymfonyCon " ,
"date" : " 2013-12-12T00:00:00+0100 "
}
]
}
}
XmlSerializer
使用すると、XML ドキュメントに Atom リンクを生成できます。これはデフォルトの XML シリアライザーです。
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< note >
< message > <![CDATA[ Hello, World! ]]> </ message >
< link rel = " self " href = " /notes/0 " />
< events rel = " associated_events " >
< event >
< name > <![CDATA[ SymfonyCon ]]> </ name >
< date > <![CDATA[ 2013-12-12T00:00:00+0100 ]]> </ date >
</ event >
</ events >
</ note >
XmlHalSerializer
使用すると、XML で HAL 準拠の関係を生成できます。
XML の HAL は、 link
タグとresource
タグを記述するという点で JSON の HAL に似ています。
注: self
関係は、実際にはlink
タグではなく、メイン リソースの属性になります。その他のリンクはlink
タグとして生成されます。
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< note href = " /notes/0 " >
< message > <![CDATA[ Hello, World! ]]> </ message >
< resource rel = " associated_events " >
< name > <![CDATA[ SymfonyCon ]]> </ name >
< date > <![CDATA[ 2013-12-12T00:00:00+0100 ]]> </ date >
</ resource >
</ note >
リンクと埋め込みリレーションをシリアル化する 2 つのメソッドを記述するSerializerInterface
を実装する必要があります。
HateoasBuilder
クラスは、強力で流暢な API のおかげで、Hateoas を簡単に構成するために使用されます。
use Hateoas HateoasBuilder ;
$ hateoas = HateoasBuilder:: create ()
-> setCacheDir ( ' /path/to/cache/dir ' )
-> setDebug ( $ trueOrFalse )
-> setDefaultXmlSerializer ()
. . .
-> build ();
以下のすべてのメソッドは現在のビルダーを返すため、それらを連鎖させることができます。
setXmlSerializer(SerializerInterface $xmlSerializer)
: 使用する XML シリアライザーを設定します。デフォルトは: XmlSerializer
です。setDefaultXmlSerializer()
: デフォルトの XML シリアライザー ( XmlSerializer
) を設定します。 setJsonSerializer(SerializerInterface $jsonSerializer)
: 使用する JSON シリアライザーを設定します。デフォルトは: JsonHalSerializer
;setDefaultJsonSerializer()
: デフォルトの JSON シリアライザー ( JsonHalSerializer
) を設定します。 setUrlGenerator($name = null, UrlGeneratorInterface $urlGenerator)
: 新しい名前付き URL ジェネレーターを追加します。 $name
がnull
の場合、URL ジェネレーターがデフォルトの URL ジェネレーターになります。 setExpressionContextVariable($name, $value)
: 新しい式コンテキスト変数を追加します。setExpressionLanguage(ExpressionLanguage $expressionLanguage)
; includeInterfaceMetadata($include)
: インターフェースからのメタデータを含めるかどうか。setMetadataDirs(array $namespacePrefixToDirMap)
: 名前空間プレフィックスのディレクトリへのマップを設定します。このメソッドは、以前に定義されたディレクトリをオーバーライドします。addMetadataDir($dir, $namespacePrefix = '')
: シリアライザーがクラス メタデータを検索するディレクトリを追加します。addMetadataDirs(array $namespacePrefixToDirMap)
: 名前空間プレフィックスのマップをディレクトリに追加します。replaceMetadataDir($dir, $namespacePrefix = '')
: addMetadataDir()
と似ていますが、既存のエントリをオーバーライドします。詳細については、シリアライザーの公式ドキュメントをお読みください。
setDebug($debug)
: デバッグ モードを有効または無効にします。setCacheDir($dir)
: キャッシュ ディレクトリを設定します。シリアライザーと Hateoas ライブラリはどちらも、YML、XML、アノテーションなどのさまざまなソースからオブジェクトに関するメタデータを収集します。このプロセスをできるだけ効率的にするには、Hateoas ライブラリがこの情報をキャッシュできるようにすることをお勧めします。これを行うには、キャッシュ ディレクトリを構成します。
$ builder = Hateoas HateoasBuilder:: create ();
$ hateoas = $ builder
-> setCacheDir ( $ someWritableDir )
-> build ();
Hateoas はいくつかのメタデータ ソースをサポートしています。デフォルトでは、Doctrine アノテーション (PHP < 8.1) またはネイティブ PHP 属性 (PHP >= 8.1) を使用しますが、メタデータを XML または YAML ファイルに保存することもできます。後者の場合、これらのファイルが配置されるメタデータ ディレクトリを構成する必要があります。
$ hateoas = Hateoas HateoasBuilder:: create ()
-> addMetadataDir ( $ someDir )
-> build ();
Hateoas は、メタデータ ファイルが、すべてのが に置き換えられた完全修飾クラス名のような名前が付けられることを期待します
.
。クラスの名前がVendorPackageFoo
の場合、メタデータ ファイルは$someDir/Vendor.Package.Foo.(xml|yml)
に配置する必要があります。
Hateoas を使用すると、構成レベルで拡張ポイントを提供することで、フレームワークがクラスにリレーションを動的に追加できるようになります。この機能は、Hateoas の上に新しいレイヤーを作成したい場合、または各クラスに同じ構成をコピーするのではなく「グローバル」関係を追加したい場合に役立ちます。
このメカニズムを利用するには、 ConfigurationExtensionInterface
インターフェイスを実装する必要があります。
use Hateoas Configuration Metadata ConfigurationExtensionInterface ;
use Hateoas Configuration Metadata ClassMetadataInterface ;
use Hateoas Configuration Relation ;
class AcmeFooConfigurationExtension implements ConfigurationExtensionInterface
{
/ * *
* {@ inheritDoc }
* /
public function decorate ( ClassMetadataInterface $ classMetadata ): void
{
if ( 0 === strpos ( ' AcmeFooModel ' , $ classMetadata -> getName ())) {
// Add a "root" relation to all classes in the `AcmeFooModel` namespace
$ classMetadata -> addRelation (
new Relation (
' root ' ,
' / '
)
);
}
}
}
$classMetadata->getRelations()
を使用して、アノテーション、XML、または YAML からロードされた既存のリレーションにアクセスできます。
$classMetadata
にリレーションがある場合、または $classMetadata にリレーションを追加すると、そのリレーションがキャッシュされます。したがって、構成ファイル (アノテーション、XML、または YAML) を読み取る場合は、必ずクラス メタデータでそれらのファイルを参照してください。
$ classMetadata -> fileResources [] = $ file ;
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< serializer >
< class name = " AcmeDemoRepresentationUser " h : providers = " Class::getRelations expr(sevice('foo').getMyAdditionalRelations()) " xmlns : h = " https://github.com/willdurand/Hateoas " >
< h : relation rel = " self " >
< h : href uri = " http://acme.com/foo/1 " />
</ h : relation >
< h : relation rel = " friends " >
< h : href route = " user_friends " generator = " my_custom_generator " >
< h : parameter name = " id " value = " expr(object.getId()) " />
< h : parameter name = " page " value = " 1 " />
</ h : ref >
< h : embedded xml-element-name = " users " >
< h : content >expr(object.getFriends())</ h : content >
< h : exclusion ... />
</ h : embedded >
< h : exclusion groups = " Default, user_full " since-version = " 1.0 " until-version = " 2.2 " exclude-if = " expr(object.getFriends() === null) " />
</ h : relation >
</ class >
</ serializer >
詳細については、 hateoas.xsd
ファイルを参照してください。
AcmeDemoRepresentationUser :
relations :
-
rel : self
href : http://acme.com/foo/1
-
rel : friends
href :
route : user_friends
parameters :
id : expr(object.getId())
page : 1
generator : my_custom_generator
absolute : false
embedded :
content : expr(object.getFriends())
xmlElementName : users
exclusion : ...
exclusion :
groups : [Default, user_full]
since_version : 1.0
until_version : 2.2
exclude_if : expr(object.getFriends() === null)
relation_providers : [ "Class::getRelations", "expr(sevice('foo').getMyAdditionalRelations())" ]
このアノテーションはクラスに対して定義できます。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation (
* name = "self" ,
* href = "http://hello" ,
* embedded = "expr(object.getHello())" ,
* attributes = { "foo" = "bar" },
* exclusion = ...,
* )
* /
use Hateoas Configuration Annotation as Hateoas ;
#[ Hateoas Relation(
name: ' self ' ,
href: ' http://hello ' ,
embedded: ' expr(object.getHello()) ' ,
attributes: [ ' foo ' => ' bar ' ],
exclusion: ' ... ' ,
)]
財産 | 必須 | コンテンツ | 表現言語 |
---|---|---|---|
名前 | はい | 弦 | いいえ |
href | 埋め込みが設定されていない場合 | 文字列 / @Route | はい |
埋め込み | hrefが設定されていない場合 | 文字列 / @Embedded | はい |
属性 | いいえ | 配列 | 値に関してはい |
除外 | いいえ | @除外 | 該当なし |
重要: attributes
リンク関係でのみ使用されます (つまり、 embedded
プロパティではなく、 href
プロパティと組み合わせて使用されます)。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation (
* name = "self" ,
* href = @ Hateoas Route (
* "user_get" ,
* parameters = { "id" = "expr(object.getId())" },
* absolute = true ,
* generator = "my_custom_generator"
* )
* )
* /
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 ' ,
),
)]
このアノテーションは、@Relation アノテーションのhrefプロパティで定義できます。これにより、URL ジェネレーターが構成されている場合に使用できるようになります。
財産 | 必須 | コンテンツ | 表現言語 |
---|---|---|---|
名前 | はい | 弦 | いいえ |
パラメータ | デフォルトは array() | 配列 / 文字列 | はい (文字列 + 配列値) |
絶対 | デフォルトは false | ブール値 / 文字列 | はい |
ジェネレータ | いいえ | 文字列 / null | いいえ |
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation (
* name = "friends" ,
* embedded = @ Hateoas Embedded (
* "expr(object.getFriends())" ,
* exclusion = ...,
* xmlElementName = "users"
* )
* )
* /
use Hateoas Configuration Annotation as Hateoas ;
#[ Hateoas Relation(
name: ' friends ' ,
embedded: new Hateoas Embedded (
' expr(object.getFriends()) ' ,
exclusion: ' ... ' ,
xmlElementName: ' users ' ,
),
)]
このアノテーションは、@Relation アノテーションの埋め込みプロパティで定義できます。これは、埋め込みリソースのexclusion
またはxmlElementName
オプションを構成する必要がある場合に役立ちます。
財産 | 必須 | コンテンツ | 表現言語 |
---|---|---|---|
コンテンツ | はい | 文字列/配列 | はい (文字列) |
除外 | デフォルトは array() | @除外 | 該当なし |
xml要素名 | デフォルトは array() | 弦 | いいえ |
このアノテーションは、@Relation アノテーションと @Embedded アノテーションの両方の除外プロパティで定義できます。
財産 | 必須 | コンテンツ | 表現言語 |
---|---|---|---|
グループ | いいえ | 配列 | いいえ |
以降のバージョン | いいえ | 弦 | いいえ |
バージョンまで | いいえ | 弦 | いいえ |
最大深度 | いいえ | 整数 | いいえ |
除外する場合 | いいえ | 文字列 / ブール値 | はい |
excludeIf
を除くすべての値は、シリアライザーを使用して通常のプロパティで直接使用される場合と同じように動作します。
excludeIf
ブール値を想定しており、ある状況下で別の式が失敗する場合に役立ちます。この例では、 getManager
メソッドがnull
場合、URL 生成の失敗を防ぐためにそれを除外する必要があります。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas Relation (
* "manager" ,
* href = @ Hateoas Route (
* "user_get" ,
* parameters = { "id" = "expr(object.getManager().getId())" }
* ),
* exclusion = @ Hateoas Exclusion ( excludeIf = "expr(null === object.getManager())" )
* )
* /
class User
{
public function getId () {}
/ * *
* @ return User | null
* /
public function getManager () {}
}
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 {}
}
このアノテーションはクラスに対して定義できます。複数のリレーション(リンク)をシリアル化したい場合に便利です。例として:
{
"_links": {
"relation_name": [
{"href": "link1"},
{"href": "link2"},
{"href": "link3"}
]
}
}
財産 | 必須 | コンテンツ | 表現言語 |
---|---|---|---|
名前 | はい | 弦 | はい |
「名前」にすることもできます。
my_func
MyClass::getExtraRelations
expr(service('user.rel_provider').getExtraRelations())
ここでは、式言語を使用した例を示します。
use Hateoas Configuration Annotation as Hateoas ;
/ * *
* @ Hateoas RelationProvider ( "expr(service('user.rel_provider').getExtraRelations())" )
* /
class User
{
...
}
use Hateoas Configuration Annotation as Hateoas ;
#[ Hateoas RelationProvider( " expr(service('user.rel_provider').getExtraRelations()) " )]
class User
{
...
}
ここでUserRelPrvider
クラスは次のようになります。
use Hateoas Configuration Relation ;
use Hateoas Configuration Route ;
class UserRelPrvider
{
private $ evaluator ;
public function __construct ( CompilableExpressionEvaluatorInterface $ evaluator )
{
$ this -> evaluator = $ evaluator ;
}
/ * *
* @ return Relation []
* /
public function getExtraRelations (): array
{
// You need to return the relations
return array (
new Relation (
' self ' ,
new Route (
' foo_get ' ,
[ ' id ' => $ this -> evaluator -> parse ( ' object.getId() ' , [ ' object ' ])]
)
)
);
}
}
CompilableExpressionEvaluatorInterface
を実装する$this->evaluator
後で使用するためにキャッシュして保存できる形式で式言語を解析するために使用されます。関係に表現言語が必要ない場合、このサービスは必要ありません。
user.rel_provider
サービスは次のように定義されます。
user.rel_provider :
class : UserRelPrvider
arguments :
- ' @jms_serializer.expression_evaluator '
この場合、 jms_serializer.expression_evaluator
CompilableExpressionEvaluatorInterface
を実装するサービスです。
このセクションでは、Hateoas の内部について言及し、このライブラリの隠された部分に関するドキュメントを提供します。これは必ずしもエンド ユーザーに関係があるわけではありませんが、開発者や内部でどのように動作するかを知りたい人にとっては興味深いものです。
willdurand/hateoas
セマンティック バージョニングに従います。
2013 年 10 月の時点で、バージョン1.x
と0.x
正式にサポートされなくなりました ( 1.x
はリリースされていないことに注意してください)。
バージョン3.x
は、現在のメジャー安定バージョンです。
バージョン2.x
セキュリティ バグの修正および発生する可能性のある重大な問題のためにのみ維持されます。
COTRIBUTING ファイルを参照してください。
Composer dev
依存関係をインストールします。
php composer.phar install --dev
次に、PHPUnit を使用してテスト スイートを実行します。
bin/phpunit
Hateoas は MIT ライセンスに基づいてリリースされています。詳細については、同梱の LICENSE ファイルを参照してください。