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形式のレスポンスを得ることが出来るようになしました。