nilportugues/haljson-bundle

Symfony 2 和 Symfony 3 的 HAL+JSON API Transformer Bundle

1.3.2 2017-03-23 10:30 UTC

This package is not auto-updated.

Last update: 2024-09-20 21:32:26 UTC


README

适用于 Symfony 2 和 Symfony 3

Scrutinizer Code Quality SensioLabsInsight Latest Stable Version Total Downloads License Donate

安装

步骤 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-1PSR-2PSR-4PSR-7

如果您发现合规性疏漏,请通过 Pull Request 发送补丁。

贡献

对包的贡献始终欢迎!

支持

通过以下方式之一与我联系

作者

许可

代码库遵循 MIT 协议