nilportugues/haljson-bundle
Symfony 2 和 Symfony 3 的 HAL+JSON API Transformer Bundle
Requires
- php: >=5.5.0
- nilportugues/hal: ^2.0
- symfony/psr-http-message-bridge: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^1.9
- symfony/symfony: ^2|^3
README
适用于 Symfony 2 和 Symfony 3
安装
步骤 1:下载 Bundle
打开命令控制台,进入您的项目目录,然后执行以下命令以下载此 Bundle 的最新稳定版本
$ composer require nilportugues/haljson-bundle
步骤 2:启用 Bundle
然后,通过将其添加到项目中 app/AppKernel.php
文件中注册的 Bundle 列表来启用 Bundle
<?php // app/AppKernel.php // ... class AppKernel extends Kernel { public function registerBundles() { $bundles = array( // ... new NilPortugues\Symfony\HalJsonBundle\NilPortuguesSymfonyHalJsonBundle(), ); // ... } // ... }
用法
创建映射
映射目录
映射文件应位于 app/config/serializer
目录。必须创建此目录。
它还可以通过编辑 app/config/config.yml
配置文件来自定义并放置在其他位置
# app/config/config.yml nilportugues_hal_json: mappings: - "%kernel.root_dir%/config/serializer/" - @AppBundle/Product/config/Mappings
映射文件
HAL+JSON 转换器通过将现有的 PHP 对象转换为其 JSON 表示形式来工作。对于每个对象,都需要一个映射文件。
映射文件 必须 放置在映射目录中。预期的映射文件格式是 .yml
,将允许您重命名、隐藏和创建与所有数据相关联的链接。
例如,这里有一个相当复杂的 Post
对象来演示它的工作方式
$post = new Post( new PostId(9), 'Hello World', 'Your first post', new User( new UserId(1), 'Post Author' ), [ new Comment( new CommentId(1000), 'Have no fear, sers, your king is safe.', new User(new UserId(2), 'Barristan Selmy'), [ 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), ] ), ] );
以及所需的映射文件系列
# app/config/serializer/acme_domain_dummy_post.yml mapping: class: Acme\Domain\Dummy\Post alias: Message aliased_properties: author: author title: headline content: body hide_properties: [] id_properties: - postId urls: self: get_post ## @Route name comments: get_post_comments ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
# app/config/serializer/acme_domain_dummy_value_object_post_id.yml mapping: class: Acme\Domain\Dummy\ValueObject\PostId aliased_properties: [] hide_properties: [] id_properties: - postId urls: self: get_post ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
# app/config/serializer/acme_domain_dummy_comment.yml mapping: class: Acme\Domain\Dummy\Comment aliased_properties: [] hide_properties: [] id_properties: - commentId urls: self: get_comment ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
# app/config/serializer/acme_domain_dummy_value_object_comment_id.yml mapping: class: Acme\Domain\Dummy\ValueObject\CommentId aliased_properties: [] hide_properties: [] id_properties: - commentId urls: self: get_comment ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
# app/config/serializer/acme_domain_dummy_user.yml mapping: class: Acme\Domain\Dummy\User aliased_properties: [] hide_properties: [] id_properties: - userId urls: self: get_user friends: get_user_friends ## @Route name comments: get_user_comments ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
# app/config/serializer/acme_domain_dummy_value_object_user_id.yml mapping: class: Acme\Domain\Dummy\ValueObject\UserId aliased_properties: [] hide_properties: [] id_properties: - userId urls: self: get_user ## @Route name friends: get_user_friends ## @Route name comments: get_user_comments ## @Route name curies: name: example href: http://example.com/docs/rels/{rel}
输出 API 响应
这非常简单,只需从 服务容器 中获取 HalJsonSerializer
的实例,并将对象传递给其 serialize()
方法。输出将是有效的 JSON-API。
以下是从 Doctrine 存储库获取的 Post
对象的示例。
最后,提供了一个辅助特质,HalJsonResponseTrait
,用于编写完全兼容的响应,封装原始 JSON API Transformer 库提供的 PSR-7 Response 对象。
<?php namespace AppBundle\Controller; use NilPortugues\Symfony\HalJsonBundle\Serializer\HalJsonResponseTrait; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PostController extends Controller { use HalJsonResponseTrait; /** * @\Symfony\Component\Routing\Annotation\Route("/post/{postId}", name="get_post") * * @param $postId * @return \Symfony\Component\HttpFoundation\Response */ public function getPostAction($postId) { $post = $this->get('doctrine.post_repository')->find($postId); $serializer = $this->get('nil_portugues.serializer.hal_json_serializer'); /** @var \NilPortugues\Api\Hal\HalTransformer $transformer */ $transformer = $serializer->getTransformer(); $transformer->setSelfUrl($this->generateUrl('get_post', ['postId' => $postId], true)); $transformer->setNextUrl($this->generateUrl('get_post', ['postId' => $postId+1], true)); return $this->response($serializer->serialize($post)); } }
输出
HTTP/1.1 200 OK
Cache-Control: private, max-age=0, must-revalidate
Content-type: application/hal+json
{ "post_id": 9, "headline": "Hello World", "body": "Your first post", "_embedded": { "author": { "user_id": 1, "name": "Post Author", "_links": { "self": { "href": "http://example.com/users/1" }, "example:friends": { "href": "http://example.com/users/1/friends" }, "example:comments": { "href": "http://example.com/users/1/comments" } } }, "comments": [ { "comment_id": 1000, "dates": { "created_at": "2015-08-13T22:47:45+02:00", "accepted_at": "2015-08-13T23:22:45+02:00" }, "comment": "Have no fear, sers, your king is safe.", "_embedded": { "user": { "user_id": 2, "name": "Barristan Selmy", "_links": { "self": { "href": "http://example.com/users/2" }, "example:friends": { "href": "http://example.com/users/2/friends" }, "example:comments": { "href": "http://example.com/users/2/comments" } } } }, "_links": { "example:user": { "href": "http://example.com/users/2" }, "self": { "href": "http://example.com/comments/1000" } } } ] }, "_links": { "curies": [ { "name": "example", "href": "http://example.com/docs/rels/{rel}", "templated": true } ], "self": { "href": "http://example.com/posts/9" }, "next": { "href": "http://example.com/posts/10" }, "example:author": { "href": "http://example.com/users/1" }, "example:comments": { "href": "http://example.com/posts/9/comments" } }, "_meta": { "author": [ { "name": "Nil Portugués Calderó", "email": "contact@nilportugues.com" } ] } }
响应对象(HalJsonResponseTrait)
以下 HalJsonResponseTrait
方法提供正确的头信息和可用的 HTTP 状态码
private function errorResponse($json); private function resourceCreatedResponse($json); private function resourceDeletedResponse($json); private function resourceNotFoundResponse($json); private function resourcePatchErrorResponse($json); private function resourcePostErrorResponse($json); private function resourceProcessingResponse($json); private function resourceUpdatedResponse($json); private function response($json); private function unsupportedActionResponse($json);
NelmioApiDocBundleBundle 集成
NelmioApiDocBundle 是一个非常有名的 Bundle,用于文档化 API。与当前 Bundle 的集成非常简单。
以下是一个遵循之前提供的 PostContoller::getPostAction()
的示例
<?php namespace AppBundle\Controller; use NilPortugues\Symfony\HalJsonBundle\Serializer\HalJsonResponseTrait; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PostController extends Controller { use HalJsonResponseTrait; /** * Get a Post by its identifier. Will return Post, Comments and User data. * * @Nelmio\ApiDocBundle\Annotation\ApiDoc( * resource=true, * description="Get a Post by its unique id", * ) * * @Symfony\Component\Routing\Annotation\Route("/post/{postId}", name="get_post") * @Sensio\Bundle\FrameworkExtraBundle\Configuration\Method({"GET"}) * * @param $postId * @return \Symfony\Component\HttpFoundation\Response */ public function getPostAction($postId) { $post = $this->get('doctrine.post_repository')->find($postId); $serializer = $this->get('nil_portugues.serializer.hal_json_serializer'); /** @var \NilPortugues\Api\Hal\JsonTransformer $transformer */ $transformer = $serializer->getTransformer(); $transformer->setSelfUrl($this->generateUrl('get_post', ['postId' => $postId], true)); $transformer->setNextUrl($this->generateUrl('get_post', ['postId' => $postId+1], true)); return $this->response($serializer->serialize($post)); } }
以及推荐在 app/config/config.yml
中添加的配置
#app/config/config.yml nelmio_api_doc: sandbox: authentication: name: access_token delivery: http type: basic custom_endpoint: false enabled: true endpoint: ~ accept_type: ~ body_format: formats: [] default_format: form request_format: formats: json: application/hal+json method: accept_header default_format: json entity_to_choice: false
质量
要运行 PHPUnit 测试,请转到测试目录并发出 phpunit。
此库试图遵守 PSR-1、PSR-2、PSR-4 和 PSR-7。
如果您发现合规性疏漏,请通过 Pull Request 发送补丁。
贡献
对包的贡献始终欢迎!
支持
通过以下方式之一与我联系
- 通过电子邮件contact@nilportugues.com联系我
- 打开问题
作者
许可
代码库遵循 MIT 协议。