2016年1月7日木曜日

2015年を振り返って2(Tuum/Respond開発日誌メモ)

2015年を振り返って、の続きです。

昨年の2015年6月から始めたのがTuum/Respondというプロジェクト。開発方針を転換して、PSR-7ベースのマイクロフレームワークに後付でViewの機能を追加するパッケージを目指しました。

面白かったのは、開発してゆくにつれ、どんどんコードが簡単になってゆきました。機能を絞ったことで、何をしているか理解できたからと思います。

いったい何をするのか。
自分で理解した形で説明します。
使い方とかは、Githubのページを見てください。

要するに次の2つを管理するパッケージです。

  • ViewData: ビューを作るのに必要な情報を運ぶデータ転送オブジェクト。これに必要な情報を設定してゆく。
  • ViewInterface: ViewDataからテンプレートなどでビューを構築して、レスポンスを返すインターフェース。

これだけなのですね。

ViewerInterface


Tuum/Respondの肝は、様々な方法でレスポンスオブジェクトを構築すること。

レスポンスを構築する、ということは、ビューを構築する、とほぼ同じです。ということで、次のインターフェースが出来ました。

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Tuum\Respond\Responder\ViewData;
interface PresenterInterface {
    /**
     * renders $view and returns a new $response.
     *
     * @param ServerRequestInterface $request
     * @param ResponseInterface      $response
     * @param ViewData               $view
     * @return ResponseInterface
     */
    public function render(
ServerRequestInterface $request,
ResponseInterface $response,
$view);
}

リクエストとレスポンスのオブジェクト、それとビュー構築に必要なデータの入ったViewDataというオブジェクトを受け取ります。適宜ボディを構築して、レスポンスオブジェクトを返します。

ついでに同じインターフェースで、ちょっと動きの違うAPIを定義しました。

interface ErrorViewInterface extends PresenterInterface {}
interface ViewerInterface extends PresenterInterface {}

この3つのインターフェースの使い分けは、


  • PresenterInterface:
    $viewを受け取って、レスポンスを返す汎用インターフェース。
  • ViewerInterface:
    テンプレートからビューを描画することで、レスポンスを返す。
  • ErrorViewInterface:
    ステータスコードに対応するテンプレートを描画することで、レスポンスを返す。エラー用。


それぞれのインターフェースを実装したクラスを作っておいて、呼び出します。次のコードを見ると、どれがどのAPIに対応するか、すぐわかると思います。

Response::view($req)->view('template/filename');
Response::error($req)->forbidden();
Response::present($req)->call(MyPresenter::class);


ViewData


もう一つの肝が、ViewDataというデータ転送オブジェクト(DTO)。Tuum/Respondとは、要するにViewDataを設定しつつ持ちまわるためのライブラリです。そして、最後にPresenterInterfaceのオブジェクトを呼び出します。

このコードだと、$viewを直接いじってからテンプレートを描画します。

Respond::view($req)
  ->withViewData(function($view) use($value) {
    return $view->setData('key', $value);
  })->view('my/template');

あるいはRedirectでは、ViewDataをSessionのフラッシュに保存します。

Respond::redirect($req)
  ->withMessage('hello')
  ->to('/my/path');

次のリクエストで、フラッシュからViewDataを読み込むことで、データを簡単に利用することが出来ます。


インターフェース遷移


想定しているマイクロフレームワークとTuum/Respondについて、インターフェースという切り口で考えて見たら面白かったので、書いてみます。

最初に、リクエストとレスポンスから**ミドルウェア**が始まります。`$next`が次のミドルウェアですね。

middleware($req, $res, closure $next);

ミドルウェアの最後にルーターが走り、実行する**コントローラー**を呼び出します。`$args`がルートパターンでの変数です。此処から先が、ユーザーコードに入ってゆく感じです。

controller($req, $res, array $args);

コントローラーでは、ドメインを操作したり、必要なビューを構築してレスポンスを返します。

ビューの構築を手助けするのが、`Tuum/Respond`で、次のようなインターフェースになります。

viewer($req, $res, ViewData $view);

$viewに情報を設定する、テンプレートを描画する、レスポンスを構築する、など様々な処理を行えます。

なんかMiddleware-View-Controller (MVC)みたい。

開発は楽しい


開発していると、動くところまで作るのは楽しいとよく言われます。

その後でも、リファクタリングしたり作りこむのも、理解が深まったり新しい見方が出てきたりして別の楽しさがあります。自分の趣味のパッケージでないと中々出来ないので、これからも続けてゆきたいです。