メニュー

ドキュメント

はじめに

 クイックスタートとして簡易掲示板を作成してみます。 簡易掲示板では書き込みを行う際に確認ページを表示します。



プロジェクトの作成

 s2base コマンドでプロジェクトを作成します。

  • プロジェクトディレクトリ : /seasar.php/sample/start
  • Base URL : http://localhost/keijiban/
% s2base /seasar.php/sample/start zf
・・・
%

.htaccess の編集

 上記で作成したプロジェクトディレクトリの /seasar.php/sample/start/public ディレクトリを WEB サーバで 公開します。Base URLを「 /keijiban 」としたので、publicディレクトリにある .htaccess で RewriteBase を設定します。

  /seasar.php/sample/start/public/.htaccess

RewriteEngine on
RewriteBase /keijiban            <--- 追記
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ z.php/$1

モジュールとコントローラを生成する

 掲示板用のモジュールとコントローラを生成します。

  • モジュール : 使用しない ( default )
  • コントローラ : index
% cd /seasar.php/sample/satrt
% phing
・・・
[ Command list ]
0 : (exit)
1 : action
2 : dao
3 : entity
4 : goya
5 : interceptor
6 : model
7 : module & controller
8 : service
choice ? : 7                 <-- モジュール作成コマンドを選択

[ Module list ]
0 : (exit)
1 : (new module)
2 : default
choice ? : 2                 <-- default モジュールを選択

controller name ? : index    <-- コントローラ名を index とします。

[ generate information ]
  module name               : default
  controller name           : index
  controller class name     : IndexController
  controller interface name : IndexService

confirm ? (y/n) : y
・・・
[ Command list ]
0 : (exit)
・・・
choice ? : 0

%

index コントローラにアクセスする

 http://localhost/keijiban/index をブラウザで閲覧すると、次のような index ページが表示されます。


データベースのセットアップ

 データベースには Sqlite を使用します。次のような keijiban テーブルを作成します。 作成するデータベースファイルは、プロジェクトディレクトリの var ディレクトリに保存します。

  create table keijiban (
    id        integer primary key,
    name      text,
    comment   text,
    timestamp text
  );
  insert into keijiban values(1, 's2base_zf', 'quick start document', '2000-01-01 00:00:00');

データベースの作成

% cd /seasar.php/sample/start/var
% sqlite start.db
SQLite version 3.3.14
Enter ".help" for instructions
sqlite> create table keijiban (
   ...>   id        integer primary key,
   ...>   name      text,
   ...>   comment   text,
   ...>   timestamp text
   ...> );
sqlite> insert into keijiban values(1, 's2base_zf', 'quick start document', '2000-01-01 00:00:00');
sqlite>                   *** サンプルデータを 1つ用意して下さい ***
%

PDO ダイコンの設定

 上記で作成した start.db を pdo.dicon ファイルに設定します。 pdo.dicon ファイルは、プロジェクトディレクトリの app/commons/dicon/pdo.dicon にあります。 デフォルトでは、MySQL用の dataSource コンポーネントが有効となっています。MySQL用の設定はコメントアウトし、 次の設定に置き換えます。

  <component name="dataSource" class="S2Container_PDODataSource">
    <property name="dsn">return 'sqlite:' . S2BASE_PHP5_ROOT . '/var/start.db'</property>
  </component>

トップページの作成

Goya コマンド

 掲示板のトップページを アクション名 : top として goya コマンドで作成します。

% phing
・・・
[ Command list ]
0 : (exit)
1 : action
2 : dao
3 : entity
4 : goya
5 : interceptor
6 : model
7 : module & controller
8 : service
choice ? : 4                  <-- goya コマンドを選択

[ Module list ]
0 : (exit)
1 : default
choice ? : 1                  <-- モジュールを選択

[ Controller list ]
0 : (exit)
1 : index
choice ? : 1                  <-- コントローラを選択

action name ? : top           <-- アクション名を top とします。

use dao ? (y/n) : y           <-- データベースにアクセスするので yes

use database ? (y/n) : y      <-- データベースから情報を取得するので yes

[ table list ]
0 : (exit)
1 : keijiban
choices ? (1,2,--,) : 1       <-- テーブルを選択

dao interface name [KeijibanDao]? :         <-- dao 名を入力します。デフォルトの場合はリターンのみ

entity class name ? [KeijibanEntity] :      <-- entity 名を入力します。デフォルトの場合はリターンのみ

[ generate information ]
  module name             : default
  controller name         : index
  action name             : top
  format action name      : Top
  action method name      : topAction
  action dicon file name  : topAction.dicon
  action template file    : top.html
  service interface name  : TopService
  service class name      : TopServiceImpl
  service test class name : TopServiceImplTest
  service dicon file name : TopServiceImpl.dicon
  dao interface name      : KeijibanDao
  dao test class name     : KeijibanDaoTest
  entity class name       : KeijibanEntity
  table name              : keijiban
  columns                 : id, name, comment, timestamp

confirm ? (y/n) : y
・・・

[ Command list ]
0 : (exit)
・・・
choice ? : 0

%

 http://localhost/keijiban/index/top をブラウザで閲覧すると、次のような トップページが表示されます。
サンプルで入力したデータが表示されます。

一覧表示

 goya コマンドで自動生成されたテンプレートファイルを編集して、名前と時間とコメントを表示します。 自動生成されたテンプレートファイルは、app/modules/index/view/top.html になります。次のようなテーブル表示に置き換えます。

<tbody>
{foreach from=$dtos item=row}
<tr><td>Name: {$row->getName()|escape} Date: {$row->getTimestamp()|escape}</td></tr>
<tr><td><pre>{$row->getComment()|escape}</pre><br></td></tr>
{/foreach}
</tbody>

 http://localhost/keijiban/index/top をブラウザで再度閲覧すると、次のような トップページが表示されます。

入力フォームの追加

 トップページに次のような名前とコメントを入力するフォームを追記します。

<form action="{$ctl_url}/insert-confirm">
<table class="list"><tbody>
<tr><td>
Name: <input type="text" name="handle" value="" maxlength="10"/>
<input type="submit"/>
</td></tr>
<tr><td>
Comment: <br><textarea name="comment" cols="50" rows="2"></textarea>
</td></tr>
</tbody></table>
</form>

 http://localhost/keijiban/index/top をブラウザで再度閲覧すると、次のような トップページが表示されます。


確認ページの作成

 入力フォームのアクションに設定したアクション名 : insert-confirm で Action コマンドを実行します。

Action コマンド

% phing
・・・
[ Command list ]
0 : (exit)
1 : action
2 : dao
3 : entity
4 : goya
5 : interceptor
6 : model
7 : module & controller
8 : service
choice ? : 1                  <-- アクションコマンドを選択

[ Module list ]
0 : (exit)
1 : default
choice ? : 1                  <-- モジュールを選択

[ Controller list ]
0 : (exit)
1 : index
choice ? : 1                  <-- コントローラを選択

action name ? : insert-confirm    <-- アクション名を入力

[ generate information ]
  module name           : default
  controller name       : index
  controller class name : IndexController
  action name           : insert-confirm
  action method name    : insertConfirmAction
  action dicon file     : insertConfirmAction.dicon
  action template file  : insert-confirm.html

confirm ? (y/n) : y
・・・

[ Command list ]
0 : (exit)
・・・
choice ? : 0

%

この状態で、入力フォームの Submit ボタンを選択すると、 insert-confirm アクションのテンプレートファイルが表示されます。

アクションメソッドの編集

 module & controller コマンドで作成されたアクションコントローラファイルは、 app/modules/default/IndexController.php になります。 IndexController.php には insertConfirmAction メソッドが追加されているので、insertConfirmAction メソッドを実装します。

class IndexController extends Zend_Controller_Action {
    ・・・
    public function insertConfirmAction(){
        $dto = new KeijibanEntity();                                // DTOを生成し、
        $dto->setName($this->getRequest()->getParam('handle'));     // リクエストパラメータをセットします。
        $dto->setComment($this->getRequest()->getParam('comment')); 
        $this->view->assign('dto', $dto);                           // ビューに DTO をセットします。
        $sn = new Zend_Session_Namespace('start_insert');           // セッションにも DTO を保存します。
        $sn->dto = $dto;
    }
    ・・・
}

テンプレートファイルの編集

 入力フォームで受け取った情報を表示する確認ページを作成します。

<form action="{$ctl_url}/insert">
<table class="list">
<tbody>
<tr><td>Name: {$dto->getName()|escape} <input type="submit"/></td></tr>
<tr><td>Comment: <br><pre>{$dto->getComment()|escape}</pre></td></tr>
</tbody>
</table>
</form>

この状態で入力フォームの Submit ボタンを選択すると、次のような確認画面が表示されます。

リクエストの検証

 入力フォームからのリクエストデータを検証します。設定ファイルはコントローラディレクトリの validate ディレクトリに アクション名.ini ファイルで生成されています。insert-confirm.ini に次のような設定を記述します。

  app/modules/default/index/validate/insert-confirm.ini

[default]
action = "top"            <-- 検証に失敗した場合のアクションを top とします。

[handle : default]        <-- handle パラメータの設定セクション
validate = "regex"
regex.pattern = "/^\w{1,10}$/"

[comment : default]       <-- comment パラメータの設定セクション
validate = "regex"
regex.pattern = "/^.{1,100}$/s"
検証に失敗した場合はトップページに遷移します。

検証エラーの表示

 リクエストパラメータの検証に失敗した場合にトップページに遷移します。トップページの先頭に次のように 検証エラーを表示します。検証エラーは、$errors['validate'] 配列に設定されています。

<font color="red">
  {foreach from=$errors.validate item=val key=key}
    {$key|escape} : {$val.msg|escape}
  {/foreach}
</font>

 handle パラメータに「 Seasar.PHP 」と入力した場合は、次のような検証エラーメッセージが表示されます。


データベースに保存

 確認フォームのアクションに設定したアクション名 : insert で Goya コマンドを実行します。

Goya コマンド

% phing
・・・

[ Command list ]
0 : (exit)
1 : action
2 : dao
3 : entity
4 : goya
5 : interceptor
6 : model
7 : module & controller
8 : service
choice ? : 4                  <-- goya コマンドを選択

[ Module list ]
0 : (exit)
1 : default
choice ? : 1                  <-- モジュールを選択

[ Controller list ]
0 : (exit)
1 : index
choice ? : 1                  <-- コントローラを選択

action name ? : insert        <-- アクション名を入力

use dao ? (y/n) : y           <-- データベースにアクセスするので yes

use database ? (y/n) : y      <-- データベースから情報を取得するので yes

[ table list ]
0 : (exit)
1 : keijiban
choices ? (1,2,--,) : 1       <-- テーブルを選択

dao interface name [KeijibanDao]? :       <-- dao 名を入力。デフォルトの場合はリターン

entity class name ? [KeijibanEntity] :    <-- entity 名を入力。デフォルトの場合はリターン

[ generate information ]
  module name             : default
  controller name         : index
  action name             : insert
  format action name      : Insert
  action method name      : insertAction
  action dicon file name  : insertAction.dicon
  action template file    : insert.html
  service interface name  : InsertService
  service class name      : InsertServiceImpl
  service test class name : InsertServiceImplTest
  service dicon file name : InsertServiceImpl.dicon
  dao interface name      : KeijibanDao
  dao test class name     : KeijibanDaoTest
  entity class name       : KeijibanEntity
  table name              : keijiban
  columns                 : id, name, comment, timestamp

confirm ? (y/n) : y
・・・

[ Command list ]
0 : (exit)
・・・
choice ? : 0

%

データの保存

Dao の編集

 Goya コマンドにより KeijibanDaoクラスファイルが コントローラディレクトリの dao ディレクトリに生成されています。 KeijibanDaoクラスに insert メソッドを追加します。

  app/modules/default/index/dao/KeijibanDao.php

interface KeijibanDao {
    const BEAN = "KeijibanEntity";
    public function findAllList();
    public function insert(KeijibanEntity $entity);
}

Service の編集

 Goya コマンドにより InsertServiceInsertServiceImplクラスファイルが コントローラディレクトリの service ディレクトリに生成されています。 insert メソッドの定義と実装を追加します。また、デフォルトで getWithLimit メソッドが用意されていますが削除します。

  app/modules/default/index/service/InsertService.php
  app/modules/default/index/service/InsertServiceImpl.php

interface InsertService {
    public function insert(KeijibanEntity $dto);
}

class InsertServiceImpl 
    ・・・
    public function insert(KeijibanEntity $dto) {
        $this->keijibanDao->insert($dto);
    }
    ・・・
}

トップページにリダイレクト

 Goya コマンドにより、IndexController クラスに insertAction メソッドが追加されています。insertAction メソッドでは、上記の InsertServiceImpl クラスを用いて データをデータベースに保存します。その後、トップページにリダイレクトします。

  app/modules/default/IndexController.php

class IndexController extends Zend_Controller_Action {
    ・・・
    public function insertAction() {
        $sn = new Zend_Session_Namespace('start_insert');  // セッションからDTOを取得して
        $this->service->insert($sn->dto);             //    データベースに保存します。
        Zend_Session::destroy();                           // セッションを破棄します。
        $this->_redirect("/{$this->getRequest()->getControllerName()}/top");
    }                        // トップページにリダイレクトします。
    ・・・
}

全件表示する

 ここまでの作業で、掲示板に書き込むことができるようになりました。掲示板に書き込む際には確認ページが表示され、 データを登録するとトップページが表示されます。また、Goya コマンドのデフォルト動作として、データベースから取得した データの最初の10件が表示されます。
全件表示するためには、次のように IndexContrller クラスの topAction メソッドを編集します。

class IndexController extends Zend_Controller_Action {
    ・・・
    public function topAction() {
        $this->view->assign('dtos', $this->service->getWithLimit(-1));
    }
    ・・・
}

ワンポイント

keijiban テーブルの timestamp カラム

 keijiban テーブルの timestamp カラムは、S2Dao.PHP5 の「Timestampによる排他制御」 の機能を利用してタイムスタンプを自動的に保存しています。

UnitTest の実行

 top アクションと insert アクションを Goya コマンドで生成した際に、それぞれの Dao と Service 用の UnitTest がテストディレクトリに作成されています。UnitTest の実行は次のように phing コマンドにサブタスクオプション( -Dst=test )を指定して実行します。

% phing zf -Dst=test
・・・
project > test:

     [echo] test directory : test/
     [echo] test target : **/*Test*.php
KeijibanDaoTest::testA

 [phpunit2] Testsuite: KeijibanDaoTest
 [phpunit2] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.19843 sec
InsertServiceImplTest::testA

 [phpunit2] Testsuite: InsertServiceImplTest
 [phpunit2] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.05006 sec
TopServiceImplTest::testA

 [phpunit2] Testsuite: TopServiceImplTest
 [phpunit2] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.02700 sec

・・・
%

 KeijibanDaoTestクラスに次のようなメソッドを追加して、KeijibanDao の動作を確認できます。

  test/modules/default/index/dao/KeijibanDaoTest.php

class KeijibanDaoTest extends PHPUnit2_Framework_TestCase {
・・・
    function testFindAllList() {
        $dtos = $this->dao->findAllList();
        foreach ($dtos as $dto) {
            print $dto;
        }
    }
・・・
}

 テストターゲットオプション( -Dtt )を指定してテストを実行します。

% phing zf -Dst=test -Dtt=**/*Dao*
・・・
project > test:

     [echo] test directory : test/
     [echo] test target : **/*Dao*
KeijibanDaoTest::testFindAllList
{id => 1, name => s2base_zf, comment => quick start document, timestamp => 2000-
01-01 00:00:00}{id => 2, name => s2php5, comment => s2container.php5
s2dao.php5, timestamp => 2007-01-01 00:00:00}
 [phpunit2] Testsuite: KeijibanDaoTest
 [phpunit2] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.17970 sec

・・・
%

一覧表示のソート

 S2Dao.PHP5の「SQLファイル」を用いて、トップページの一覧を最新の項目順で表示してみます。次のような sql ファイルを作成します。

  app/modules/default/index/dao/KeijibanDao_findAllList.sql

select * from keijiban order by timestamp desc

 再度、トップページを閲覧すると次のようにタイムスタンプの新しい順で一覧が表示されます。


 また、SQLファイルに LIMIT 句を追記して、一覧表示する件数を指定できます。

select * from keijiban order by timestamp desc limit 1

 再度、トップページを閲覧すると次のように 1 件だけ表示されます。