IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Web development | Open source  >

「Zend Framework」で加速するPHP開発: 第2回 Zend Frameworkの各コンポーネントを一気に制する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません


レベル: 初級

杉田 直哉, Writer, ITmedia

2004年 11月 05日

前回は、Zend Frameworkの概要とその導入方法について説明しました。今回は、各コンポーネントの使用方法について紹介していきます。

 第1回となる前回では、Zend Frameworkの概要を説明した後、Zend Frameworkの導入方法について説明しました。今回は、各コンポーネントの使用方法について紹介していきます。

各コンポーネントの役割と使用法

 さて、ここまででZend FrameworkのMVCモデルを使用する準備は整いました。ここからは、各コンポーネントの使用方法を説明しますが、その前にZend FrameworkのFront Controllerの動作をもう一度まとめておきましょう(図1)。まず、ブラウザで指定されるURLはmod_rewriteの機能によってindex.phpのアクセスへrewriteされます。index.phpではZend_Controller_Frontクラスを読み込み、このクラスがRouterとなるクラスとDispatcherとなるクラスへ振り分けます。指定されたURLは、Routerによって「どのAction ControllerのどのActionを呼び出す」という情報に解釈されて、Zend_Controller_Dispatcher_Tokenにまとめられます。これをDispatcherが受け取り、該当のActionへ制御が移ります。



図1 Front Controllerの動作

拡大図

 利用者が独自に書かなければならないソースコードは次の4種類です。

  1. index.php:どのRouterを使用するかを設定する
  2. Action Controller:各コントローラーにActionメソッドを定義する
  3. Viewクラス:ブラウザ画面に表示される際のレイアウトやロジックを定義する
  4. Modelクラス:データベースアクセスやロジックを処理するモデル層を定義する



上に戻る


index.php:どのRouterを使用するかを設定する

 Zend FrameworkにはPreview 0.1.5リリースの時点で2つのRouterが存在し、どちらを選ぶかでindex.phpの書き方も変わってきます。

簡単に使用できるが自由度の低いZend_Controller_Routerクラス

 デフォルトではZend_Controller_Routerクラスが使用されます。Zend_Controller_Routerクラスは、簡単に使用できて独自に記述するコードが最小限で済みます(リスト1)。ただし、ルーティング定義が固定されており、図2のようにURLの指定方法も固定されてしまいます。


リスト1 Zend_Controller_Routerクラスを使うときのindex.php
                
require_once 'Zend/Controller/Front.php';
Zend_Controller_Front::run('./application/controllers';


図2 Zend_Controller_RouterクラスのURL指定方法

 後ろにつけるキーは、Actionメソッド内で変数として取得できます。このURLの解釈で分かるとおり、Zend_Controller_Routerクラスを使用する場合は、DocumentRootにindex.phpが配置されている必要があります。このため、1つのWebサーバでZend Frameworkを使用した複数のアプリケーションをホストしたい場合は、Virtual Hostを設定してアプリケーションごとにホスト名称を用意する必要があります。

柔軟に利用できるがコーディング量の増えるZend_Controller_RewriteRouterクラス

 もう1つのRouterとしてZend_Controller_RewriteRouterクラスが用意されています。こちらのRouterは自由にルーティング制御を定義できる半面、コーディング量が増えます。

 例えば、Zend_Controller_Routerクラスと同様のルーティングをしたい場合、リスト2のように記述します。Zend_Controller_RewriteRouterでは、定義したいルートごとにaddRouteメソッドを使用して設定し、リスト2は「:controller/:action」のルートを設定しています。先頭に「:」をつけることで変数として解釈されますが、「:controller」と「:action」は予約語として定義されており、そのままAction ControllerとActionメソッドの名称として解釈されます。


リスト2 Zend_Controller_RewriteRouterクラスを使うときのindex.php
                
require_once 'Zend/Controller/Front.php';
require_once 'Zend/Controller/RewriteRouter.php';

$router = new Zend_Controller_RewriteRouter();
$router->setRewriteBase("C:\www\blog");
$router->addRoute('user', ':controller/:action', array('controller' => 'Main', 'action' => 'Index'));

$ctrl = Zend_Controller_Front::getInstance();
$ctrl->setRouter($router);
$ctrl->setControllerDirectory('./application/controllers')->dispatch();
 

また、リスト2ではsetRewriteBaseによってルートディレクトリを指定*しています(デフォルトでルートディレクトリを検知するためこの指定は必須ではありません)。注意すべき点としては、Zend_Controller_Routerクラスのように、キーを後ろにつなげるルーティングはサポートされていないことです。このため、Zend_Controller_Routerクラスを使用したアプリケーションをそのままZend_Controller_RewriteRouterクラスへ移行することはできません。現状では、用途に応じて使い分けるのが良いでしょう。




上に戻る


Action Controller:各コントローラーにActionメソッドを定義する

Action Controllerは、Zend_Controller_Actionクラスを継承したクラスである必要があります。また、Action Controller内には、「Action名称+"Action"」という名前でメソッドを定義しなければいけません。Indexアクションの場合は、IndexActionメソッドとなります。これらはRouterにかかわらず同一です。Action Controllerの簡単なサンプルコードをリスト3に示しましょう。


リスト3 Action Controllerの簡単なサンプルコード
                
<?php

require_once 'Zend/Controller/Action.php';
require_once 'Zend/View.php';

// コントローラーに定義されていないアクションが呼ばれた場合に処理が行われるハンドラ
class IndexController extends Zend_Controller_Action
{
    public function __call($action, $arguments)
    {
        global $config;
        $this->_redirect('/Blog/Index');
    }

    // Indexアクション(~Actionの命名規則が存在する)
    public function indexAction()
    {
        global $config;
        $this->_redirect('/Blog/Index/');
    }

    // ルーティング定義が見つからなかった場合はZend_Controller_Router_Exceptionが発生し、
				IndexController.phpのnoRouteアクションが呼ばれる
    public function noRouteAction()
    {
        header('HTTP/1.1 404 Not found');
        $view = new Zend_View();
        $view->setScriptPath('../application/views');
        $view->pageTitle = '404 error';
        echo $view->render('Pages/ServicePages/404.php');
    }
}

?>




上に戻る


Viewクラス:ブラウザ画面に表示される際のレイアウトやロジックを定義する

Zend Frameworkには、「Zend_View」というHTMLレンダリング用のコンポーネントが備わっています。ビューに関しては、Smartyなど既存のテンプレートエンジンも使用可能です。どこまでZend_Viewの機能に頼るかは、次のような選択肢の中から選ぶことができます。

  1. Zend_Viewが読み込むビュースクリプト内でテンプレートエンジンを使用する
  2. Zend_View_Abstractを継承したクラスにテンプレートエンジンを内包する
  3. Zend_Viewを使用せずにテンプレートエンジンを使用する
  4. Zend_Viewのみを使用する
  5. Zend_Viewを使用しない

マニュアルには1の方法が例示されていますが、Viewコンポーネントの中で、さらにHTMLとプレゼンテーションロジックを分離するため、必要以上にコードが冗長になってしまう恐れがあります。1ページ単位の情報量が多く、規模も大きいWebサイトを作成する場合には適切ですが、そうでない場合は避けた方が良いでしょう。特に1のような書き方にこだわりがなく、コード量も少なくて済む場合には4を、すでに慣れ親しんだテンプレートエンジンがある場合は3を選べば良いでしょう。

なお、「RSSやJSONのデータを発信するサーバの役目を担うAction」といったように、結果がHTMLとならない場合には5を選択するのが妥当です。2の方法を取れば使いやすいViewコンポーネントを独自に開発することも可能ですが、互いの依存性が高まってしまいます。

Zend_Viewは、大まかにコントローラースクリプトとビュースクリプトに分かれます。ここでのコントローラースクリプトは、「Actionメソッド内などコントローラー処理の最後でビュースクリプトを読み込むために定義する記述」を指します。ビュースクリプトは、それを受けて引き渡される変数とともにレンダリングされます。HTMLの記述は通常、ビュースクリプトに記述されます。

コントローラースクリプト

コントローラースクリプトでは、必要に応じて次の処理を記述します。

Zend_Viewクラスのインスタンス生成
$view = new Zend_View();

ビュースクリプトへ引き渡す変数のアサイン

「$view->a = $a」のように、直接代入する方法もありますが、「$view->assin($array)」のように配列をまとめて代入することも可能です。オブジェクトの場合は配列にキャストして渡します。

$view->a = $a;$view->assin($array);

ビュースクリプトのパスを追加

デフォルトでは、ビュースクリプトを読み込むコントローラークラスの存在するディレクトリが検索されます。保管ディレクトリを別々に分けている場合は、次のようにビュースクリプトが保管されているディレクトリを指定する必要があります。

$view->setScriptPath('/path/to/app/views');

独自ヘルパーパスの設定

Zend_Viewでは、よく使用するHTML要素をレンダリングする関数として、ヘルパーが用意されています。HTMLフォーム要素のヘルパークラスがZend_Viewに付属しており、デフォルトで使用可能になっています。

ここでは独自にヘルパークラスを作成した場合に、そのヘルパークラスが保管されるディレクトリへのパスを設定することで、同様にヘルパーとして使用することを可能にします(特に使用しない場合は設定する必要はありません)。

 $view->setHelperPath('/path/to/more/helpers');
 

エスケープの設定

ビュースクリプト内で使用できるescapeの関数を指定します。ビュースクリプト内で「echo $this->escape($this->variable);」のように記述しておけば、エスケープに使用される関数を一括して切り替えられるなど、管理が容易になります。デフォルトではhtmlspecialcharsが設定されており、「<」や「>」などHTMLにおいて特殊な意味を持つ文字はエスケープされます。

$view->setEscape('htmlentities');

ビュースクリプトのレンダリング

上記で指定したパス上のビュースクリプトファイルを指定して、レンダリングを行います。

echo $view->render(...);

ビュースクリプト

Zend/Viewディレクトリ以下にはFilterディレクトリが存在し、ヘルパーと同様にZend_Viewのインスタンスに対してフィルタを登録可能です。Filterディレクトリには付属するクラスが存在しないので、使用する場合はすべてカスタマイズ作成する必要があります。ビュースクリプトにおいて使用した場合には、指定した文字列に対してディレクトリに保管されているフィルタクラスのfilter()メソッドの処理がすべて適用されます。

ビュースクリプトでは、HTMLを交えたPHPコードと同じように、コントローラースクリプトで引き渡された変数と設定されたヘルパー、エスケープなどの処理を交えて、最終的にレンダリングされるHTMLレイアウトを構成します。引き渡された変数やassign関数で設定された配列は「$this->books」のようにアクセスします(リスト4)。


リスト4 変数や配列にアクセスするコードの例
                
<?php if ($this->books): ?>
<!--本の一覧-->
<table>
  <tr>
    <th>著者</th>
    <th>タイトル</th>
  </tr>
  <?php foreach ($this->books as $key => $val): ?>
  <tr>
    <td><?php echo $this->escape($val['author']) ?></td>
    <td><?php echo $this->escape($val['title']) ?></td>
  </tr>
  <?php endforeach; ?>
</table>
<?php else: ?>
<p>表示する本がありません。</p>
<?php endif; ?>





上に戻る


Modelクラス:データベースアクセスやロジックを処理するモデル層を定義する

Zend Frameworkでは、データベースアクセスの抽象レイヤーとなるZend_Dbを備えています。基本的にはPDOを中心としたアダプタで構成されていますが、DB2、Oracle、MySQLiはネイティブのドライバによって実装されています*

DBMSの切り替え

Zend_Dbでは、factoryメソッドに渡すURLを変更することで、ドライバの種類を変更可能です。このURLの形式は、「PDO_MYSQL」のように「PDO_」を先頭につけることが推奨されています*表1)。



表1 ドライバの種類を判別させるときに指定するURL

SQLクエリの発行方法

現在のバージョンでは、例えば次のような選択肢があります。

Zend_Db_Adapterを使用して直接的にSQLクエリを発行する(リスト5)

ほかのフレームワークでよくあるようなSQLの隠蔽効果はありませんが、シンプルで分かりやすいコードが記述できます。


リスト5 Zend_Db_Adapterを使用して直接的にSQLクエリを発行する
                
<?php
require_once 'Zend/Db.php';
$params = array ('host' => '127.0.0.1', 'username' => 'malory', 'password' => '******', 'dbname' => 'camelot');
$db = Zend_Db::factory('PDO_MYSQL', $params);
$result = $db->query('SELECT * FROM example WHERE date > :placeholder', array('placeholder' => '2006-01-01'));
$rows = $result->fetchAll();
?>


SQLクエリの発行を、内包されたZend_Db_Adapterの機能に委譲する(リスト6)

Zend_Dbではドライバの抽象レイヤーが提供されているので、データベースにアクセスするAPIの違いを意識することなく、互換性の高いコードを記述可能です。ただし、データベースによっては発行するSQLに多少の差異が存在するので、SQLが記述されたアプリケーションを、互換性を意識せずに移行するのは難しいです。そのため、SQL文の生成をZend_Dbに委譲して、必要最低限の記述のみで済ませることもできます。


リスト6 SQLクエリの発行を、内包されたZend_Db_Adapterの機能に委譲する
                
<?php
require_once 'Zend/Db.php';
$params = array ('host' => '127.0.0.1', 'username' => 'malory', 'password' => '******', 'dbname' => 'camelot');
$db = Zend_Db::factory('PDO_MYSQL', $params);
$select->from('round_table', '*')
       ->where('noble_title = :title')
       ->order('first_name')
       ->limit(10,20);
$params = array('title' => 'Sir');
$result = $db->fetchAll($select, $params);
?>

Zend_Db_Tableを使用してO/Rマッピングを行う(リスト7)

Zend_Db_Table は、Zend_Db_Tableクラスを継承したオブジェクトと、対応する表をマッピングするような仕組みを備えています。これによって、オブジェクト指向と親和性の高い記述が可能です。また、余計なコードを記述しなくても済むように、デフォルト値として規約が存在します。リスト7でいうと、「RoundTable」クラスはデータベースの「round_table」表とマッピングされます。また、主キーは「id」列として認識されます。ただし、次のように継承したクラスの変数を上書きして、任意の値をデフォルト値の代わりに使用することもできます。


リスト7 Zend_Db_Tableを使用してO/Rマッピングを行う
                
<?
ass RoundTable extends Zend_Db_Table
{
    $this->_name = 'another_table_name';
    $this->_primary = 'another_column_name';
}
?>


<?php
class RoundTable extends Zend_Db_Table {}
$table = new RoundTable();
$db = $table->getAdapter();
$where = $db->quoteInto('noble_title = ?', 'Sir')
       . $db->quoteInto('AND first_name = ?', 'Robin');
$order = 'favorite_color';
$row = $table->fetchRow($where, $order);
?>




上に戻る


おわりに

以上、2回に渡ってZend Frameworkの機能と概要を解説しました。より詳細は、具体例を用いて今後解説していきます。また、Zend Frameworkのマニュアルでは、すぐに実行可能なサンプルコードを交えながらフレームワークの機能を解説しています。このマニュアルは、日本語を含む主要10か国語でリリースされており、英語が得意でない方にも始めやすいように配慮がなされています。ぜひチャレンジしてみてください。

次回からは、Zend Frameworkで構築されたブログツールを題材にして、実際にZend Frameworkに備わる機能や使い方を解説していきたいと思います。




上に戻る


このページで出てきた専門用語

setRewriteBaseによってルートディレクトリを指定
ディレクトリを移動する場合の依存性となるため、このメソッドは指定しないように推奨されています。
DB2、Oracle、MySQLiはネイティブのドライバによって実装されています
ただし、Zend_Dbが提供するAPIはPDOに依存しないため、使用する上で意識しなくて良いよう配慮されています。
「PDO_」を先頭につけることが推奨されています
この方法によるURL指定は、Preview 0.2から推奨されており、Preview 0.1.5では別の指定方法も可能です。


参考文献



著者について

杉田直哉,ITmedia




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


この記事を共有する

はてなブックマーク はてなブックマーク livedoorクリップ livedoorクリップ del.icio.us del.icio.us Buzzurl(バザール) Buzzurl(バザール) Choix! Choix!
Saafブックマーク Saafブックマーク FC2ブックマーク FC2ブックマーク MM/memo MM/memo ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
CZブックマーク CZブックマーク newsing newsing




上に戻る


    日本IBMについて プライバシー お問い合わせ