こちらで紹介したBEAR.Sundayですが、名前を指定すると挨拶を返してくれるアプリケーションを作成してみます。

http://ホスト名/Hello?name=nori

にアクセスすると、ブラウザに以下のように表示されるアプリケーションを作成してみます。

Hello nori!!

まずプロジェクトを作成します。そのためにはComposerというパッケージ管理ツールが必要です。インストールは以下で一発です。

# curl -sS https://getcomposer.org/installer | php

そしてBEAR.Sundayのプロジェクトのひな形を作成します。

# composer create-project bear/skeleton /var/tutorial

すると以下のような構成のディレクトリが出来上がります。

tutorial
    bootstrap
        api.php → App層で作成したスクリプトをコマンドラインで試すためのもの
        web.php → Page層で作成したスクリプトをコマンドラインで試すためのもの
    var
        log → ログが出力されるディレクトリ
        www
            index.php → すべてのHTTPリクエストが集約されるPHPスクリプト
    src
        Resource
            App → App層で作成したスクリプトを格納するディレクトリ
            Page → Page層で作成したスクリプトを格納するディレクトリ
        Module
            AppModule.php → Seasarでいうところのdiconファイル(後述)
    Vendor → 外部のライブラリが格納されるディレクトリ

まず、App層のファイルを作成します。/var/tutorial/src/Resource/AppのディレクトリにHello.phpというファイルを以下のように作成します。このプログラムについて、説明します。

<?php
namespace Vendor\Tutorial\Resource\App; // (1)

use BEAR\Resource\ResourceObject; // (2)

class Hello extends ResourceObject // (3)
{
    public function onGet($name) // (4)
    {
        $greeting = "Hello ".$name; // (5)
        $this['greeting'] = $greeting; // (6)

        return $this; // (7)
    }
}
?>

上記のソースコードの詳細は以下のとおりです。

namespace Vendor\Tutorial\Resource\App; // (1)

名前空間を指定します。Javaでいうところのpackageで、名前空間が違えば、同じクラス名を使っても問題ないです。実際クラス名はよくかぶります。

use BEAR\Resource\ResourceObject; // (2)

Javaでいうところのimportになります。事前に指定した名前空間のクラスを利用するときに使います。

class Hello extends ResourceObject // (3)

クラスの定義です。App層のクラスを作成する場合には、必ずResourceObjectというクラスを継承します。これは、このフレームワークの決まりです。先ほどの「use」で宣言したクラスは、このResourceObjectを宣言しています。Abstractなクラスなので、単体ではnewできないようです。そして、いろんなインターフェースを実装しているようです。このクラスを継承すると、HTTPリクエストの内容がこのクラスのインスタンス自身に設定されるようです。

    public function onGet($name) // (4)

onGetというメソッドを定義しています。publicはJavaと同じで、外部からこのメソッドが利用できるという意味です。そして、このonGetメソッドはPage層から呼び出されます。この辺りはPage層の話になるので、後述します。

そして、引数として、名前を定義しています。こちらもPage層から指定するのですが、これも後述します。

        $greeting = "Hello ".$name; // (5)

指定された名前に「Hello」という文字列を付与しています。

        $this['greeting'] = $greeting; // (6)

JSONのレスポンスの出力形式を定義してます。

        return $this; // (7)

最後にこのクラスのインスタンスをreturnします。フレームワーク側では、Page層からアクセスがあると、ResouceObjectを継承したクラスのインスタンスが返されることを期待しているようです。

では、上記のスクリプトの動作確認をしてみます。動作確認はbootstrapディレクトリにあるapi.phpで行います。以下のコマンドを発行して下さい、

# php /var/tutorial/bootstrap/api.php get '/Hello?name=nori'

以下のようなレスポンスが返ってきます。

200 OK
content-type: application/hal+json

{
    "gretting": "Hello nori!!",
    "_links": {
        "self": {
            "href": "/Hello?name=nori"
        }
    }
}

1つ目のフィールドのキーは、先ほどApp層のクラスHelloで定義した’$this[‘greeting’] = $greeting;’とマッチしています。上記のように記述すると、JSONのキーと値の形式で出力されます。これは、フレームワークが裏側でそのように処理してくれています。

次に、先ほどのApp層で作成したクラスを利用するPage層のクラスを作成します。

BEAR.SundayはHTMLやJSONに出力するためのテンプレートエンジンを自由に切り替えることができます。テンプレートエンジンとは、ServletでいえばJSPに相当する部分です。JSPはJSP独自の書き方でServletから受け取った値をHTMLに出力することができます。

Servletもそうですが、こういったものはJavaの世界でもJSPのほかにVelocityなどたくさんのテンプレートエンジンがあります。

JSPだとServletから受け取った変数の記述方法は<%= name %>と書きますが、Velocityでは${name}とかきます。そのほかにもいろいろと異なる部分があり、どちらも一長一短ありで、ケースバイケースで使い分けます。

そして、PHPの世界にもたくさんのテンプレートエンジンがあり、その一つはTwigで、一番メジャーですので、今回もTwigを使います。

そして、BEAR.Sundayはこのテンプレートエンジンの切り替えを簡単に行うことができます。StrutsなどはJSP固定ですが、BEAR.Sundayは、自分の好みに合わせて、商用やOSSの色々なテンプレートエンジンを利用できます。

テンプレートエンジンの切り替え方法については、Ray.DIなどの知識が必要となるため、詳細は後程説明します。なので、ここでは、Twigへの出力方法は機械的に覚えてしまって構いません。

では先ほどのApp層で作成したクラスを利用するPage層のクラスを作成します。Hello.phpというファイルを/var/tutorial/src/Resource/Pageに作成します。

<?php
namespace Vendor\Tutorial\Resource\Page;

use BEAR\Resource\ResourceObject;

class Hello extends ResourceObject // (1)
{
    public function onGet($name) // (2)
    {
        $this['name'] = $name; // (3)
        $this['greeting'] = $this->resource
            ->get // (4)
            ->uri('app://self/hello') // (5)
            ->withQuery(['name' => $name]) // (6)
            ->request();

        return $this; // (7)
    }
}

上記のソースコードの詳細は以下のとおりです。

class Hello extends ResourceObject // (1)

App層と同様にResouceObjectを継承します。

    public function onGet($name) // (2)

ブラウザからはgetメソッドで呼ばれる想定なので、onGetメソッドを作成します。そしてURLのクエリパラメータに指定される引数がname=noriの場合は、onGetのメソッドの引数名を$nameとします。これはフレームワークの決まりです。

        $this['name'] = $name; // (3)

ブラウザに出力したい値を$this[‘xxx’]の形式で記載します。このように書くとTwigのテンプレートエンジンから{name}といった書式でこの値を取得できます。

            ->get // (4)

App層で作成したメソッドを呼び出している処理です。getはApp層で作成したonGetメソッドを呼び出すという意味です。ここがpostと書いてあれば、onPostメソッドが呼び出されます。

            ->uri('app://self/hello') // (5)

App層で定義したHelloというクラスを呼び出しますよという意味です。前の記述合わせるとApp層のHelloというクラスのonGetメソッドを呼び出しますよという意味になります。

            ->withQuery(['name' => $name]) // (6)

onGetメソッドの引数nameに$nameを入れますよという意味になります。

        return $this; // (7)

このクラスのインスタンス自信をreturnします。これはこのフレームワークの決まりです

「/var/tutorial/var/www/index.php」の「app」を以下のように「html-app」に変更します。

<?php

$context = 'html-app';
require dirname(dirname(__DIR__)) . '/bootstrap/bootstrap.php';

この記述をすることによりTwigのテンプレートエンジンを使う準備ができました。正確にいうと、この記述をすることにより、HtmlModule.phpに記載した内容をもとに、TwigのRendereをBEAR.SundayのRenderInterfacleにBindするのですが、詳細は後述します。

次にいよいよテンプレートエンジンTwigModuleをインストールします。BEAR.Sundayはシンプルなフレームワークで、データベースへ接続するためのモジュールなどはほとんど入っていません。必要なものは適宜インストールする必要があります。

これはComposerでインストールします。

# cd /var/tutorial
# composer require madapaja/twig-module

/var/tutotial/vendor配下にmadapajaというディレクトリが作成されます。そこにTwig関連のモジュールが入っています。

次にModuleファイルを記述します。ここでは、とりあえず、おまじないだと思い以下のファイルを作成してください。(詳細はRay.DIに関する記事(を書く予定)で説明します。)

/var/tutorial/src/Module/HtmlModule.phpを以下の内容で作成してください。

<?php
namespace Vendor\Tutorial\Module;

use Ray\Di\AbstractModule;
use Madapaja\TwigModule\TwigModule;
use Madapaja\TwigModule\Annotation\TwigPaths;

class HtmlModule extends AbstractModule
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {

        $this->install(new TwigModule); // (1)
        $appDir = dirname(dirname(__DIR__)); // (1)
        $paths = [$appDir . '/var/twig']; // (1)
        $this->bind()->annotatedWith(TwigPaths::class)->toInstance($paths); // (1)
    }
}

上記のソースコードは、今の段階ではおまじないでよいのですが、一点だけ説明します。

        $this->install(new TwigModule); // (1)
        $appDir = dirname(dirname(__DIR__)); // (1)
        $paths = [$appDir . '/var/twig']; // (1)
        $this->bind()->annotatedWith(TwigPaths::class)->toInstance($paths); // (1)

ここで、テンプレートを配置する場所(Servletでいうところのjspの配置場所)をアプリケーションディレクトリ/var/twigとしています。つまり今回の場合は、/var/tutorial/ /var/twigとしています。

次にTwigのテンプレートを作成します。

/var/tutorial/var/twig/Hello.html.twigを以下の内容で作成してください。

<!DOCTYPE html>
<html>
<body>
Hello {{ name }}!!
</body>
</html>

先ほど/var/tutorial/src/Resource/Page/Hello.phpで記載した$this[‘name’] を、Twigのテンプレートファイルで{{name}}という形式で取り出すことができます。

これで準備ができました。ブラウザに以下のURLを入力すると・・・

http://ホスト名/Hello?name=nori

以下の内容が表示されます。

Hello nori!!

以上がリソース指向の説明でした。おまじない的な部分が多かったのですが、そこについては次回以降で説明します。