Zend Framework 2.0 beta2でquick startしてみた。

beta2でskeletonアプリが出てきました。早速、skeletonのquick startを試してみました。
いずれは、コマンドで基本構造やモジュール・コントローラーを作成できるようになるだろうと思いますが、とりあえずskeletonだけでもありがたいです。

なるべく依存するものが少なくなるようにベタにやってみました。

仮想環境の作成

vmware playerで仮想マシンを作成、今回はCentOS5.7としました。
phpのインストール
yum install php53 php53-mbstring php53-mysql php53-pdo php53-gd php53-mcrypt php53-xml

apacheの調整

個人的にテストはUserDirでやることにしているので、UserDirを有効にしていつものrewriteを設定。
Zend Framework標準のものをUserDir対応にして設置しました。
http://framework.zend.com/manual/ja/project-structure.rewrite.html

Skeletonアプリのダウンロード

http://packages.zendframework.com/docs/latest/manual/en/zend.mvc.quick-start.html
こちらの指示に従って進めていきますが、とりあえずダウンロードし、自分のhome直下に解凍、4つのフォルダがありますが、public以下のファイルをpublic_htmlに移しました。(Apacheのデフォルトに合わせた)

ZF2のダウンロード

http://packages.zendframework.com/
こちらのページに従って入手してSkeletonアプリのvendor/ZendFramework以下にlibraryをコピー
結果、vendor/ZendFramework/library/Zend/EventManager てな感じになります。
さて、localhostにアクセスしてみます。


ちゃんちゃん、とりあえず出ました。簡単ですね。

quickstartしてみる

それでは、Zend\Mvcのquickstartの指示に従って試してみます。
http://packages.zendframework.com/docs/latest/manual/en/zend.mvc.quick-start.html
SkeletonにはApplicationというモジュールが含まれ、そこには基本的なviewのrenderとlayout用スクリプト、エラーページ用のビューがあるようです。
モジュール用のSkeletonも用意されています。
• Zip: https://github.com/zendframework/ZendSkeletonModule/zipball/master
• Tarball: https://github.com/zendframework/ZendSkeletonModule/tarball/master

これをダウンロードして指示に従ってrename等していきます。
まず、ダウンロードしたSkeletonモジュールを解凍して先ほど作ったSkeletonアプリのmodule直下に配置して、ディレクトリ名を好きなモジュール名に変更します。
モジュール名の注意としては、設定ファイル上では、CamelCaseをlowercased,dash-separatedにします。FoodFighterならfood-fighterになります。
autoload_classmap.phpをreturn array();にしろと書いてありますがこれは影響しません。
config/module.config.php
については、

<?php
return array(
    'routes' => array(
    ),
    'di' => array(
        'instance' => array(
            'alias' => array(
            ),
            'Zend\View\TemplatePathStack' => array('parameters' => array(
                'paths'  => array(
                    '<module-name>' => __DIR__ . '/../views',
                ),
            )),
        ),
    ),
);

このようにします。部分を先ほど変更したモジュール名に変えます。viewスクリプト(テンプレート)の配置場所を変えたい場合は、ここで設定しますが、通常はこのままで。
設定ファイルとして、私はIniファイルが好きなのですが、ここではPHPファイルを使っています。
この部分は、Module.phpのgetConfigメソッドを好きに書けば変更できます。
配列のdi部分がDIによるインスタンス管理用の設定ですね。ここで設定した名前でどこからでもインスタンスを呼ぶ事ができるようです。
このaliasを見てうれしくなりました。ソフトウエアの品質を向上していくと、コントローラーに具象コードをガツガツ書く開発は終了して、コントローラー機能も抽象化されていく流れだと思うのですが、このaliasはまさにそれです。同じコントローラークラスに対して、パラメーターの与え方のみで別のコントローラーとして振舞わせることができます。

特定のモデル名が現れないので、同じ挙動のコントローラは、モデルが違ってもコードがまったく同じ実装になりますね。わりとこんなふうに、モデルのクラス名すらも隠蔽してMとVCの間の密結合を避けるようにしてる箇所が多く現れます。

http://d.hatena.ne.jp/tanakahisateru/20120105/1325759589

こちらのYiiに関する記事にあるように、コントローラーのクラスそのものは、どのような挙動をするかという性質だけを実装してあればよく、対応するモデル名やパラメーターの与え方については、DI側から制御してやればよいわけです。それには、aliasを張りたいわけですね。はい。是非に。( 私はこれまで、dispatcherを自作してaliasしていたんですよ>< )
たとえば、ZF2側に用意されているRestfulControllerは典型的です。RESTによるリクエストの裁き方は十分に設計されているので、RESTリクエストを受け付けるコントローラーを継承で量産する必要はなく、それぞれのリソース毎にaliasを張るだけでよいわけです。
コントローラーにモデル名直書きとか画面毎に1コントローラーなんてやめようって現場で言っても、もう大丈夫。

さて、話が横道にそれてしまいましたが、元に戻します。

新しいコントローラーを作る

Moduleの基本構造としては、モジュール内のsrc以下がautoloadの対象になりますので、src//Controller以下にコントローラークラスファイルを配置します。
ここでは、HelloController.phpとします。

<?php
namespace <module name>\Controller;

use Zend\Mvc\Controller\ActionController;

class HelloController extends ActionController
{
    public function worldAction()
    {
        $message = $this->getRequest()->query()->get('message', 'foo');
        return array('message' => $message);
    }
}

ViewScriptを書きます。

ViewScriptの配置は、先ほど指定した場所以下に、コントローラー名をlowercase,dash-separatedに直してディレクトリを作成します。
quick-startドキュメントでは、モジュール名-helloにしろとか書いてありますが、要するにaliasとして呼びだすコントローラー名のことなので、そこはこだわらなくてもいいです。
とにかく、コントローラーのalias名を基準にやるとよいです。
そのディレクトリにworld.phtmlを作成します。worldはアクション名で、標準のActionControllerを継承している場合には、worldActionに対応します。

<h1>Greetings!</h1>

<p>You said "$foo".</p>

このように書かれていますが、これはさすがに動きません。Controllerでreturnする配列の添字がmessageですし、デフォルトのrendererはPHPで書きますので、正しくは、

<h1>Greetings!</h1>

<p>You said <?php echo $message;?></p>

となります。echoの後の部分、スクリプト上ではエスケープしてませんが、View側でエスケープしてくれます。
そういえば、ZF1だと、$this->messageじゃなかったっけ?ですが、ここでは、$messageでよいみたいです。

routeを作成する。

多分、デフォルトのルートでもルーティングできると思いますが、ここでは、コントローラーにaliasを使うサンプルも兼ねているようなので、routeを書きます。
ここで、defaultsはルーティングされた際のデフォルトの変数値を指定しますので、controllerのところは、↑で使ったalias名を指定します。
先ほどの、configs/module.config.phpに追記します。

    'routes' => array(
        '<module name>-hello-world' => array(
            'type'    => 'Zend\Mvc\Router\Http\Literal',
            'options' => array(
                'route' => '/hello/world',
                'defaults' => array(
                    'controller' => '<module name>-hello',
                    'action'     => 'world',
                ),
            ),
        ),
    ),

ドキュメントをコピペすると、Zend\Mvc\Router\Http\Literalを囲う文字がバッククォートになっているので要注意です。バッククォートでもエラーにならない場合もあるんでしょうか。私は、ちょっとハマったのですが、おかげでエラー処理のフローもチェックできるので、そのままお試しするのも悪くないですね。
また、コントローラー名が'-hello'となっていますが、この部分はDIで指定するエイリアス名を指定します。

DIでエイリアスを張ります。

大事なことなのでもっかい書いときます。↓で'-hello'となっている部分はエイリアス名にしてください。

<?php
return array(
    // ... routes configuration ...
    'di' => array(
        'instance' => array(
            'alias' => array(
                '<module name>-hello' => '<module namespace>\Controller\HelloController',
            ),
            'Zend\View\TemplatePathStack' => array('parameters' => array(
                'paths'  => array(
                    '<module-name>' => __DIR__ . '/../views',
                ),
            )),
        ),
    ),
);

いいですね。

アプリケーションにモジュールの存在を教えます。

config/application.config.php

<?php
return array(
    'modules' => array(
        'Application',
        '<module namespace>',
    ),
    'module_listener_options' => array( 
        'module_paths' => array(
            './module',
            './vendor',
        ),
    ),
);

はい。これで一応おしまいなので、hello/worldおよびhello/world?message=barへアクセスします。

意図した通りに表示されていればquickstartは完成です。
ほっ。

このSkeltonにしろquickstartにしろ、Zend\Mvcを理解するために作られているものと思いますので、ツールが整備されればもっと楽にできるだろうと思います。

これで、"Zend Framework 日めくり Calendar 2012" http://atnd.org/events/23579 6日目、
Zend Framework2 beta2 を触ってみる。 (featuring EventManager) とさせていただきます。

急遽5日目を代わっていただいた@sasezakiさんありがとうございました。

最後に一言。Zend\Mailが新しくなるようですが、日本語が通るか誰か試してたら教えてください!!

※注)この記事は正式リリースではないbeta版に関するものです。正式版では仕様が変わっているかもしれないのでご注意ください。