Home > Tags > Doctrine

Doctrine

Zend Framework Quick StartにDoctrineを適用してみる – その2

前回のエントリのコードはDoctrine関連の記述が煩雑だった。せっかくZend_Applicationが出てきたのだからそれを利用したスマートな記述ができるのではと思っていたら、すでに先人がいた。

Doctrine ORM and Zend Framework « Danceric

多忙のため更新が滞っている元ネタの作者に代わりZF1.8を適用した形で書き直したというエントリである。内容はコードを見てもらえばわかるとして、doctrine-cliの中の

$application->bootstrap('doctrine')

$application->getBootstrap()->bootstrap('doctrine');

の間違いだと思う。(前者だとBootstrapの中の_init*メソッドがすべて実行されてしまうので。)

それから同じくdoctrine-cliの中で

define('APPLICATION_ENV', 'development');

とあるが、この値は外部に出してindex.phpとdoctrine-cliとで共用すべきだろう。preparation.phpの中にまとめてあるのでそれをインクルードするようにした。

doctrine-cli
#!/usr/bin/env php

<?php
/**
 * Doctrine CLI script
 */
//Preparation
require_once '../library/preparation.php';

//Doctrine Bootstrap
$application->getBootstrap()->bootstrap('doctrine');

$cli = new Doctrine_Cli($application->getOption('doctrine'));
$cli->run($_SERVER['argv']);

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独自の制約といった難し さもあるのだろうが、それらを補ってあまりある恩恵が得られると思う。これはトライする価値ありだ。

Zend FrameworkとDoctrineを組み合わせる

現在のZend_Dbはモデルの扱いが面倒でありまだまだ改善の余地がある。(その点symfonyはモデルの扱いについてはPropelやDoctrineといった外部ライブラリに依存することで割り切っている。)ZFもせっかくの疎結合を売りにしているのだからモデル層についてはZend_Dbよりもっとよいものが使えれば、と思っていた。一方他の開発者も同じことを思っているようで、海外ではZFをDoctrineと組み合わせて使う試みがけっこう盛んなようだ。この分野ではこの記事が有名なようで、数カ国後に訳されている。今回はこれを日本語に訳してみた。誤訳・ぬけがあれば指摘してもらいたい。個人的にDoctrineには非常に興味があるのだが、Web上ではZend_Log / Zend_AuthといったモジュールをZend_Dbを使用せずにDoctrineで置き換えるためのプロジェクトもあり面白い。それらは後日改めて紹介していきたい。


Ruben Vermeersch
Retrieved from: http://ruben.savanne.be/articles/integrating-zend-framework-and-doctrine

Zend Framework と Doctrineの統合

Zend Framework とDoctrine. を一緒に使用してプロジェクトをセットアップする方法について説明します。簡単なメッセージボードをステップバイステップで作っていきます。

最初に

この記事の内容は平易なものですが、読者がZendFrameworkとDoctrineについて知識があることを前提にしています。 二つを組み合わせる方法を知る前にまずそれぞれを個別に使ってみることを勧めます。 どちらにも初心者のための良質なドキュメントが整備されています。Zend Framework Quick StartDoctrine’s My First Projectです。 Akra’s Zend Framework Tutorial も非常に良い手引きです。

Zend Framework は”use-at-wil”(使いたいときに使う)というアーキテクチャに基づいています。 つまり他のフレームワークのように「全部使うか、全く使わないか」というアプローチはとっていません。ZendFrameworkは全体のうち必要な部分だけ使うことができるのです。 「使いたいときに使う」というアーキテクチャであるゆえに、ZendFremeworkが提供するデータベース抽象化レイヤーを使用せずともZendFrameworkアプリケーションを作ることができます。Zend_Dbがダメなテクノロジーだというわけではありませんが、低層のデータベースレイヤーに近い部分をカバーしているだけにとどまっています。 Doctrineを使えば、データベースのことを気にせずにデータをオブジェクトライクに操作することができます。

Zend Framework ではアプリケーション作成の際の自由度が高くなっています。 言い換えるなら、ZendFrameworkではプロジェクトにフレームワークが定める特定の構造を使わなくともよいのです。 今回はここで提供されているデフォルトのプロジェクト構造になるべく沿うようにします。 しかしこれは全くもって好みの問題です。

始めましょう

まず最初に、デフォルトのプロジェクト構造を作成してライブラリをインストールします。 ファイルマネージャを開いて次のようなフォルダー構造を作ってください。 それぞれのフォルダの目的についてはすぐ後で説明します。

基本のフォルダ構造

basic folder structure Zend FrameworkとDoctrineを組み合わせる

たくさんのフォルダがありますが、ZendFrameworkを使ったことがあるならばほとんど見覚えがある名前のはずです。 ただしデフォルトの構造と異なる部分があります。:

  • application/doctrine/: ここにはDoctrineが使用するSQLやYAMLのスキーマ、マイグレーション、データダンプといったものが格納されます。
  • application/models/: Doctrineが自動的に生成するモデルファイルが格納されます。モデルファイルはZendFrameworkの中から簡単に利用することができます。
  • library/: 普通はここにZendFrameworkだけを入れればよいのですが 今回は二つのライブラリが必要になります。つまりZendFrameworkとDoctrineです。 ですので、サブフォルダを二つ作ってそれぞれにインストールすることにします。
  • scripts/Doctrineにはちょっとしたコマンドラインスクリプトが付属しています。ここにそのツールが配置されます。(先ほど紹介したサイトでそのように推奨されています。)

次にZendFrameworkとDoctrineをインストールします。 ウェブサイトからそれぞれの最新版を個別にダウンロードして解凍してください。その中からZendFrameworkの場合はlibraryフォルダの中を、Doctrineの場合はlibフォルダの中を先ほど作ったフォルダに入れてください。 こんな感じになるはずです。

Zend Framework と Doctrine がインストールされた状態

zend framework and doctrine installed Zend FrameworkとDoctrineを組み合わせる

ブートストラップ

Zend Framework Quick Start の内容に従うならば、bootstrap.phpというファイルを作る必要があります。 このファイルを作った上でさらにDoctrineを使うことができるように少々手直しをしましょう。

最初にpublic/index.phppublic/.htaccess を作ります。 自分の好みのエディタを起動して、次のソースコードをコピーしてファイルを作ってください。(注:Gitを使用してすべてのソースコードを入手できます。詳細は記事の末尾にある付録を見てください。)

public/index.php

<?php
require '../application/bootstrap.php';

public/.htaccess

RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1

見てわかるように、このコードは他のZendFrameworkアプリケーションの場合と変わりありません。 一方application/bootstrap.php は多少違っています。 このファイルを2つのファイルに分割します。: application/bootstrap.phpapplication/global.php です。. 前者はクライアントリクエストを担当し、後者は必要なファイルのインクルードを行います。 bootstrapファイルを分割したのはglobal.php はDoctrineのコマンドラインスクリプトからも使う必要があるからです。(これについてはすぐ後で説明します。)
application/global.php

<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/Brussels');

/*
 * Setup libraries & autoloaders
 */
set_include_path(dirname(__FILE__).'/../library/zendframework'
        . PATH_SEPARATOR . dirname(__FILE__).'/../library/doctrine'
        . PATH_SEPARATOR . dirname(__FILE__).'/models'
        . PATH_SEPARATOR . dirname(__FILE__).'/models/generated'
        . PATH_SEPARATOR . get_include_path());
require 'Zend/Loader.php';
Zend_Loader::registerAutoload('Zend_Loader');

/*
 * Set super-global data
 */
Doctrine_Manager::connection("mysql://user:pass@localhost/database");

/*
 * Configure Doctrine
 */
Zend_Registry::set('doctrine_config', array(
        'data_fixtures_path'  =>  dirname(__FILE__).'/doctrine/data/fixtures',
        'models_path'         =>  dirname(__FILE__).'/models',
        'migrations_path'     =>  dirname(__FILE__).'/doctrine/migrations',
        'sql_path'            =>  dirname(__FILE__).'/doctrine/data/sql',
        'yaml_schema_path'    =>  dirname(__FILE__).'/doctrine/schema'
        ));

application/bootstrap.php

require dirname(__FILE__).'/global.php';

Zend_Controller_Front::run(dirname(__FILE__).'/controllers');

では順を追って詳しく見ていきましょう。

error_reporting(E_ALL | E_STRICT);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/Brussels');

適切なエラーハンドリングとタイムゾーンを設定するのはいつでもふさわしいことです。 特に言及することはありません。

/*
 * Setup libraries & autoloaders
 */
set_include_path(dirname(__FILE__).'/../library/zendframework'
        . PATH_SEPARATOR . dirname(__FILE__).'/../library/doctrine'
        . PATH_SEPARATOR . dirname(__FILE__).'/models'
        . PATH_SEPARATOR . dirname(__FILE__).'/models/generated'
        . PATH_SEPARATOR . get_include_path());
require 'Zend/Loader.php';
Zend_Loader::registerAutoload('Zend_Loader');

Doctrineを使うための設定です。 inlude pathをZendFrameworkとDoctrineをインクルードするように記述します。 Doctrineが生成するモデルファイルを格納するフォルダもインクルードしています。 Doctrineをautoloadの対象にしていないことに注意してください。 include_pathが正しく設定されていれば後はZend Loaderがやってくれます。 注意: 1.8より前のZendFrameworkにはバグがあるために、Doctrin Class Templateを使った際に(軽微な)ワーニングが出力されます。 この問題はバージョン1.8のリリースで解決されることになっています。(subversion内のリポジトリではすでに修正されています。)

/*
 * Set super-global data
 */
Doctrine_Manager::connection("mysql://user:pass@localhost/database");

/*
 * Configure Doctrine
 */
Zend_Registry::set('doctrine_config', array(
        'data_fixtures_path'  =>  dirname(__FILE__).'/doctrine/data/fixtures',
        'models_path'         =>  dirname(__FILE__).'/models',
        'migrations_path'     =>  dirname(__FILE__).'/doctrine/migrations',
        'sql_path'            =>  dirname(__FILE__).'/doctrine/data/sql',
        'yaml_schema_path'    =>  dirname(__FILE__).'/doctrine/schema'
        ));

このコードの最後の部分では二つの機能を実行します。 まずデータベースへの接続を行います。 コードをシンプルにするために接続情報はハードコーディングしてあります。 より現実的なシステムにおいてはZend_Configなどを使うことになるでしょう。方法についてはここでは説明しませんので各自でトライしてみてください。 次の部分ではDoctrineのコマンドラインツールへのパスを設定しています。(このツールは必要なコードとデータベーススキーマすべてを生成します。) 情報を含んだ配列をZend_Registryに登録します。Zend_Registryはオブジェクトをストアするために汎用的に用いられます。オブジェクトをそこへ保管し後から必要になった時に取り出すことができます。
接続情報の部分については各自のシステムに合わせて修正してください。 データベースは空のものを指定する必要があります。 後でそのデータベースに中身を入れます。
application/bootstrap.php には余分なコードを入れないでください。 繰り返しになりますが、このアプリケーションはできるだけシンプルにしてあります。
いよいよDoctrineのコマンドラインツールをセットアップします。

scripts/doctrine-cli

#!/usr/bin/env php
<?php
require dirname(__FILE__).'/../application/global.php';
$cli = new Doctrine_Cli(Zend_Registry::get('doctrine_config'));
$cli->run($_SERVER['argv']);

次のコマンドでスクリプトを実行可能な状態にしてください。

chmod +x scripts/doctrine-cli

これでツールを使えるようになります。

アプリケーションの作成

土台となるコードの準備ができました。ではZendFrameworkとDoctrineを使用した簡単なアプリケーションを作っていきましょう。 書き込みと閲覧を行うとてもシンプルなメッセージボードです。
このアプリケーションはコントローラ一つとビュースクリプトが一つだけという非常に単純な構造です。 次のコードをコピーしてください。

application/views/scripts/index/index.phtmlf

<html>
<head>
    <title>ZF & Doctrine example</title>
</head>

<body>
<h1>Submit a message:</h1>
<?=$this->form?>

<hr />
<h1>Messages posted:</h1>
<!-- TODO: ここにメッセージを表示 -->
</body>
</html>

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $form = $this->getForm();
        $req = $this->getRequest();
        if ($req->getPost() && $form->isValid($req->getPost())) {
            // TODO: データベースにメッセージ書き込む
        }
        $this->view->form = $form;

        // TODO: メッセージを全件取得
    }

    private function getForm()
    {
        $form = new Zend_Form();
        $form->addElement('text', 'name', array(
                    'label' => 'Your name',
                    'required' => true
                    ));
        $form->addElement('textarea', 'message', array(
                    'label' => 'Message',
                    'required' => true,
                    'rows' => 4
                    ));
        $form->addElement('submit', 'send');
        return $form;
    }
}
?>

コードの中に全部で3つのTODOアイテムがあるのに気づきましたか。ビュースクリプトに1つとコントローラに2つあります。 この部分にDoctrineを呼び出すためのコードを入れます。 そうするためにはまずデータオブジェクトをいくつか定義する必要があります。 このTODOの部分はあとで処理することにして、まずはデータベースのスキーマを作ります。

スキーマの定義

Doctrineではスキーマ定義にシンプルなテキスト構造であるYAMLを使うことができます。 これを使うとDoctrineがPHPスクリプトを自動で生成してくれます。 スキーマ定義は次のようになります。
application/doctrine/schema/schema.yml

---
Message:
    columns:
        id:
            primary: true
            autoincrement: true
            type: integer(4)
        posted:
            type: timestamp
        name:
            type: string(255)
        message:
            type: string

このアプリケーションで必要になるのはMessageという名前の非常にシンプルなオブジェクト一つでだけです。Messageはユニークid、メッセージが投稿された時のタイムスタンプ、投稿者の名前、メッセージ本文という4つのカラムからなります。
Doctrineのコマンドラインツールを用いてモデルとDBテーブル定義を生成しましょう。 シェルから次のコマンドを実行してください。

$ ./scripts/doctrine-cli generate-models-yaml
generate-models-yaml - Generated models successfully from YAML schema
$ ./scripts/doctrine-cli generate-sql
generate-sql - Generated SQL successfully for models
$ ./scripts/doctrine-cli create-tables
create-tables - Created tables successfully

正しく実行されれば何もエラーメッセージは表示されません。 もしエラーメッセージが出るようならデータベースへの接続が正しくセットアップされているか確かめてください。

統合する

先ほど残したTODOアイテムを片付けましょう。 一つずついきます。 完成したコードは記事の末尾に載せてありますので参照してください。 まずにメッセージを保存するためのコードです。 この部分を

// TODO: データベースにメッセージを書き込む

次のようにしてください。<?php?> は省略してあります。

$message = new Message();
$message->fromArray($form->getValues(true));
$message->posted = new Doctrine_Expression('NOW()');
$message->save();

Messageというクラスが使われています。 このクラスはDoctrineによって自動生成されたものです。 application/models/の中にあります。 オートローダが必要なクラスを自動でロードしてくれます。
メッセージを表示するためにそれを取得する必要があります。 まずはコントローラです。

// TODO: メッセージを全件取得

を次のコードで置き換えてください。

messages = Doctrine_Query::create()
             ->from('Message m')
             ->orderBy('m.posted DESC')
             ->execute();
$this->view->messages = $messages;

これも非常にシンプルです。 DQLを使って投稿時間の新しいものから表示されるようにソートしてあります。
あとは取得したメッセージレコードをビュースクリプトに表示させるだけです。

<!-- TODO: ここにメッセージを表示 -->

を次のコードで置き換えてください。
<?php foreach ($this->messages as $message): ?>
    <h2><?=$message->name?> (<?=$message->posted?>)</h2>
    <?=$message->message?>
<?php endforeach; ?>

できました。表示結果はこのようになります。

完成したアプリケーション

finished application Zend FrameworkとDoctrineを組み合わせる

このアプリケーションを公開して運用することは避けてください。今回は重要なポイントだけに絞ったので入力値のエスケープなどは省略してあります。 自分で組み込んでみてください。

まとめ

これでZendFrameworkとDoctrineを使ってクリーンでシンプルなアプリケーションを作ることができました。 両フレームワークは同様の設計思想を持っているので非常に美しく統合することが可能なのです。そのためアプリケーション開発はとても楽しいものになります。
意見/コメント/質問があれば(ruben@savanne.be) にメールしてください。あるいは 私のブログにコメントしてください。.

付録: コードの入手について

コードのコピー&ペーストを行いたくなければGitを使ってください。 修正前のTODOアイテムが残っているバージョンと完成したバージョンの両方をオンラインのGitレポジトリに置きました。 以下に入手方法を示します:

  • リポジトリのクローンを作る: git clone git://git.savanne.be/git/chatapp.git これで修正前のコードを入手できます。
  • 修正後のバージョンが欲しい場合は次のコマンドを実行してください: git checkout -b finished-version origin/finished-version
  • 両方のバージョンの間を移動する場合はgit checkout master (修正前のバージョン) 、そして git checkout finished-version (修正後のバージョン)を実行してください。

付録: 完成したコード

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $form = $this->getForm();
        $req = $this->getRequest();
        if ($req->getPost() && $form->isValid($req->getPost())) {
            $message = new Message();
            $message->fromArray($form->getValues(true));
            $message->posted = new Doctrine_Expression('NOW()');
            $message->save();
        }
        $this->view->form = $form;

        $messages = Doctrine_Query::create()
                    ->from('Message m')
                    ->orderBy('m.posted DESC')
                    ->execute();
        $this->view->messages = $messages;
    }

    private function getForm()
    {
        $form = new Zend_Form();
        $form->addElement('text', 'name', array(
                    'label' => 'Your name',
                    'required' => true
                    ));
        $form->addElement('textarea', 'message', array(
                    'label' => 'Message',
                    'required' => true,
                    'rows' => 4
                    ));
        $form->addElement('submit', 'send');
        return $form;
    }
}
?>

application/views/scripts/index/index.phtml

<html>
<head>
    <title>ZF & Doctrine example</title>
</head>

<body>
<h1>Submit a message:</h1>
<?=$this->form?>

<hr />
<h1>Messages posted:</h1>
<?php foreach ($this->messages as $message): ?>
    <h2><?=$message->name?> (<?=$message->posted?>)</h2>
    <?=$message->message?>
<?php endforeach; ?>
</body>
</html>

Home > Tags > Doctrine

アーカイブ

Return to page top