こんにちは、はじめまして、初投稿です!


最近*入社したまっちーと申します。(*2012年8月

ワタクシ、今年の1月からプログラマーに転向しまして、ひよっこプログラマー(アラサー)としてお仕事&お勉強しております。


zou.png


言語はHTML → CSS → PHPを触って、次にPHPのフレームワークとしてZend Frameworkを触り始めました。
手始めに公式サイトのチュートリアルを.........と思ったのですが、こいつのハードルが高い、ベリーハイでした。


なぜなら...


日本語のドキュメントがぬぁぁぁい!!


のです。


Translations

・Chinese version
・Italian version
・Polish version
・Portuguese version
・Czech version
・French version
・Spanish version


...ナンドミテモ、ニホンゴガ、ナイデハナイカ


純正ジャパニーズなワタクシにとってこれはいただけない状況です。見逃しがたい!

しょっぱなから前置きが長めですが、英語の復習がてらZend Frameworkのチュートリアルを日本語に翻訳してみました!

 誤訳などあればご指摘いただければ幸いです!!



Zend Framework入門

著者:Rob Allen http://akrabat.com/

バージョン 1.7.7

Copyright © 2006, 2011



このチュートリアルでは、Model - View - Controller の考え方に従った簡単なデータベース連動型アプリケーションを作成することで、Zend Frameworkの使い方を学習したいと思います。


注:このチュートリアルは Zend Framework1.10.1から1.11.4のバージョンで動作確認しています。1.x系のバージョンであれば動作するとを見込んでいますが、1.10.1以前のバージョンでは動作しない可能性もあります。


必要条件

Zend Frameworkを動作させるには、次の要件が必要です。

  • PHP5.2.4(またはそれ以降のバージョン)
  • Webサーバーが modrewriteをサポートしている、または同等の機能を有していること

チュートリアルの前提

Apache Webサーバ上で5.2.4以降のPHPが実行されてることを前提としています。Apacheでは、拡張機能のmodrewriteをインストールして、有効にする必要があります。


また、 Apacheが .htaccessファイルをサポートするように設定されているか確認してください。この設定は、通常httpd.confファイルを下記のように書き換えることにより設定できます。


AllowOverride None

     ↓

AllowOverride All


詳細については配布されているドキュメントで確認してください。modrewriteと.htaccessを正しく設定しなかった場合、このチュートリアルのホームページにしか移動できません。


フレームワークの取得

Zend Frameworkはzipまたはtar.gz形式でhttp://framework.zend.com/download/latestからダウンロードできます。リンク先のページ下部を確認してみてください。 "Minimal"バージョンをダウンロードしてください。


ZendToolの設定

Zend Frameworkには、コマンドラインツールが付属しています。まずはその設定から始めましょう。


Windows用のZendTool

  • Program FilesZendFrameworkCliという新しいディレクトリを作成します。
  • ダウンロードした ZendFramework - 1.11.10 - minimal.zipをダブルクリックで解凍します。
  • ZendFramework - 1.11.10 - minimal.zipフォルダ内のbinlibraryフォルダを、C:\Program Files\ZendFrameworkCli フォルダにコピーします。このフォルダはbinlibraryという2つのサブフォルダを有することになります。
  • 環境変数のPathにbinディレクトリを追加します。
    • [コントロールパネル]の[システム]セクションに移動します。
    • [詳細設定]を選択し、[環境変数]ボタンを押してください。
    • 「システム環境変数」リストで、Path変数をダブルクリックします。
    • 入力欄の最後に「;C:\Program Files\ZendFrameworkCli\bin」を追加して、OKを押します。(最初のセミコロン;は重要です!)
    • コンピュータを再起動します。

Mac用のZendTool(Linuxも似た処理です)

  • アーカイブファイルをダウンロードして、ダウンロードディレクトリのZendFramework-1.11.10-minimal.zipをダブルクリックします。
  • ターミナルを開き、

  sudo cp -r ~/Downloads/ZendFramework-1.11.10-minimal /usr/local/ZendFrameworkCli

  と入力し、/usr/local/ZendFrameworkCliにコピーします。

  • bashのプロファイルを編集し、エイリアスを作成します。
    • ターミナルに open ~/.bashprofile と入力します
    • 開いたファイルの最後に alias zf=/usr/local/ZendFrameworkCli/bin/zf.sh を追記します。
    • 保存し、テキストエディタを閉じます。
    • ターミナルを終了します。

ZendToolのテスト

ターミナルまたはコマンドプロンプトで下記のコマンドを実行することで、ZendToolコマンドラインインターフェイスの動作確認ができます。

zf show version

すべてが正常に動作した場合、次のように表示されます。

Zend Framework Version: 1.11.10

表示されない場合は、パスを正しく設定し、 binディレクトリがZendFrameworkCliディレクトリにあるか確認してください。

一度zf toolが作動した状態でzf --helpコマンドを実行すると、使用可能なコマンドがすべて表示されます。


注:PHPがZend Frameworkを同梱している場合、ZF 1.9を使用していないか確認してください。このチュートリアルが上手く動作しないおそれがあります。執筆時点ではxamppがこれに該当します。


アプリケーションの解説

Zend Frameworkアプリケーションを構築するための準備が整ったので、次にこれから作成するアプリケーションについて少し見てみましょう。今回は、CDアルバムのコレクションを表示する簡単な在庫管理システムを作成したいと思います。メインページではCDアルバムコレクションの一覧を表示し、CDアルバムの追加、編集、削除ができます。ほかのソフトウェアエンジニアリングと同様、実行する前に少し事前に計画を立ててみましょう。このウェブサイトには以下の4つのページが必要です。


Home pageアルバムの一覧を表示し、それらを編集および削除するためのリンクを設置します。また、新しいアルバムを追加するためのリンクを設置します。
Add New Album新しいアルバムを追加するためのフォームを設置します
Edit Albumアルバムを編集するためのフォームを設置します
Delete Albumアルバムの削除の確認を行い、その後削除を実行します

また、データベースに情報を保存する必要があります。以下のフィールドを持つテーブルが必要になります。


フィールド名データ型Null許可その他
idintegerNoPrimary key, auto increment
artistvarchar(100)No
titlevarchar(100)No

アプリケーションを構築する

それでは、アプリケーションの構築を始めてみましょう。時間と労力を節約するために、できるだけzfコマンドラインツールを利用していきます。最初の作業は、プロジェクトのスケルトンファイルとディレクトリを作成することです。


ターミナルかコマンドプロンプトを開き、cdコマンドをタイプして、Webサーバーのドキュメントルートに移動します。このディレクトリにファイルを作成する権限があることとWebサーバーに読み取り権限があることを確認し、以下のコマンドを実行してください。


zf create project zf-tutorial

ZFツールは、zf-tutorialディレクトリを作成して、フレームワークが推奨するディレクトリ構造を作成します。このディレクトリ構造に従うと、Web上に公開する必要のあるファイルのみドキュメントルートに設置できます。ただしこの構造はApacheの設定を制御できることが前提です。コマンドを実行すると次のようなファイルとディレクトリ構造が作成されます。



(publicディレクトリ内には隠しファイルの.htaccessも含まれています)


applicationディレクトリにはWebアプリケーションのソースコードが格納されています。ご覧のように、アプリケーションのモデル、ビュー、コントローラ用にそれぞれのディレクトリがあります。publicディレクトリはWebサイトの一般公開用ルートディレクトリで、これはアプリケーションにアクセスするためのURLがhttp://localhost/zf-tutorial/public/であることを意味しています。Apacheの機能などによりほとんどのアプリケーションファイルには直接アクセスできないので、よりセキュアな構造となっています。


注:

ウェブサイトを一般公開する際は、ウェブサイト用の仮想ホストを作成し、publicディレクトリを直接ドキュメントルートに設定してください。たとえば下記のようなzf-tutorial.localhostという仮想ホストを作成することができます。


<VirtualHost *:80>
    ServerName zf-tutorial.localhost
    DocumentRoot /var/www/html/zf-tutorial/public
    <Directory "/var/www/html/zf-tutorial/public">
        AllowOverride All
    </Directory>
</VirtualHost>

このサイトはhttp://zf-tutorial.localhost/というURLでアクセスすることになります。(zf-tutorial.localhostというホスト名が127.0.0.1を指すようにするために、/etc/hostsかc\windows\system32\drivers\etc\hostsファイルが設定されているか確認して下さい。)テスト用のサブディレクトリに直接アクセスする方が簡単ですので、今回のチュートリアルではこの設定はしません。


画像、JavaScript、CSSファイルは、publicディレクトリ配下の別のディレクトリに格納されています。ダウンロードしたZend Frameworkのファイルはlibraryディレクトリに置かれます。他のライブラリを使用する必要がある場合、このディレクトリに配置します。


ダウンロードしたアーカイブファイル(ZendFramework-1.11.10-minimal.zip) 内のlibrary/Zendディレクトリを、zf-tutorial/libraryディレクトリにコピーします。これにより、zf-tutorial/libraryディレクトリはZendというサブディレクトリを含むことになります。


すべてが正常に動作しているかどうかはhttp://localhost/zf-tutorial/publicにアクセスすることで確認できます。下記のような画面が表示されるはずです。



ブートストラップの背景

Zend Frameworkのコントローラはフロントコントローラというデザインパターンを採用しているため、すべてのリクエストは共通のindex.phpファイルを経由します。共通のindex.phpファイルを経由することで、必ずアプリケーションの初期化処理が実行される仕組みになっています(この共通の初期化処理はブートストラップとして知られています)。フロントコントローラの仕組みは、ZendToolが生成したzf-tutorial/publicディレクトリ内の.htaccessで実現しています。.htaccessファイルはすべてのリクエストをpublic/index.phpにリダイレクトさせます。.htaccessもまたZendtoolによって作成されています。


index.phpファイルはアプリケーションのエントリーポイントです。このファイルはZendApplicationクラスのインスタンスを生成し、アプリケーションを初期化し、実行をします。このファイルでは、2つの定数(APPLICATIONPATHAPPLICATIONENV)を定義しています。APPLICATIONPATHapplicationディレクトリへのパス、APPLICATIONENVはアプリケーションの使用環境あるいはモードを定義します。デフォルトではindex.php内でproductionと設定されていますが、.htaccessファイルで変更することも可能です。.htaccessファイルに以下の行を追加してdevelopmentに設定しましょう。:


SetEnv APPLICATIONENV development

ZendApplicationクラスは、アプリケーションを起動するために使用され、さらに application/configs/application.iniの環境設定ファイルに定義されている値が使用されるように設定されます。このapplication/configs/application.iniファイルもまた自動生成されます。

ZendApplicationBootstrapBootstrapを継承したBootstrapクラスはapplication/Bootstrap.php内で提供されています。Bootstrapクラスではリクエストされた時のアプリケーション起動時の初期化処理を実行する場合に使用されます。


application/configsディレクトリに格納されているapplication.iniは、ZendConfigIniクラスを使用して読み込まれます。ZendConfigIniではコロン区切りでセクションを継承することができます。例えば、


[staging : production]

という記述はstagingセクションがproducitonセクションのすべての設定を継承することを意味しています。読み込んだセクションのうち、APPLICATIONENV定数で定義されているセクションの値が使用されることになります。開発中はdevelopmentセクションが最適で、本番公開されているときは、productionセクションを使用を推奨します。すべてセクションに変更を適用させたいときは、application.iniファイルのproductionセクションに変更を記載します。


application.iniファイルの編集

まず最初に、PHPの日付と時刻の関数が使用するタイムゾーン情報を追加をしなければなりません。application/configs/application.iniを開き、


phpSettings.date.timezone = "Asia/Tokyo"

[production]セクションの他のPHP設定値の後ろに追記します。もちろん、各自のタイムゾーンを使用する必要があります。これでアプリケーションに独自のコードを追加する準備が整いました。


アプリケーション独自のコード

独自のコードを記述するファイルを作成する前に、Zend Frameworkがどのような構成のWebページを作成するのか理解しましょう。これは重要なことです。それぞれのページのアプリケーションはアクションといい、アクションはコントローラに含まれています。例えばhttp://localhost/zf-tutorial/public/news/viewのURLでは、Newsがコントローラ、viewがアクションを指します。これは関連するアクションのグループ化が可能なことを意味しています。例えば、Newコントローラには、list, archived, viewといった複数のアクションが含まれます。Zend FrameworkのMVCシステムはコントローラをグループ化するためのモジュールという機能もサポートしていますが、このチュートリアルのアプリケーションでは特に気にする必要はありません。


Zend Frameworkのコントローラには、デフォルトでindexと呼ばれる特別なアクションが設定されています。http://localhost/zf-tutorial/public/news/のようなケースでは、Newsコントローラ内のindexアクションが実行されます。コントローラにもindexと呼ばれるデフォルトのコントローラ名があり、http://localhost/zf-tutorial/public/の場合は、indexコントローラ内のindexアクションが実行されることになります。


今回のチュートリアルは簡単なもので、ログインのような「複雑」な処理は行いません。それについてはほかのチュートリアルに譲ります(または、Zend Framework in Actionを参照してみてください!)


アルバムに関するページは全部で4ページありますので、4つのアクションを単一のコントローラでグループ化します。デフォルトコントローラを使用し、4つのアクションは下記のようになります。


ページコントローラアクション
Home pageIndexindex
Add new albumIndexadd
Edit albumIndexedit
Delete albumIndexdelete

サイトがより複雑になるにつれ、コントローラをたくさん作成することもありますが、その場合は必要に応じてモジュール機能でコントローラをグループ化することも可能です。


コントローラの作成

ここまでの作業で、コントローラを作成する準備が整いました。Zend Frameworkではコントローラは1つのクラスになっており、{Controller name}Controllerと命名する必要があります。{Controller name}は大文字で始める必要があるので注意してください。このクラスはapplication/controllersディレクトリの{Controller name}Controller.phpというファイルに記載されている必要があります。また、各アクションは{action name}Actionと命名する必要があり、コントローラクラス内のpublicメソッドで宣言します。この場合、{action name}の名前は小文字で始まり、すべて小文字で記述する必要があります。大文字小文字混在のコントローラとアクション名も使用可能ですが、特別なルールをあるため、使用する場合は事前にドキュメントを確認し、ルールを理解するようにしてください。


IndexControllerというコントローラクラスはapplication/controllers/IndexController.phpで定義され、ZendToolによって自動的に作成されています。また、最初のアクションメソッド、indexAction()も含まれています。これ以外のアクションについては、独自に追加していく必要があります。


コントローラにアクションを追加するには、zfコマンドラインツールのcreate actionコマンドを使用します。ターミナルかコマンドプロンプトを開いて、zf-tutorialディレクトリに移動します。そして以下の3つのコマンドを実行します。


zf create action add Index
zf create action edit Index
zf create action delete Index

これらのコマンドは3つの新しいメソッド:addAction, editAction, deleteActionIndexController内に追加し、関連したViewスクリプトファイルも生成します。Viewスクリプトファイルは後々必要となります。これで使用する4つすべてのアクションが準備できました。


各アクションのURLは以下のとおりです。


URLアクションのメソッド名
http://localhost/zf-tutorial/public/IndexController::indexAction()
http://localhost/zf-tutorial/public/index/addIndexController::addAction()
http://localhost/zf-tutorial/public/index/editIndexController::editAction()
http://localhost/zf-tutorial/public/index/deleteIndexController::deleteAction()

新しく生成した3つのアクションの動作確認が可能です。アクセスすると次のようなメッセージが表示されます。


View script for controller index and script/action name add


注:404エラーが出る場合は、Apacheのmodrewriteモジュールを設定していないか、あるいはApacheに正しくAllowOverrideを設定できていないため、publicフォルダの.htaccessファイルの設定が反映されていない可能性があります。


データベース

これでコントローラのアクションとViewファイルで構成されたスケルトンアプリケーションの準備ができました。次にアプリケーションのモデルを見てみましょう。モデルはアプリケーションのコアとなる処理を行う機能(いわゆる「ビジネスルール」)を担う機能であることを覚えておいてください。今回の場合ではデータベース関連の処理を扱います。データベースからテーブルの検索、追加、更新、および行を削除するため、Zend Frameworkの'''ZendDbTable'クラス''を利用します。


データベースの設定

ZendDbTableを使用するためには、使用するデータベース名と接続ユーザ名とパスワードを設定する必要があります。簡単に設定するためには、configs/application.ini設定ファイルを使用します。ZendApplicationコンポーネントには、データベース設定に関するリソースが同梱されているため、私たちがやらなければならないことは、configs/application.iniファイルに適切な情報を設定することだけです。あとはZendApplicationコンポーネントが自動的に処理してくれます。


application/configs/application.iniファイルを開き、[production]セクションの最後の行に(つまり[staging]セクションの上に)以下の内容を追記します。


resources.db.adapter = PDOMYSQL
resources.db.params.host = localhost
resources.db.params.username = rob
resources.db.params.password = 123456
resources.db.params.dbname = zf-tutorial

上記はサンプルですので、自身のユーザー名、パスワード、データベース名を指定する必要があります!この設定を行うとことでデータベースに自動的に接続されるようになり、ZendDbTableのデフォルトアダプタに設定されます。他の利用可能なリソースプラグインについては下記のサイトで確認できるので参考にしてみてください。:http://framework.zend.com/manual/en/zend.application.available-resources.html


データベーステーブルの作成

今回のチュートリアルでどういったアプリケーションを作成するかを序盤で述べたように、アルバムのデータの保存にデータベースを使用します。私はMySQLを使用しますので、テーブルを作成するSQL文は次のようになります。


CREATE TABLE albums (
    id int(11) NOT NULL autoincrement,
    artist varchar(100) NOT NULL,
    title varchar(100) NOT NULL,
    PRIMARY KEY (id)
);

phpMyAdminのようなMySQLクライアントか標準のMySQLコマンドラインのクライアントでこの命令を実行します。


テストデータの入力

ホームにある検索機能からデータを確認できるように、テーブルにいくつか行を挿入します。私は英国Amazonで上からいくつかの「ベストセラー」のCDを取得してきました。MySQLクライアントで次の命令を実行します。

MySQLクライアント:


INSERT INTO albums (artist, title)
VALUES
('Paolo Nutine', 'Sunny Side Up'),
('Florence + The Machine', 'Lungs'),
('Massive Attack', 'Heligoland'),
('Andre Rieu', 'Forever Vienna'),
('Sade', 'Soldier of Love');

これでデータベースにいくつかデータが保存されたので、簡単なモデルを記述することができます。


モデル

Zend Frameworkでは、ビジネスロジックを担当するクラスとしてZendModelといったようなクラスは用意されていないため、ビジネスロジックをどう実装するかは制作者に任されていますが、ビジネスロジックを実装するための手段として利用できる多くのコンポーネントが用意されています。一つの方法として、アプリケーション内のそれぞれのエンティティを表すモデルクラスを作成し、データベースとエンティティのやりとりをするマッパーオブジェクトを使用する方法があります。このアプローチは、Zend Frameworkクイックスタートにも記載されています:http://framework.zend.com/manual/en/learning.quickstart.create-model.html


このチュートリアルでは、ZendDbTableクラスを継承したモデルを作成し、ZendDbTableRowクラスも使用します。Zend FrameworkはZendDbTableクラスを提供しています。これはデータベースのテーブルとデータのやりとりを可能にするテーブルデータゲートウェイというデザインパターンを実装しています。テーブルデータゲートウェイパターンは、大規模システムでは限界があるので注意しなければなりません。またZendDbTableによってデータベースへアクセスするメソッドが提供されているのですが、コントローラアクション内にもデータベースへのアクセスコードを記載する危険性もあります。


ZendDbTableAbstractは抽象クラスで、そこからアルバムを管理する独自のクラスを派生させます。このクラス名をどう命名するかは自由ですが、データベーステーブルと同じ名前にすることを推奨します。ZendFrameworkのZendApplicationではオートローダーが用意されていて、モジュール配下のリソースクラスを指定のディレクトリと紐付け、自動的にクラスをロードします。メインのapplication/フォルダの場合、接頭語としてApplicationを使用します。


オートローダーは次のような関連付けで、リソースを該当のディレクトリと紐付けます。


接頭辞ディレクトリ
Formforms
Modelmodels
ModelDbTablemodels/DbTable
ModelMappermodels/mappers
Pluginplugins
Serviceservices
ViewFilterviews/filters
ViewHelperviews/helpers

例えば、データベーステーブルが「album」というテーブル名で、かつZendDbTableを使用する場合、クラス名はApplicationModelDbTableAlbumsとなり、applications/models/DbTable/ Albums.phpというファイルで格納することになります。


使用するテーブル名のZendDbTableを呼び出したら、protectedプロパティの$ nameにそのテーブル名を設定する必要があります。また、ZendDbTableはオートインクリメントのidと呼ばれる主キーをもっていることを前提としています。この主キー用のフィールドの名前は必要に応じて変更することができます。


また、モデルを作成するための作業にzfコマンドラインツールを使用することができます。下記のコマンドをコマンドラインから実行しましょう。


zf create db-table Albums albums

このコマンドでは、application/models/DbTableフォルダにファイルAlbums.phpを作成することができます。

このファイル内にはApplicationModelDbTableAlbumsと呼ばれるクラスがあり、クラス内にアクセスするデータベーステーブル名が設定されています。


このモデルクラスにいくつかの機能を追加する必要がありますので、application/models/DbTable/Albums.phpを編集し、getAlbum(), addAlbum(), updateAlbum() deleteAlbum()メソッドを追記します。下記のようになります。


zf-tutorial/application/models/DbTable/Albums.php

<?php

class Application_Model_DbTable_Albums extends Zend_Db_Table_Abstract
{
    protected $_name = 'albums';

    public function getAlbum($id)
    {
        $id = (int)$id;
        $row = $this->fetchRow('id = ' . $id);
        if (!$row) {
            throw new Exception("Could not find row $id");
        }
        return $row->toArray();
    }

    public function addAlbum($artist, $title)
    {
        $data = array(
            'artist' => $artist,
            'title' => $title,
        );
        $this->insert($data);
    }

    public function updateAlbum($id, $artist, $title)
    {
        $data = array(
            'artist' => $artist,
            'title' => $title,
        );
        $this->update($data, 'id = '. (int)$id);
    }

    public function deleteAlbum($id)
    {
        $this->delete('id =' . (int)$id);
    }
}

アプリケーションがデータベーステーブルとやりとりをする4つのメソッドを作成しました。getAlbum()は配列形式で単一のレコードを取得し、addAlbum()はデータベースに新しいレコードを追加し、updateAlbum()はアルバムのレコードを更新し、deleteAlbum()はレコードを完全に削除します。これらのメソッドのそれぞれのコードは一目瞭然です。なお、ZendDbTableを使用して関連するテーブルのデータを取得することもできますが、このチュートリアルでは行いません。

コントローラはモデルを通じてデータを取得した後に、画面への表示を行うためにビュースクリプトを取得する必要があります。しかし、その前にZend Frameworkのビューシステムがどのように機能するかを理解する必要があります。


レイアウトとビュー

Zend Frameworkのビューコンポーネントは、(いくぶん予想通りかもしれませんg)ZendViewといいます。ビューコンポーネントにより、コントローラのアクションのコードとページを表示するためのコードを分離できます。


ZendViewの基本的な使い方は、次のとおりです。


$view = new ZendView();
$view->setScriptPath('/path/to/scripts');
echo $view->render('script.php');

それぞれのアクションにこのコードを直接を記載した場合、アクション内のロジックとはあまり関係のない非常に退屈な「重層的な」コードの繰り返しになることは、想像に固くありません。別の箇所でビューの初期化を行ってから、各アクション内でその初期化したビューオブジェクトを呼び出す方が好ましいです。Zend FrameworkではViewRendererと呼ばれるアクションヘルパーを提供しています。このアクションヘルパーは、コントローラ内でビューオブジェクトの初期化を行い(コントローラの $this->view にオブジェクトをセットし)、アクションの処理が実行された後、ビュースクリプトをレンダリングします。

ビューのレンダリングをするにあたり、ViewRendererZendViewオブジェクトの設定をします。このオブジェクトはviews/scripts/{controller name} ディレクトリでレンダリングするビュースクリプトを確認し、(少なくともデフォルトでは)アクション名と同じファイル名の拡張子.phtmlのビュースクリプトをレンダリングします。つまり、レンダリングされたビュースクリプトはviews/scripts/{controller name}/{actionname}.phtmlファイルとなり、レンダリングされたコンテンツはレスポンスオブジェクトのボティに追加されます。レスポンスオブジェクトはすべてのHTTPヘッダやHTTPボティコンテンツ、および、MVCシステムが生成した例外を収集します。フロントコントローラは、ディスパッチの終了時にボディコンテンツを含むヘッダーを自動的にクライアントへ送信します。


これらの設定はすべて、Zendtoolを使用してプロジェクトの作成やコントローラとアクションの追加などを行った時に設定されます。コントローラとアクションの追加で使用したコマンドはzf create controllerコマンドとzf create actionコマンドです。


共通のHTMLコード:レイアウト

ビューにたくさんの共通のHTMLコードができることは明白かもしれません。少なくともヘッダーとフッターセクション、ほかにもサイドバーが2つほどできるかもしれません。これは非常に一般的な問題であり、ZendLayoutコンポーネントはこの問題を解決するように設計されています。ZendLayoutにより、すべての共通ヘッダー、フッター、その他の共通化したいのコードをレイアウトビュースクリプトに移動させることができます。レイアウトビュースクリプトにはコンテンツ本体を参照するためのビューコードが含まれています。


レイアウトはデフォルトでapplication/layouts/に保存され、そしてZendApplicationにはZendLayoutの設定を行う仕組みがあります。Zendtoolを使ってlayoutビュースクリプトを生成し、application.iniを変更してみましょう。ここでもターミナルまたはコマンドプロンプトから、zf-tutorialディレクトリで次のように入力します。


zf enable layout

ZendToolapplication/layouts/scriptsフォルダを作成し、フォルダ内にファイル名layout.phtmlのビュースクリプトを設置しました。application.iniもまた変更されて、次の行を[production]セクションに追加しました。

resources.layout.layoutPath = APPLICATIONPATH "/layouts/scripts/"

ディスパッチサイクルの終わり、コントローラのアクションメソッドが終了した後に、ZendLayoutレイアウトがレンダリングされます。Zend_Toolはアクションのビュースクリプトのコンテンツを表示するための、とても基本的なレイアウトファイルを提供しています。それでは、このHTMLを必要な形に変更してみましょう。layouts.phtmlを開き、以下のコードと置き掛えます。


zf-tutorial/application/layouts/scripts/layout.phtml

<?php
$this->headMeta()->appendHttpEquiv('Content-Type', 'text/html;charset=utf-8');
$this->headTitle()->setSeparator(' - ');
$this->headTitle('Zend Framework Tutorial');

echo $this->doctype(); ?> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <?php echo $this->headMeta(); ?> <?php echo $this->headTitle(); ?> </head> <body> <div id="content"> <h1><?php echo $this->escape($this->title); ?></h1> <?php echo $this->layout()->content; ?> </div> </body> </html>


レイアウトファイルにはとても一般的なHTMLの"outer"が含まれています。このファイルは通常のPHPファイルであるため、コードの内部でPHPを利用できます。変数$thisがあり、この変数からBootstrap時に生成されたビューオブジェクトのインスタンスを利用することができます。この$this変数からは、ビューに割り当てられたデータ取り出したり、メソッドを呼び出したりすることができます。ビューに用意されているメソッド(ビューヘルパーと呼ばれます)は画面への出力が可能な文字列を返します。


では、ビューヘルパーの設定をいくつかしてみましょう。Webページのヘッダーセクションに関するものです。この設定により正しいdoctypeを出力するようになります。<body>内では、タイトルを含む<h1>をもつdivセクションを作成します。アクションの実行結果を表示するビュースクリプトを取得するため、layout()ビューヘルパーを使用してコンテンツのプレースホルダを出力します。この処理は echo $this->layout()->contentが行います。これはアクションのビュースクリプト生成がレイアウトのビュースクリプトより前に実行されることを意味しています。


ビュースクリプトをレンダリングする前に、WebページにDOCTYPEを設定する必要があります。アクションビュースクリプトが先にレンダリングされるので、事前にDOCTYPEを設定する必要があります。これはZendFormで特に顕著です。


DOCTYPEを設定するには、application.iniの[production] セクションに下記の行を追加します。


resources.view.doctype = "XHTML1STRICT"

これでdoctype()ビューヘルパーは正しいDOCTYPEを出力し、Zend_Formのようなコンポーネントは互換性のあるHTMLを生成します。


スタイル

今回は "単なる"チュートリアルではありますが、少しアプリケーションの見栄えを整えようとするとCSSファイルが必要になってきます。CSSファイルを作成して読み込みませようとしても、URLが正しいルートディレクトリを指していないがために、CSSファイルをどう参照するべきかが課題となります。この課題には幸いなことに、baseUrl()というビュースクリプトを利用することで解決することが可能です。このヘルパーは私たちが必要とする情報をリクエストオブジェクトから収集し、いくつかのURLを提供してくれます。

CSSファイルを読み込むためには、application/layouts/scripts/layout.phtmファイル内の<head>セクションに、ビューヘルパーのheadLink()を使用してCSSファイルパスを追記します。


zf-tutorial/application/layouts/scripts/layout.phtml

...
<head>
    <?php echo $this->headMeta(); ?>
    <?php echo $this->headTitle(); ?>
    <?php echo $this->headLink()->prependStylesheet($this->baseUrl().'/css/site.css'); ?>
</head>
...

headLink()prependStylesheet()メソッドを使用すると、コントローラビュースクリプト内にも細かなCSSファイルの追加が可能です。

これらのCSSファイルは <head> セクション内のsite.cssの後ろにレンダリングされます。


最後に、いくつかのCSSスタイルが必要ですので、publicフォルダにcssディレクトリを作成し、以下のコードを記載したsite.cssを追加します。


zf-tutorial/public/css/site.css

body,html {
    margin: 0 5px;
    font-family: Verdana,sans-serif;
}
h1 {
    font-size: 1.4em;
    color: #008000;
}
a {
    color: #008000;
}

/* Table */ th { text-align: left; } td, th { padding-right: 5px; }

/* style form */ form dt { width: 100px; display: block; float: left; clear: left; } form dd { margin-left: 0; float: left; } form #submitbutton { margin-left: 100px; }


もう少し綺麗にできた方がいいのですが、お分かりの通り、私はデザイナーではないのでお許しください!


これで、自動生成されていた4つのアクションスクリプトを削除できますので(もう覚えていないかもしれませんが)、application/views/scripts/indexディレクトリ内のindex.phtml, add.phtml, edit.phtml and delete.phtmlを削除します。


アルバム一覧

環境、データベース情報、ビュースケルトンの生成が完了したので、アプリケーションの実装にとりかかることができるようになりました。アプリケーションでは、いくつかのアルバムを表示することができます。これはIndexControllerクラスで行います。まずはindexAction()メソッドでデータベースのアルバムを一覧表示することから始めてみます。


zf-tutorial/application/controllers/IndexController.php

...
function indexAction()
{
    $albums = new ApplicationModelDbTableAlbums();
    $this->view->albums = $albums->fetchAll(); 
}
...

テーブルデータゲートウェイベースのモデル'''ApplicationModelDbTableAlbums'''クラスをインスタンス化します。fetchAll()メソッドはZendDbTableRowsetを返します。ZendDbTableRowsetはレコードを繰り返し取得することができるオブジェクトです。アクションのビュースクリプトファイル内に、この戻り値を渡します。


こうすることで、関連するビュースクリプトindex.phtmlで繰り返し処理を記述することができます:


zf-tutorial/application/views/scripts/index/index.phtml

<?php
$this->title = "My Albums";
$this->headTitle($this->title);
?>
<p><a href="<?php echo $this->url(array('controller'=>'index',
    'action'=>'add'));?>">Add new album</a></p>
<table>
<tr>
    <th>Title</th>
    <th>Artist</th>
    <th> </th>
</tr>
<?php foreach($this->albums as $album) : ?>
<tr>
    <td><?php echo $this->escape($album->title);?></td>
    <td><?php echo $this->escape($album->artist);?></td>
    <td>
        <a href="<?php echo $this->url(array('controller'=>'index',
            'action'=>'edit', 'id'=>$album->id));?>">Edit</a>
        <a href="<?php echo $this->url(array('controller'=>'index',
            'action'=>'delete', 'id'=>$album->id));?>">Delete</a>
    </td>
</tr>
<?php endforeach; ?>
</table>

最初に、(レイアウトに反映される)ページタイトルを設定しましょう。このタイトルは<head>セクションにも設定されることになります。ページタイトル設定はheadTitle()ビューヘルパーを使用することででき、これによりブラウザのタイトルバーに表示することができます。次に新しいアルバムを追加するリンクを作成しましょう。url()ビューヘルパーは、フレームワークが提供してくれる正しいベースURLを含むリンク作成を補助します。単に必要なパラメータを含む配列を渡せば、必要に応じて残りの処理が行われます。


次に、各アルバムのタイトル、アーティスト、レコードの編集や削除を可能にするためのリンクを表示するHTMLテーブルを作成します。標準のforeach:ループはアルバムのリストを反復処理するために使用されますが、我々はコロンとendforeach;を使用する別の構文を採用しています。それは中括弧を使うより可読性が高くなるためです。編集と削除のリンク作成には再びurl()ビューヘルパーを使用します。


http://localhost/zf-tutorial/publicにアクセスすると(or wherever you are following along from!)、次のようなアルバムの素敵なリストが表示されます。



新しいアルバムの追加

次に新しいアルバムを追加する機能を実装します。これには2つの機能があります。


  • ユーザーが詳細情報を入力するフォームを表示
  • データベースへのフォーム情報の送信および保存

フォームの表示にはZendFormを使います。ZendFormコンポーネントは、フォームを作成し、入力を検証することができます。フォームを定義するために、新しくZendformを継承したFormAlbumクラスを作成します。アプリケーションのリソースとして、そのクラスはformsディレクトリ内のAlbum.phpファイルに格納します。zfコマンドラインツールを使用してこのファイルを作成してみましょう。


zf create form Album

このコマンドはapplication/formsフォルダ内にAlbum.phpファイルを作成します。このファイルにはinit()メソッドが定義されています。init()メソッドでは、フォームを初期化設定したり必要な要素を追加することができます。

application/forms/Album.phpを編集し、init()メソッド内のコメントを削除し、以下のコードを追記します。


zf-tutorial/application/forms/Album.php

<?php

class Application_Form_Album extends Zend_Form
{
    public function init()
    {
      $this->setName('album');

      $id = new Zend_Form_Element_Hidden('id');
      $id->addFilter('Int');

      $artist = new Zend_Form_Element_Text('artist');
      $artist->setLabel('Artist')
             ->setRequired(true)
             ->addFilter('StripTags')
             ->addFilter('StringTrim')
             ->addValidator('NotEmpty');

      $title = new Zend_Form_Element_Text('title');
      $title->setLabel('Title')
            ->setRequired(true)
            ->addFilter('StripTags')
            ->addFilter('StringTrim')
            ->addValidator('NotEmpty');

      $submit = new Zend_Form_Element_Submit('submit');
      $submit->setAttrib('id', 'submitbutton');

      $this->addElements(array($id, $artist, $title, $submit)); 
    }
}

ApplicationFormAlbuminit()メソッド内で、ID、アーティスト、タイトル、送信ボタンの4フォーム要素を作成しています。表示されるラベルを含むそれぞれの項目には様々な属性を設定できます。idでは、潜在的なSQLインジェクション問題を防止するため、整数のみが使用されているかを確認したいと思います。この処理はIntフィルターで行う事ができます。


テキスト要素には2つのフィルターを追加します。StripTagsは入力されて欲しくないHTMLを削除し、StringTrimは不要な空白を削除します。それらをセットしたうえで、さらに必要であればユーザーが本当に情報を記入してるのかを確認するため、NotEmptyバリデーターを追加することもできます。

NotEmptyバリデーターは実際には設定する必要がありません。代わりにsetRequired()にtureをセットすることで、システムによって自動的に加えられるためです。今回はバリデーターを追加する方法の"デモンストレーション"をお見せするために記述しています)


フォームを使用するには、フォームを取得し、画面へ表示し、それからフォームの送信時に処理をする必要があります。これらはIndexControlleraddAction()内で行います。


zf-tutorial/application/controllers/IndexController.php

...
function addAction()    
{
  $form = new Application_Form_Album();
  $form->submit->setLabel('Add');
  $this->view->form = $form;

  if ($this->getRequest()->isPost()) {
      $formData = $this->getRequest()->getPost();
      if ($form->isValid($formData)) {
          $artist = $form->getValue('artist');
          $title = $form->getValue('title');
          $albums = new Application_Model_DbTable_Albums();
          $albums->addAlbum($artist, $title);

          $this->_helper->redirector('index');
      }else{
          $form->populate($formData);
      }
  }
}
...

それでは、詳細を見て行きましょう。


$form = new ApplicationFormAlbum();
$form->submit->setLabel('Add'); 
$this
->view->form = $form;

まず、FormAlbumをインスタンス化します。そして、送信ボタンに「Add」ラベルをセットします。それからレンダリングのためにビューへ割り当てます。


 if ($this->getRequest()->isPost()) {
      $formData = $this->getRequest()->getPost();
      if ($form->isValid($formData))

リクエストオブジェクトのisPost()メソッドがtrueの場合、フォームから送信されたとみなすことができるので、getPost()を使用してリクエストからデータを受け取り、isValid()メソッドを使用して入力値が適切かどうかチェックします。


          $artist = $form->getValue('artist');
          $title = $form->getValue('title');
          $albums = new ApplicationModelDbTableAlbums();
          $albums->addAlbum($artist, $title);

フォームの入力値が妥当であれば、ApplicationModelDbTableAlbumsモデルクラスをインスタンス化し、addAlbum()メソッドを呼び出します。このメソッドはデータベースに新しいレコードを作成します。


          $this->helper->redirector('index');

新しいアルバムの行を追加した後、Redirectorアクションヘルパーを使用して、indexアクションにリダイレクトを行います。(すなわちホームページへ戻ります。)


      }else{
          $form->populate($formData);
      }

フォームの入力値が妥当でない場合、ユーザーが入力したデータをフォームに配置して再表示します。


表示にはadd.phtmlのビュースクリプトでフォームをレンダリングする必要があります。


zf-tutorial/application/views/scripts/index/add.phtml

<?php
$this->title = "Add new album";
$this->headTitle($this->title);
echo $this->form ;
?>

ご覧のように、フォームをレンダリングすることは非常に簡単です。フォーム自身が表示する方法を理解しているので、私たちはただそれを呼び出すだけです。これで、新しいアルバムのレコードを追加できるようになったので、アプリケーションのホームページで「Add new album」リンクを使用できるはずです。


アルバムの編集

アルバムの編集は、アルバムの追加とほとんど同じなので、コードは非常に似ています。


zf-tutorial/application/controllers/IndexController.php

...
function editAction()
{
  $form = new ApplicationFormAlbum();
  $form->submit->setLabel('Save');
  $this->view->form = $form;

if ($this->getRequest()->isPost()) { $formData = $this->getRequest()->getPost(); if ($form->isValid($formData)) { $id = (int)$form->getValue('id'); $artist = $form->getValue('artist'); $title = $form->getValue('title'); $albums = new ApplicationModelDbTableAlbums(); $albums->updateAlbum($id, $artist, $title); $this->helper->redirector('index'); }else { $form->populate($formData); } } else { $id = $this->getParam('id', 0); if ($id > 0) { $albums = new ApplicationModelDbTableAlbums(); $form->populate($albums->getAlbum($id)); } } } ...


アルバムの追加との違いを見てみましょう。まず、フォームを表示する際に、データベースからアルバムのアーティスト名とタイトルを受け取り、そのデータをフォームに配置する必要があります。これがメッソドの一番下の部分です。


      $id = $this->getParam('id', 0);
      if ($id > 0) {
          $albums = new ApplicationModelDbTableAlbums();
          $form->populate($albums->getAlbum($id));
      }

リクエストがPOSTされていない場合でもこの処理が実行されますので注意してください。それはPOSTが入力済みとして処理されることを意味しているからです。フォームの初期表示のため、getParam()メソッドを使用してリクエストからidを取り出します。次にデータベースの行を取得するためにモデルを使用し、行のデータを直接フォームにセットします。

(モデル内のgetAlbum()メソッドがなぜ配列を返したのかは、あなたは既に知っていますね!)


フォームを検証した後、データベースの該当行にデータを渡して、保存する必要があります。これにはモデルのupdateAlbum()メソッドを使います。


     $id = $form->getValue('id');
     $artist = $form->getValue('artist');
     $title = $form->getValue('title');
     $albums = new ApplicationModelDbTableAlbums();
     $albums->updateAlbum($id, $artist, $title);

ビューテンプレートはadd.phtmlと同じです。


zf-tutorial/application/views/scripts/index/edit.phtml

<?php
$this->title = "Edit album";
$this->headTitle($this->title);

echo $this->form ; ?>


これでアルバムを編集することができるようになるはずです。


アルバムの削除

アプリケーションを完成させるために、私たちは削除処理を追加する必要があります。アルバムの一覧ページで、各アルバム名の隣に[削除]リンクを用意します。もっとも簡単な方法はクリックした時点で削除することですが、それは適切ではありません。HTTPの仕様を思い出すと、GETを使用して元に戻すことのできない処理をすべきではなく、代わりにPOSTを使用して処理を行う必要があります。


また、ユーザーがリンクをクリックして削除するとき、確認画面を表示させる必要もあり、そして「はい」をクリックした時点で削除を行うようにもしなければなりません。


それではIndexController::deleteAction():内のアクションコードを見てみましょう。


zf-tutorial/application/controllers/IndexController.php

...
public function deleteAction()
{
  if ($this->getRequest()->isPost()) {
      $del = $this->getRequest()->getPost('del');
      if ($del == 'Yes') {
          $id = $this->getRequest()->getPost('id');
          $albums = new ApplicationModelDbTableAlbums();
          $albums->deleteAlbum($id);
      }
      $this->helper->redirector('index');
  } else {
      $id = $this->getParam('id', 0);
      $albums = new ApplicationModelDbTableAlbums();
      $this->view->album = $albums->getAlbum($id);
  }
}
...

確認フォームを表示すべきか、あるいは、削除すべきかの決定には、追加や編集と同じように、リクエストのisPost()メソッドを使用します。deleteAlbum()メソッドを使用して実際に行を削除するためには、ApplicationModelDbTable_Albumsモデルを使用します。リクエストがPOSTされていない場合はidパラメータを探し、正しいデータベースのレコードを取得し、ビューに割り当てます。


ビュースクリプトは簡単なフォームです。


zf-tutorial/application/views/scripts/index/delete.phtml

<?php
$this->title = "Delete album";
$this->headTitle($this->title);
?>
<p>Are you sure that you want to delete 
'
<?php echo $this->escape($this->album['title']); ?>' by
'
<?php echo $this->escape($this->album['artist']); ?>'? </p> <form action="<?php echo $this->url(array('action'=>'delete')); ?>" method="post"> <div> <input type="hidden" name="id" value="<?php echo $this->album['id']; ?>" />
<input type="submit" name="del" value="Yes" />
<input type="submit" name="del" value="No" /> </div> </form>

このスクリプトでは、ユーザーへの確認メッセージ[はい]と[いいえ]ボタンを表示します。アクションで、明確に[はい]が選択されているときにのみ削除を行います。


これでチュートリアルはすべてです - アプリケーションは問題なく動作するはずです。


まとめ

ここまでで、Zend FrameworkのMVCを使った簡単だけどちゃんと動くアプリケーションを作成する方法をご覧いただけたと思います。あなたにとってこれが面白く、そして有益であったことを願っています。もし、何か間違いを見つけた場合、rob@akrabat.comにメールをください!


このチュートリアルでは、フレームワークの基本的な使用方法を見ましたが、さらに調べてみると、ZendFrameworkには他にもたくさんのコンポーネントが用意されています。このチュートリアルでは、それらの説明の多くはスキップしています。私のWebサイト(http://akrabat.com)には、Zend Frameworkの多くの記事が掲載されているので参照してみてください。また、 http://framework.zend.com/manual でドキュメントをお読むこともオススメします。


最後に、あなたが本を読む方が好きな場合は、「Zend Framework in Action」という本を執筆しましたので、こちらもご覧になってみてください。

最新の情報は http://www.zendframeworkinaction.com でご確認いただけます。是非ご覧ください。