[RadarPHP]Action-Domain-Responder(ADR)パターンとRadarの紹介
こんにちは、ナカエです。
Radar.ADRがベータになったので、前から書こう書こうと思っていたとRadarの紹介を数回に分けてしていきたいと思います。
※今日の記事はRadarにたどり着くくらいで終わります。
最近のPHP製Webフレームワークと私
弊社も業務で利用していますが、世間ではLaravelが盛り上がっていて、日本語記事も増えたなと感じます。CakePHP3も2に比べグッと使いやすくなりました。大御所のSymfonyも3が出ました。Zend Frameworkも3系の詳しい情報が入ってきています。
PHP7の本番導入もそろそろ見えてくるかなという今日この頃。
新しいのが出たからフレームワークを今すぐ乗り換えるぞ、ということはまずありえません。しかし、今後の新しいフレームワークの登場や既存のフレームワークのメジャーアップデートに必要以上に惑わされないために、Webフレームワークとどう付き合っていくかを考えるのにちょうどいい時期だと感じました。
PHPフレームワーク界隈の新しい波の1つとしてPSR-7への対応があります。
HTTPメッセージのPHPにおける表現の標準が定まることで、PHPで構築するWebアプリケーションを「HTTPリクエストを入力としてHTTPレスポンスを出力する関数」として素朴に捉えることが容易になりました。フレームワークごとの差異に気をとられることが減り、自身が注力すべき問題領域に時間を割くことができるようになるはずです。
※フルスタックフレームワークに含まれるHTTPに関係ないライブラリの使い方についてはまた別の話ですが。
PSR-7対応を謳うWebフレームワークの中には、従来のWebフレームワークとは違う構造を持つものがあります。代表格はHTTPミドルウェアを処理の中心に据えたZend Expressiveであり、今回紹介するRadarもその1つです。
MVC2(以下単にMVCと呼称)と違う構造や理念を採用したフレームワークに1つ手をつけると、Webフレームワークの共通の関心や、逆に今使っているフレームワークの特徴も見えてくると思います。
Action-Domain-Responderパターン
Radarが採用するADRパターンは、pmjonesことPaul M. Jones氏が"MVC Refinement"として提唱したMVCの派生パターンの1つです。Paul M. Jones氏はPHPの高品質コンポーネント群「Aura for PHP」のリード開発者です。
ADRパターンの説明原文はこちら: pmjones/adr
MVCと比較すると、
- ModelとDomain
- ViewとResponder
- ControllerとAction
が対応しています。
ModelとDomainにはさほど違いはありません。
ControllerとActionについては、ControllerにまとめていたActionをクラスに小分けにすることで、ルートごとの処理を疎に、またAction自体に対するメタな処理を容易にしている、というのが実装上の違いであり感じやすいメリットです。
本質的な差があるのはViewとResponderで、それにControllerとActionの役目の違いが付随します。
View = テンプレートという風潮
よくあるMVCフレームワークでは、ControllerがTwo Step Viewの仕組みで(テンプレートを利用して)HTTPレスポンスのbodyを生成します。また HTTPヘッダの値もControllerの中で設定されます。Viewと聞くと、ああテンプレートのことね、という人も多いでしょう。
ADRパターンの説明ではbodyだけではなくHTTPレスポンスを組み立てることこそが、"View"の本来の責務であるプレゼンテーションロジックだと強調されています。Domainが出力したデータをHTTPの表現に変換するのがResponderの役目です。テンプレートによりbody部のHTMLを生成することは役目の一部にすぎません。Responderだけを入れ替えることで、同じDomainの出力を違う表現、たとえばJSONやHTMLとして出し分けることも可能になります。
この違いに対応して、Actionは入力をDomainに受け渡し、Domainの出力をResponderに渡す層となります。よくあるControllerのアクションメソッドとは異なり、Viewのbody部出力に利用するテンプレートには触れません。
- ModelとDomain
- ViewとResponder
- ControllerとAction
※adrのリポジトリのサンプルコードを引用
<?php
use Framework\Action;
class BlogCreateAction extends Action
{
public function __invoke()
{
// is this a POST request?
if ($this->request->isPost()) {
// yes, retain incoming data
$data = $this->request->getPost('blog');
// create a blog post instance
$blog = $this->blog_model->newInstance($data);
// is the new instance valid?
if ($blog->isValid()) {
$blog->save();
}
} else {
// not a POST request, use default values
$blog = $this->blog_model->getDefault();
}
// set data into the response
$this->responder->setData(array('blog' => $blog));
$this->responder->__invoke();
}
}
?>
<?php
use Framework\Responder;
class BlogCreateResponder extends Responder
{
// $this->response is the actual response object, or a response descriptor
// $this->view is a view or template system
public function __invoke()
{
// is there an ID on the blog instance?
if ($this->data->blog->id) {
// yes, which means it was saved already.
// redirect to editing.
$this->response->setRedirect('/blog/edit/{$blog->id}');
} else {
// no, which means it has not been saved yet.
// show the creation form with the current response data.
$this->response->setContent($this->view->render(
'create.html.php',
$this->data
));
}
}
}
?>
名前を変えただけで結局はMVCじゃないか、という意見もあるようです。 重要なのはADRパターンという名前ではなく、「実際にどのような責務分割が行われれば、本当に嬉しいだろうか?」ということを再考させてくれる点だと思います。
なお、adrのGitHubリポジトリにはEBI、DCI、MVP、MVVM、RMRなど他のパターンの説明や考察もあり、非常に興味深いです。
https://github.com/pmjones/adr
Radarの紹介の続きは次回
RadarはADRパターンのフレームワークの1つです。
要諦は「ドメインの入出力をHTTPの入出力に変換するラッパー」と言えましょう。
ADRパターンの実現のためにAura for PHPのコンポーネントを含むいくつかのパッケージの上に成り立ちます。
次回以降、Radarの概要と利用方法を掲載していきます。