Home > 技術・開発ツール > Zend Framework Quick StartにDoctrineを適用してみる

Zend Framework Quick StartにDoctrineを適用してみる

前回のエントリに基づき、ZF本家のクイックスタートにあるチュートリアルのコードをDoctrineを使って書き直してみた。Zend_Dbを使う場合に一番面倒なモデルのコードの記述が簡単なYAMLファイルを一つ書くだけで済み、コントローラの修正も最低限で済んだ。

新旧の概要を比較を見てみると

オリジナルのディレクトリ構造

zf_original

Doctrine適用後のディレクトリ構造

zf_modified

  • モデルの生成をDoctrinに任せた結果、チュートリアル中の”Create a Model and Database Table”に関わる部分は不要になる。つまりオリジナルの”models/”以下のコードはまるまるDoctrineが生成するコードで置き換わる。
  • MySQLを使用するのでdata/に入っていたSQLiteのテーブルを削除。代わりにDoctrineを使用する際に必要になる4つのディレクトリを置く。schema.sqlはDoctrineが生成したものである。
  • library/の配下にDoctrine本体(1.1.1)と自分でカスタマイズしたプログラムを入れる。本来はプラグインとして定義すればスマートなのだろうが今回は省略。また環境設定関連の情報はWebアプリとDoctrineのコマンドラインツールの両方から参照される必要があるので、preparation.phpとして外に出しここに配置。
  • scripts/の配下はDoctrineのコマンドラインツールを動かすためのdoctrine-cli.phpに置き換える。
  • あらかじめZendFrameworkにパスが通っていることが前提。もちろんlibrary/の下にZFを置いてもいい。自分が使用したバージョンは1.8.2。
  • 余談だが、library/の下に複数のライブラリを置く場合にどうやって配置するかという問題を感じた。正攻法で行けば各ライブラリごとにサブディレクトリを切ってその中に配置することで明示的に分けるべきだろう。ただしそうなると新たにライブラリを追加するたびにinclude_pathのメンテも行わなければならなくなり面倒だ。一方フラットに配置したとするとlibrary/にさえパスが通っていればあとはAutoloader任せでOKということになる。ただしファイル名の衝突が生じたときにやっかいなことになるだろう。

public/index.phpとscripts/doctrine-cli.phpの両方から呼び出されるpreparation.phpの内容はこんな感じだ。

preparation.php
<?php

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Set include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    realpath(APPLICATION_PATH . '/../library/doctrine'),
    realpath(APPLICATION_PATH . '/models'),
    realpath(APPLICATION_PATH . '/models/generated'),
    get_include_path()
)));

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

// Create application
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);

$application_ini = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', null);
Zend_Registry::set('application_ini', $application_ini);

$connection = My_Db_Doctrine::connect($application_ini );

Zend_Registry::set('doctrine_config', array(
    'data_fixtures_path'  =>  APPLICATION_PATH . '/../data/fixtures/',
    'migrations_path'     =>  APPLICATION_PATH . '/../data/migrations/',
    'sql_path'            =>  APPLICATION_PATH . '/../data/sql/',
    'yaml_schema_path'    =>  APPLICATION_PATH . '/../data/schema/',
    'models_path'         =>  APPLICATION_PATH . '/models/'
    ));

Doctrineとの接続を行うクラスであるMy_Db_Doctrineも定義する

library/My/Db/Doctrine.php
<?php

class My_Db_Doctrine
{

    public static function connect($application_ini){

        $data = $application_ini->con_database;

        $dsn = sprintf(
                '%s://%s:%s@%s/%s',
                strtolower($data->type),
                $data->username,
                $data->password,
                $data->host,
                $data->dbname
        );

        $db =  Doctrine_Manager::connection($dsn);

        return $db;
    }

}

今回モデル関連で作成する必要のある唯一のファイルがschema.ymlである。

schema.yml
---
Guestbook:
  tableName: guestbook
  columns:
    id:
      primary: true
      autoincrement: true
      type: integer(10)
    email:
      type: string(32)
      notnull: true
      email: true
    comment: string(255)
    created: timestamp

オリジナルのスキーマにはemailフィールドにデフォルト値を定義しているが今回は省略。また初期データの投入のしかけもスキップした。

今回はSQLiteではなくMySQLを使用するのでapplication.iniファイルに以下のセクションを追記する。

[con_database]
name      = "db"
type      = "mysql"
dbname    = "zfdev"
host      = "localhost"
username  = "zfdev"
password  = "zfdev"
charset   = "utf8"

scripts/doctrine-cli.phpは実行スクリプトではなくただのphpファイルにした。こうすればWindowsからも使えるはずだ。

doctrine-cli.php
<?php

//Preparation
require_once '../library/preparation.php';

$cli = new Doctrine_Cli(Zend_Registry::get('doctrine_config'));

if (isset($_GET['cmd'])) {
    $_SERVER['argv'] = array('doctrine-cli.php', $_GET['cmd']);
}

$cli->run($_SERVER['argv']);

scripts/の中から

php doctrine-cli.php

と実行するとDoctrineのオプション一覧が出てくる。

doctrine cli execution 150x150 Zend Framework Quick StartにDoctrineを適用してみる

正しくコマンドラインツールが動いているのが確認できたので今度は

php doctrine-cli.php build-all

を実行。DoctrineがMySQL内にテーブルを作り、同時にapplication/modelsの配下にモデルが生成される。DDL文は別途

php doctrine-cli.php generate-sql

とすることでdata/sqlの配下に生成されるがアプリの動作そのものには必須ではない。

コントローラについて修正が必要なのはapplication/controllers/GuestbookController.phpだけだ。

application/controllers/GuestbookController.php
<?php

class GuestbookController extends Zend_Controller_Action
{

    public function init()
    {

    }

    public function indexAction()
    {
        $guestbook = Doctrine_Query::create()
                        -> from('Guestbook g')
                        -> orderBy('g.created DESC')
                        -> execute();

        $this->view->entries = $guestbook;
    }

     public function signAction()
    {
        $request = $this->getRequest();
        $form    = new Default_Form_Guestbook();

        if ($this->getRequest()->isPost()) {
            if ($form->isValid($request->getPost())) {
            	$guestbook = new Guestbook();
                $guestbook->fromArray($form->getValues(true));
                $guestbook->created = new Doctrine_Expression('now()');
                $guestbook->save();

                return $this->_helper->redirector('index');
            }
        }
    	$this->view->form = $form;
    }

}

元のコードは、indexAction()が

    public function indexAction()
    {
        $guestbook = new Default_Model_Guestbook();
        $this->view->entries = $guestbook->fetchAll();
    }

で、signAction()が

   public function signAction()
     {
        $request = $this->getRequest();
        $form    = new Default_Form_Guestbook();

        if ($this->getRequest()->isPost()) {

            if ($form->isValid($request->getPost())) {

                $model = new Default_Model_Guestbook($form->getValues());
                $model->save();

                return $this->_helper->redirector('index');
            }
        }

である。非常に単純なアプリケーションとはいえ拍子抜けするほど簡単に変更できた。(当然ながらビューはまったく変更していない。)

Doctrineを使うと参照整合性制約やモデル同士の一対一/一対多/多対多といった関係、さらにモデル同士の継承でさえも簡単に定義できてしまうという。 もちろんDoctrineという一種のフレームワークを覚えなければならないからその分のコストはかかるしDoctrine独自の制約といった難し さもあるのだろうが、それらを補ってあまりある恩恵が得られると思う。これはトライする価値ありだ。

Comments:0

Comment Form
Remember personal info

Trackbacks:1

Trackback URL for this entry
http://studiokdf.com/blog/2009/06/137.html/trackback
Listed below are links to weblogs that reference
Zend Framework Quick StartにDoctrineを適用してみる from KDF Memo
pingback from Zend Framework Quick StartにDoctrineを適用してみる - その2 - KDF Memo 09-06-14 (日) 17:58

[...] Older [...]

Home > 技術・開発ツール > Zend Framework Quick StartにDoctrineを適用してみる

アーカイブ

Return to page top