LoginSignup
5
5

More than 5 years have passed since last update.

BEAR.Sundayで任意のPageリソースでJSON形式のレスポンスを返す

Last updated at Posted at 2014-09-15

BEAR.SundayではTwigがデフォルトのテンプレートエンジンとして採用されており、通常の画面表示ではPageリソースはTwigでHTML表現にレンダリングされます。しかし、Ajax等でJSON形式のレスポンスが欲しい場合には、PageリソースをJSON表現にレンダリングする必要があります。

最も簡単な実装

JSON形式のレスポンスが欲しいPageリソースクラスで、RendererにJsonRendererを指定します。

namespace My\Project\Resource\Page;

use BEAR\Package\Provide\ResourceView\JsonRenderer;
use BEAR\Resource\ResourceObject;

class Hello extends ResourceObject
{
    /**
     * @param string $name
     * @return $this
     */
    public function onGet($name)
    {
        $this['greeting'] = "hello " . $name;

        $this->setRenderer(new JsonRenderer($this));
        return $this;
    }
} 

これで

$.ajax({
    type: 'GET',
    url: '/hoge',
    data: { 'name': 'foobar' },
    dataType: 'json'
}).done(function(json) {
    console.log(json.greeting); // "hello foobar"
})...

のように動作します。

と、ここで、折角BEAR.Sundayなので、AOPで実装してみます。

AOPでの実装

構成

以下のコマンドでプロジェクトを作成した前提です。

$ composer create-project bear/skeleton My.Project
$ cd My.Project
$ composer install
$ tree My.Project/src
My.Project/src 
├── Annotation
│   └── ResponseJson.php ★追加
├── App.php
├── Interceptor
│   └── ResponseJson.php ★追加
├── Module
│   ├── App
│   │   ├── Aspect.php ★編集
│   │   └── Dependency.php
│   └── AppModule.php ★編集
└── Resource
    ├── App
    └── Page
        ├── Index.php
        ├── Index.twig
        └── Hello.php ★追加

Pageリソースクラス

src/Resource/Page/Hello.php

下記のようにPageリソースクラスのメソッドにResponseJsonアノテーションを指定することでJSON表現にレンダリングできることを目指します。

namespace My\Project\Resource\Page;

use BEAR\Resource\ResourceObject;
use My\Project\Annotation\ResponseJson;

class Hello extends ResourceObject
{
    /**
     * @ResponseJson
     *
     * @param string $name
     * @return $this
     */
    public function onGet($name)
    {
        $this['greeting'] = "hello " . $name;
        return $this;
    }
} 

Annotation

src/Annotation/ResponseJson.php

アノテーションを定義します。
アノテーションを指定する対象(@Target)はMETHODです。

namespace My\Project\Annotation;

use BEAR\Sunday\Annotation\AnnotationInterface;

/**
 * ResponseJsonアノテーション
 *
 * @Annotation
 * @Target("METHOD")
 */
final class ResponseJson implements AnnotationInterface
{
} 

Interceptor

src/Interceptor/ResponseJson.php

インターセプターを実装します。
ここでPageリソースのRendererにJsonRendererを指定します。

namespace My\Project\Interceptor;

use BEAR\Package\Provide\ResourceView\JsonRenderer;
use BEAR\Resource\ResourceObject;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\MethodInvocation;

/**
 * ResponseJsonインターセプター
 */
class ResponseJson implements MethodInterceptor
{
    /**
     * {@inheritdoc}
     */
    public function invoke(MethodInvocation $invocation)
    {
        /** @var ResourceObject $page */
        $page = $invocation->getThis();
        $page->setRenderer(new JsonRenderer($page));
        return $invocation->proceed();
    }
}

AOPの設定

src/Module/App/Aspect.php

ResourceObjectクラスのサブクラス(=Pageリソースクラス)の、ResponseJsonアノテーションが指定されたメソッドに対して、インターセプターをを束縛します。

namespace My\Project\Module\App;

use BEAR\Package;
use Ray\Di\AbstractModule;

class Aspect extends AbstractModule
{
    protected function configure()
    {
        $this->installResponseJson();
    }

    private function installResponseJson()
    {
        $this->bindInterceptor(
            $this->matcher->subclassesOf('BEAR\Resource\ResourceObject'),
            $this->matcher->annotatedWith('My\Project\Annotation\ResponseJson'),
            [$this->requestInjection('My\Project\Interceptor\ResponseJson')]
        );
    }
}

src/Module/AppModule.php

★印の箇所をコメントインし、上記のAOPの設定をアプリケーションに適用します。

※Aspect#installResponseJsonの処理をAppModule#configureに直接書いても同じように動作します。

namespace My\Project\Module;

use BEAR\Package\Module\Package\StandardPackageModule;
use Ray\Di\AbstractModule;
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;

class AppModule extends AbstractModule
{
        :
        : 

    protected function configure()
    {
        $this->install(new StandardPackageModule('My\Project', $this->context, dirname(dirname(__DIR__))));

        // override module
        // $this->install(new SmartyModule($this));

        // $this->install(new AuraViewModule($this));

        // install application dependency
        // $this->install(new App\Dependency);

        // install application aspect
        $this->install(new App\Aspect($this)); コメントイン
    }
}

これでResponseJsonアノテーションをPageリソースクラスのメソッドに付加するだけで、JSON形式のレスポンスを得ることが出来るようになしました。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5