Zend Framework入門

第2章 Zend Frameworkの基本

前へ | 目次へ |次へ  | Yamada-Lab

2.4 Smartyの基本

■Smartyのインストール

 smartyは以下のURIからダウンロードが出来ます。2009/03/24時点での最新版は2.6.22です。

http://smarty.php.net/download.php

 ここでは、Windows環境にインストールするので、「(.zip)」をクリックします。引き続き「保存」ボタンをクリックします。「Smarty-2.6.22.zip」ファイルを任意のフォルダにダウンロードし、解凍します。

 解凍されたファイル群の中の「libs」フォルダをPHPのインクルードパスが通っているフォルダにコピーし、フォルダ名を「Smarty」に変更します。ここでは、コピー先のフォルダは「c:\PHP5\includes\Smarty\」になります。

 PHPのインクルードパスに追加するには、php.iniファイルの「include_path=」の行に以下のように、「;c:\php5\includes」を追加し、Apacheを再起動します。

include_path=".;c:\php5\pear;c:\ZendFramework\library\;c:\php5\includes"

Apache2.2の場合は、\Apache2.2\binをカレントディレクトリにして、以下の再起動コマンド「httpd -k restart」を入力します。

■Smartyの環境設定

 Smartyを利用するためには、以下のフォルダを任意の場所に作成しておく必要があります。

templates     テンプレートファイルの格納先
templates_c    コンパイル済テンプレートの格納先

 ここでは、とりあえずドキュメントルートディレクトリの下に作成することとします。

c:\Apache2.2\htdocs
  \templates
  \templates_c

■Smartyの動作確認

 以下のPHPファイルsmarty.phpと、Smartyテンプレートファイルtest.tplを作成し、アクセスします。

c:\Apache2.2\htdocs\smarty.php

<?php
require_once "Smarty/Smarty.class.php";
$message = "今日は、Smarty!";
$smarty = new Smarty;
$smarty->template_dir = "./templates";
$smarty->compile_dir = "./templates_c";
$smarty->assign("message",$message);
$smarty->display("test.tpl");

c:\Apache2.2\htdocs\template\test.tpl

<head>
<title>Smarty test</title>
</head>
<body>
{$message}
</body>
</html>

 「http://localhost:8080/smarty.php」にアクセスし、以下のように表示されれば、Smartyのインストールと環境設定はOKです。

■Smartyを使わない電話帳入力アプリケーション

 Smartyを使わないアプリケーションとSmartyを使ったアプリケーションの対比の例として、第3章で示した電話帳管理(admin_tel)アプリケーションのうちの開始画面と電話帳データ入力画面からのみなる電話帳入力(input_tel)アプリケーションを以下に示します。

c:\Apache2.2\htdocs\zf\db\23
  .htaccess          
  index.php   
       
c:\Apache2.2\zendapps\db
  zend.ini
  \23
    \controllers        
      IndexController.php   
    \models   
      DbManager.class.php
      TelModel.class.php     
    \views           
      \scripts        
        \index     
          index.phtml   
          pre-insert.phtml

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル

アプリケーションディレクトリ
設定ファイル
アプリケーションルートディレクトリ
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ
データベース接続用クラス
電話帳モデル
ビュー関連ディレクトリ
ビュースクリプトディレクトリ
デフォルトアクションコントローラ用ディレクトリ
初期画面用ビュースクリプト
入力画面用ビュースクリプト

 MVCモデルにおける相互関連は次のようになります。

アクションコントローラ/アクション(C) モデル(M) ビュー(V)
(->:フォアワード)
概要
index/index searchAllTel index/index.phtml 開始画面表示
index/pre-insert なし index/pre-insert.phtml 電話帳データ入力画面表示
index/insert insertTel

・入力データOK
 ->index/index
・入力データエラー
 ->index/pre-insert

・入力データOK
 電話帳データ登録

 デフォルトアクションコントローラ(C)IndexControllerは次のとおりです。バリデータ関連でrequiredCheckメソッド、regexCheckメソッド、CheckErrorメソッドを新たに定義して、実用向けにコンパクト化しています。

c:\Apache2.2\zendapps\zf\db\23\controllers\IndexController.php

<?php
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';
// デフォルトアクションコントローラクラスを生成
class IndexController extends Zend_Controller_Action {
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
    // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
  }

  // デフォルト(index/index)アクションの定義
  public function indexAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $this->view->msg = $msg;
    // 電話帳全データを取得
    $result = $this->_tel->searchALLTel();
    // 電話帳全データをビュー変数に設定
    $this->view->result = $result;
    // 電話帳管理初期画面表示
    // (index/index.phtml)
  }

  // 入力(index/pre-insert)アクションの定義
  public function preInsertAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $errorMsgAll = $request->getUserParam('errorMsgAll');
    //var_dump($_errorMsgAll);
    // エラーメッセージをビュー変数に設定
    $this->view->errorMsgAll = $errorMsgAll;
    // フォアワード後のPOSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // 受信データをビュー変数に設定
    $this->view->var = $this->_var;
    // 電話帳データ入力画面表示
    // (index/input.phtml)
  }

  // 登録(index/insert)アクションの定義
  public function insertAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "登録") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // inputアクションにフォアワード
        $this->_forward('input');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを登録
        $num = $this->_tel->insertTel($this->_var);
        $request->setParam('msg',"{$num}レコードを登録しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
      $this->_forward('index');
    }
  }

  // データ受信
  public function getData() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    if($request->getPost('tel_id') != NULL) {
      $this->_var['tel_id']
         = stripslashes($request->getPost('tel_id')) ;
    }
    $this->_var['name'] = stripslashes($request->getPost('name')) ;
    $this->_var['tel_number']
       = stripslashes($request->getPost('tel_number')) ;
    return;
  }

  // 受信データのチェック
  public function checkData() {
    // POSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // バリデータチェック
    $this->requiredCheck($this->_var['name'],'氏名');
    $this->requiredCheck($this->_var['tel_number'],'電話番号');
    $this->regExCheck($this->_var['tel_number'],'/^[0-9-]+$/','電話番号');
  }

  // 入力値の必須チェックを行う
  public function requiredCheck($value,$varName) {
    
// Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/NotEmpty.php';
    
// バリデータのインスタンスを生成する
    $validate = new Zend_Validate_NotEmpty();
    $validate->setMessage("{$varName}は必須入力です");
    $this->checkError($validate,$value);
  }
 
 // 入力値の正規表現チェックを行う
  public function regExCheck($value,$pattern,$varName) {
    
// Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/Regex.php';
    
// バリデータのインスタンスを生成する
    $validate = new Zend_Validate_Regex($pattern);
    $validate->setMessage("{$varName}を正しい形式で入力してください");
    $this->checkError($validate,$value);
  }
 
 // 個々のバリデータによるエラーチェックを行いエラーメッセージを格納する
  public function checkError($validate,$value) {
    if(!$validate->isValid($value)) {
      foreach($validate->getMessages() as $msg) {
        $this->_errorMsg[] = $msg;
      }
    }
  }

}

 電話帳モデル(M)telModelは次のとおりです。

c:\Apache2.2\zendapps\zf\db\23\models\TelModel.class.php

<?php
// 電話帳モデルをクラスとして定義
class telModel {
  // データベースアダプタ用メンバー変数を定義
  private $_db;

  // コンストラクタの定義
  public function __construct() {
    // データベースへの接続
    $this->_db = DbManager::getConnection();
  }

  // 登録メソッドの定義
  public function insertTel(&$tel) {
    // insertメソッド(戻り値は入力レコード数)
    $num = $this->_db->insert(
                 'tbl_tel'             // テーブル名
                 ,array('name'=>$tel['name']    // 入力データ
                 ,'tel_number'=>$tel['tel_number']
                 ,'updated'=>$tel['updated'])
                     );
     return $num;
  }

  // 全レコード検索メソッドの定義
  public function searchAllTel() {
    // Zend_Db_Selectオブジェクトを生成
    $sel = $this->_db->select();
    // FROM句の追加
    $sel->from('tbl_tel','*');
    // ORDER句の追加
    $sel->order('updated desc' );
    // クエリを実行
    $stt = $this->_db->query($sel);
    // 結果取得
    $result = array();
    while($row = $stt->fetch()) {
      array_push($result,$row);
    }
    return $result;
  }
}

 ビュースクリプト(V)index/index.phtmlとindex/pre-insert.phtmlは次のとおりです。

c:\Apache2.2\zendapps\zf\db\23\views\script\index\index.phtml

<html>
<head>
<title>input_tel</title>
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
-->
</style>
</head>
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
<?php if($this->msg != "") {
  print $this->msg;
}
?>
<table border="0" width="100%">
 <tr>
  <form method="POST" action="<?php print BASE_DIR ?>index/pre-insert">
  <td>
   <input type="submit" name="command" value="新規">
  </td>
  </form>
 </tr>
</table>

<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
 <?php foreach ($this->result as $rows) { ?>
 <tr>
  <td><?php print $rows['tel_id']; ?></td>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td><?php print $this->escape($rows['name']); ?></td>
  <td><?php print $this->escape($rows['tel_number']); ?></td>
  <td><?php print $rows['updated']; ?></td>
 </tr>
<?php } ?>
</table>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\23\views\script\index\pre-insert.phtml

<html>
<head>
<title>input_tel</title>
</head>
<body>
<!-- index/insertアクションにPOSTデータを送信-->
<p style="color:red"><?php print($this->errorMsgAll); ?></p>
<form method="POST" action="<?php print BASE_DIR ?>index/insert">
<table border="0">
 <tr>
  <th>氏名</th>
  <td><input type="text" name="name" size="10"
     value="<?php print $this->var['name'] ?>"></td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td><input type="text" name="tel_number" size="10"
     value="<?php print $this->var['tel_number'] ?>"></td>
 </tr>
 <tr>
  <th></th>
  <td><input type="submit" name="command" value="登録">
   <input type="reset" value="リセット">
   <input type="submit" name="command" value="キャンセル">
  </td>
 </tr>
</table>
</form>
</body>
</html>

■Smartyを使った電話帳入力アプリケーション

 Smartyを使った電話帳入力(input_tel)アプリケーションを以下に示します。

c:\Apache2.2\htdocs\zf\db\24
  .htaccess          
  index.php   
       
c:\Apache2.2\zendapps\db
  zend.ini
  \24
    DbManager.class.php
    MySmarty.class.php
    \controllers        
      IndexController.php   
    \models   
      TelModel.class.php     
    \templates           
      index.tpl   
      pre-insert.tpl
    \templates_c          

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル

アプリケーションディレクトリ
設定ファイル
アプリケーションルートディレクトリ
データベース接続用クラス
MySmartyクラス
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ
電話帳モデル
テンプレート用ディレクトリ
初期画面用テンプレート
入力画面用テンプレート
コンパイル済みテンプレート用ディレクトリ

 Smartyを利用するには、Smartyを継承したMySmartyクラスを定義して利用するのが一般的です。これは、後に示すようにたとえばSmarty用のテンプレート格納ディレクトリ「template」は、Smartyそのものは、アプリケーションやコントローラ/アクションにかかわらず1箇所しか持っていないため、その管理をMySmartyクラスのようなSmarty派生クラスに委ねコーディングや管理の柔軟性を保持するためです。

 ただ、ここでは、テンプレート格納ディレクトリ等は、アクション/メソッドを意識することなくアプリケーションルートディレクトリ(定数APP_DIRに設定)に置くこととします。

c:\Apache2.2\zendapps\zf\db\24\MySmarty.class.php

<?php
// Smartyコンポーネント(クラス)のロード
require_once 'Smarty/Smarty.class.php';

// MySmartyクラスの定義
class MySmarty extends Smarty {
  public function __construct() {
    
// 親クラスであるSmartyクラスのコンストラクタを呼び出す
    $this->Smarty();
    $this->template_dir = APP_DIR . "templates/";
    $this->compile_dir = APP_DIR . "templates_c/";
  }
}

 このMySmartyクラスのロードはフロントコントローラindex.phpで行っておきます。

c:\Apache2.2\htdocs\zf\db\24\index.php

<?php
//アプリケーションルートパスの定義
define('APP_DIR','../../../../zendapps/db/24/');
//公開ディレクトリの定義
define('BASE_DIR','/zf/db/24/');
//フロントコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Front.php';
//アクションコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Action.php';
//データベース接続クラス(ユーザ定義)のロード
require_once APP_DIR . 'DbManager.class.php';
// MySmartyクラス(ユーザ定義)のロード
require_once APP_DIR . 'MySmarty.class.php';
/**フロントコントローラのインスタンスの取得
*コントローラのフォルダ指定
*ディスパッチ
*/
Zend_Controller_Front::run(APP_DIR . 'controllers');

 Smartyを使った場合のデフォルトアクションコントローラ(C)IndexControllerの例は次のとおりです。

c:\Apache2.2\zendapps\zf\db\24\controllers\IndexController.php

<?php
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';
// デフォルトアクションコントローラクラスを生成
class IndexController extends Zend_Controller_Action {
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
    // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
    // 自動レンダリングモードの無効化
    $this->_helper->ViewRenderer->setNoRender();
  }

  // デフォルト(index/index)アクションの定義
  public function indexAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // 電話帳全データを取得
    $result = $this->_tel->searchALLTel();
    // 電話帳全データをビュー変数に設定
    $smarty->assign('result',$result);
    // 電話帳管理初期画面表示
    $smarty->display("index.tpl");
  }

  // 入力(index/pre-insert)アクションの定義
  public function preInsertAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $errorMsgAll = $request->getUserParam('errorMsgAll');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('errorMsgAll',$errorMsgAll);
    // フォアワード後のPOSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // 受信データをビュー変数に設定
    $smarty->assign('var',$this->_var);
    // 電話帳データ入力画面表示
    $smarty->display("input.tpl");
  }

  // 登録(index/insert)アクションの定義
  public function insertAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "登録") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // inputアクションにフォアワード
        $this->_forward('pre-insert');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを登録
        $num = $this->_tel->insertTel($this->_var);
        $request->setParam('msg',"{$num}レコードを登録しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
      $this->_forward('index');
    }
  }

  // データ受信
  public function getData() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    // $var = $request->getPost('tel_id');
    if($request->getPost('tel_id') != NULL) {
      $this->_var['tel_id']
         = stripslashes($request->getPost('tel_id')) ;
    }
    $this->_var['name'] = stripslashes($request->getPost('name')) ;
    $this->_var['tel_number']
       = stripslashes($request->getPost('tel_number')) ;
    return;
  }

  // 受信データのチェック
  public function checkData() {
    // POSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // バリデータチェック
    $this->requiredCheck($this->_var['name'],'氏名');
    $this->requiredCheck($this->_var['tel_number'],'電話番号');
    $this->regExCheck($this->_var['tel_number'],'/^[0-9-]+$/','電話番号');
  }

  // 入力値の必須チェックを行う
  public function requiredCheck($value,$varName) {
    // Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/NotEmpty.php';
    // バリデータのインスタンスを生成する
    $validate = new Zend_Validate_NotEmpty();
    $validate->setMessage("{$varName}は必須入力です");
    $this->checkError($validate,$value);
  }

  // 入力値の正規表現チェックを行う
  public function regExCheck($value,$pattern,$varName) {
    // Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/Regex.php';
    // バリデータのインスタンスを生成する
    $validate = new Zend_Validate_Regex($pattern);
    $validate->setMessage("{$varName}を正しい形式で入力してください");
    $this->checkError($validate,$value);
  }
  // 個々のバリデータによるエラーチェックを行いエラーメッセージを格納する
  public function checkError($validate,$value) {
    if(!$validate->isValid($value)) {
      foreach($validate->getMessages() as $msg) {
        $this->_errorMsg[] = $msg;
      }
    }
  }
}

 Smartyを利用する場合は、自動レンダリングモードは使わず、ビュースクリプトの呼び出し(レンダリング)はSmartyで行います。そのためにはZend Frameworkでデフォルトで有効になっている自動レンダリングモードを無効にする必要があります。自動レンダリングモードを無効にする方法は、フロントコントローラで行う方法等いろいろありますが、ここでは、アクションコントローラ側で無効にする柔軟な方法を示します。

 アクションコントローラは自動レンダリングモードを無効に設定するメソッド$this->_helper->ViewRenderer->setNoRender()を持っています。ここでは、各アクションごとに、以下のように自動レンダリングモードを無効に設定

// 自動レンダリングモードを無効に設定
$this->_helper->ViewRenderer->setNoRender();

 各アクション(メソッド)ごとにMySmartyオブジェクト(インスタンス)$smartyを生成します。

 Smartyを使った場合ビュースクリプトへのビュー変数の設定のかわりに、テンプレートへのテンプレート変数の設定をassignメソッドで行います。構文は次のとおりです。$smartyはSmartyの派生オブジェクト(インスタンス)の名称例です。

$smarty->assign('テンプレート変数名',値)      //変数

$smarty->assign('テンプレート配列名',配列)    //配列

 テンプレートファイルの呼び出しおよびレンダリングはdisplayメソッドで行います。構文は次のとおりです。

$smarty->display('テンプレートファイル名')

 Smartyを使っても、モデル(M)は特に変更になりません。これはMVCモデルの各モデル間の独立性によるものです。Smartyはビュー(V)のためのツールであり、データ管理のモデル(M)とは関係ないためです。ただ、コントローラ(C)は上記のようにテンプレート変数の設定とレンダリング(画面表示)を行う必要があります。

 ビュー(V)は、ビュースクリプトの代わりに、Smartyのテンプレートファイルが担当します。input_telアプリケーションでは、index/indexアクションとindex/inputアクションに対応してテンプレートファイルindex.tplとinput.tplを以下のように作成します。

c:\Apache2.2\zendapps\zf\db\24\template\index.tpl

<html>
<head>
<title>admin_tel</title>
{literal}
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
-->
</style>
{/literal}
</head>
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
 {$msg}
{/if}

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}index/input">
  <td>
   <input type="submit" name="command" value="新規">
  </td>
  </form>
 </tr>
</table>
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item="rows"}
 <tr>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
</body>
</html>

 SmartyのスクリプトはHTMLファイルの中にデリミタ「{」、「}」で囲んで記述します。ファイルの拡張子は「.tpl」とします。Smartyでは変数や配列を扱えます。変数や配列は冒頭に「$」を付与します。

 HTMLファイルの中での変数の表示はPHPの場合は、「<?php print $var; ?>」ですが、Smartyの場合は「{$var}」と記述します。

{$変数名}

【例】

<b>{$msg}</b>

 配列の表示場合は、以下の構文となります。

{$配列名[n]}      // 配列

{$連想配列名.キー}   // 連想配列

【例】

{$num[0]}        // $num[0]
{$rows.name}      // $rows['name']

 定数の表示は、以下の構文となります。

{$smarty.const.定数名}

【例】

<form method="POST" action="{$smarty.const.BASE_DIR}index/input">

 HTMLファイルの中にスタイルシートを記述するとその中で「{ }」を使います。そこで、Smartyのデリミタと混乱しないように、スタイルシートのコード全体を{literal}と{/literal}で囲みます。

{literal}
スタイルシートのコード
{/literal}

 Smartyでは、if文も使えます。構文は次のとおりです。

{if 論理式}
  HTMLコード
{/if}

あるいは

{if 論理式}
  HTMLコード
{elseif 論理式}
  HTMLコード
{else}
  HTMLコード
{/if}

【例】

{if $msg != ""}
 {$msg}
{/if}

 foreach文の構文は次のとおりです。fromの項の配列名には「$」をつけますが、itemの項の変数名等には「$」をつけません。ただ、itemの項の変数等を引用する場合は「$」を付加します。

{foreach from=$配列名 item=変数名}
  HTMLコード
{/foreach}

あるいは

{foreach from=$配列名1 item=配列名2}
  HTMLコード
{/foreach}

あるいは

{foreach from=$配列名 key=キー item=変数名}
  HTMLコード
{/foreach}


あるいは

{foreach from=$配列名 item=変数名}
  HTMLコード
{foreachelse}
  (配列が空の場合の処理)
{/foreach}

 配列あるいは配列1の各要素について順次繰り返し処理を行います。たとえば、以下のような例になります。

【例】

<table>
{foreach from=$result item=rows}
  <tr>
    <td>{$rows.name}</td>
    <td>{$rows.tel_number}</td>
  </tr>
{/foreach}
</table>

【例】

<table>
{foreach from=$rows key=label item=value}
  <tr>
    <td>{$label}</td>
    <td>{$value}</td>
  </tr>
{/foreach}
</table>

 Smartyではescape修飾子でサニタイジングも行えます。構文は次のとおりです。

{変数 | escape:'html'}

【例】

<td>{$name|escape:'html'}</td>

c:\Apache2.2\zendapps\zf\db\24\template\pre-insert.tpl

<html>
<head>
<title>input_tel</title>
</head>
<body>
<!-- index/insertアクションにPOSTデータを送信-->
<p style="color:red">{$errorMsgAll}</p>
<form method="POST" action="{$smarty.const.BASE_DIR}index/insert">
<table border="0">
 <tr>
  <th>氏名</th>
  <td><input type="text" name="name" size="10"
        value="{$var.name|escape:'html'}"></td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td><input type="text" name="tel_number" size="10"
        value="{$var.tel_number|escape:'html'}"></td>
 </tr>
 <tr>
  <th></th>
   <td><input type="submit" name="command" value="登録">
     <input type="reset" value="リセット">
     <input type="submit" name="command" value="キャンセル">
   </td>
 </tr>
</table>
</form>
</body>
</html>

 サンプルスクリプトへのアクセス結果は次のとおりです。

 電話番号欄に、使用可能英数字以外の「(」、「)」を使った場合にエラーメッセージが表示されます。

■アクションコントローラごとにテンプレート用ディレクトリ設置

 上記のSmartyを使った電話帳入力(input_tel)アプリケーションでは

$this->template_dir = APP_DIR . "templates/";

としているので、アクションコントローラにかかわらず全てのテンプレートが、「APP_DIR . "templates/"」に格納されることになります。Zend Frameworkでは、アクションコントローラごとにコントローラ名のディレクトリにビュースクリプトを格納しているので、Smartyを使った場合でも、アクションコントローラごとに別のディレクトリにテンプレートファイルを格納した方がZend Frameworkとの親和性がありかつ保守性もよくなります。

 そこで、テンプレートファイルの格納ディレクトリを各アクションコントローラごとに以下のようにすることとします。

APP_DIR . 'views/smarty/templates/アクションコントローラ名/'

 テンプレートファイル用ディレクトリは各アクションメソッド内で動的に指定するようにMySmartyクラスを下記のように変更します。またテンプレートファイル名もビュースクリプトファイルの場合と同様アクション名と同じにします。

c:\Apache2.2\zendapps\zf\db\25\MySmarty.class.php

<?php
// Smartyコンポーネント(クラス)のロード
require_once 'Smarty/Smarty.class.php';

// MySmartyクラスの定義
class MySmarty extends Smarty {
  public function __construct() {
    // 親クラスであるSmartyクラスのコンストラクタを呼び出す
    $this->Smarty();
    $this->template_dir = APP_DIR . "templates/";
    $this->compile_dir = APP_DIR . "templates_c/";
  }

  public function simpleDisplay($req) {
    $path = APP_DIR . 'views/smarty/';
    $this->template_dir = $path . 'templates/';
    $this->compile_dir = $path . 'templates_c/';
    $name = $req->getControllerName(). '/' . $req->getActionName(). '.tpl';
    $this->assign('current',$name);
    $this->display($name);
  }

}

 アクションコントローラindexAction.php内の各アクション内では、「$smarty->display('テンプレートファイル名');」のかわりに、「$smarty->simpleDisplay($request);」($rquestはリクエストオブジェクト)とします。

 ディレクトリおよびファイル構成は以下のようにします。

c:\Apache2.2\htdocs\zf\db\25
  .htaccess          
  index.php   
       
c:\Apache2.2\zendapps\db
  zend.ini
  \25
    DbManager.class.php
    MySmarty.class.php
    \controllers        
      IndexController.php   
    \models   
      TelModel.class.php
    \views
      \smarty
        \templates
          \index           
            index.tpl   
            pre-insert.tpl
        \templates_c        
   \templates
   \templates_c  

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル

アプリケーションディレクトリ
設定ファイル
アプリケーションルートディレクトリ
データベース接続用クラス
MySmartyクラス
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ
電話帳モデル
ビュー用ディレクトリ
Smarty用ディレクトリ
テンプレート用ディレクトリ
indexコントローラ用ディレクトリ
indexアクション用テンプレート
pre-insertアクション用テンプレート
コンパイル済みテンプレート用ディレクトリ
テンプレート用ディレクトリ(デフォルト)
コンパイル済みテンプレート用ディレクトリ(デフォルト)

 MVCモデルにおける相互関連は次のようになります。

アクションコントローラ/アクション(C) モデル(M) ビュー(V)
(->:フォアワード)
概要
index/index searchAllTel index/index.tpl 開始画面表示
index/pre-insert なし index/pre-insert.tpl 電話帳データ入力画面表示
index/insert insertTel

・入力データOK
 ->index/index
・入力データエラー
 ->index/pre-insert

・入力データOK
 電話帳データ登録

■電話帳管理アプリケーション(admin_tel)のSmarty版

 電話帳管理アプリケーション(admin_tel)のビューをSmartyで表示する場合のスクリプトを示します。

 MVCモデルにおける相互関連は以下のようにします。デフォルトアクション(index)コントローラは検索用とし、検索表示のみを行い、電話帳データ入力、更新、削除は管理アクション(admin)コントローラで行うこととします。

アクションコントローラ/アクション(C) モデル(M) ビュー(V)
(->:フォアワード)
概要
index/index searchNamePageTel
totalNameTel
index/index.tpl 検索用開始画面表示
index/search searchNmaePageTel
totalNameTel
index/search.tpl 検索結果表示
edit/index searchNamePageTel
totalNameTel
edit/index.tpl 編集用開始画面表示
edit/search searchNmaePageTel
totalNameTel
edit/search.tpl 変種用検索結果表示
edit/pre-insert なし edit/pre-insert.tpl 電話帳データ入力画面表示
edit/insert insertTel

・入力データOK
 ->edit/index
・入力データエラー
 ->edit/pre-insert

・入力データOK
 電話帳データ登録
edit/pre-update searchIdTel edit/pre_upadate.tpl 電話帳データ更新画面表示
edit/update updateTel ・入力データOK
 ->edit/index
・入力データエラー
 ->edit/pre-update
・入力データOK
 電話帳データ更新
edit/pre-delete searchIdTel edit/pre-delete.tpl 電話帳データ削除確認画面表示
edit/delete deleteTel ->edit/index 電話帳データ削除

 ディレクトリおよびファイル構成は以下のようにします。

c:\Apache2.2\htdocs\zf\db\26
  .htaccess          
  index.php   
       
c:\Apache2.2\zendapps\db
  zend.ini
  \26
    DbManager.class.php
    MySmarty.class.php
    \controllers        
      IndexController.php   
    \models   
      TelModel.class.php
    \views
      \smarty
        \templates
          \index
            index.tpl
            search.tpl
          \edit
            index.tpl 
            search.tpl
            pre-update.tpl
            pre-insert.tpl
            pre-delete.tpl
        \templates_c
   \templates
   \templates_c  

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル

アプリケーションディレクトリ
設定ファイル
アプリケーションルートディレクトリ
データベース接続用クラス
MySmartyクラス
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ
電話帳モデル
ビュー用ディレクトリ
Smarty用ディレクトリ
テンプレート用ディレクトリ
indexアクションコントローラ用ディレクトリ
index/indexアクション用テンプレート
index/searchアクション用テンプレート
editアクションコントローラ用ディレクトリ
indexアクションコントローラ用ディレクトリ
edit/searchアクション用テンプレート
edit/updateアクション用テンプレート
edit/pre-insertアクション用テンプレート
edit/pre-deleteアクション用テンプレート
コンパイル済みテンプレート用ディレクトリ
テンプレート用ディレクトリ(デフォルト)
コンパイル済みテンプレート用ディレクトリ(デフォルト)

 Smartyを利用する場合は、\viewsディレクトリの下に、「\smamrty\templates」と「\smarty\templates_c」を設け、\smamrty\templatesディレクトリの下に、各アクションコントローラごとのディレクトリを作成し、各ディレクトリに対応するアクション用テンプレートを配置します。

 フロントコントローラは次のようにします。

c:\Apache2.2\htdocs\zf\db\26\index.php

<?php
//アプリケーションルートパスの定義
define('APP_DIR','../../../../zendapps/db/26/');
//公開ディレクトリの定義
define('BASE_DIR','/zf/db/26/');
//フロントコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Front.php';
//アクションコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Action.php';
//データベース接続クラス(ユーザ定義)のロード
require_once APP_DIR . 'DbManager.class.php';
// MySmartyクラス(ユーザ定義)のロード
require_once APP_DIR . 'MySmarty.class.php';
/**フロントコントローラのインスタンスの取得
*コントローラのフォルダ指定
*ディスパッチ
*/
Zend_Controller_Front::run(APP_DIR . 'controllers');

 デフォルトコントローラ(C)は次のようにします。

c:\Apache2.2\zendapps\zf\db\26\controllers\IndexController.php

<?php
// PEAR::Pagerライブラリのロード
require_once 'Pager/Pager.php';
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';
// デフォルトアクションコントローラクラスを生成
class IndexController extends Zend_Controller_Action {
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
    // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
    // 自動レンダリングモードの無効化
    $this->_helper->ViewRenderer->setNoRender();
  }

  // デフォルト(index/index)アクションの定義
  public function indexAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    // 指定ページの電話帳データを取得
    $name = "";
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    // 全レコード数の取得
    $total = $this->_tel->totalNameTel($name);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // ページャオブジェクトの生成
    $p = Pager::factory(array('perPage'=>$perPage
                 ,'totalItems'=>$total
                 ,'path'=>''
                 ,'fileName'=>BASE_DIR.'index/index/page/%d'
                 ,'append'=>FALSE
                 ,'currentPage'=>$page
                 ,'linkClass'=>'xs'
                 ,'prevImg'=>'前のページ'
                 ,'nextImg'=>'次のページ'
                 ,'firstPageText'=>'最初'
                 ,'lastPageText'=>'最後'
                )
              );
    // ページャ情報を取得
    $pager = $p->getLinks();
    $pageInfo = array('page' => $page
               ,'lastPage' => $lastPage
               ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    // 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 検索(index/search)アクションの定義
  public function searchAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // キー受信
    $name = $request->getUserParam('key');
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    if($name == '' || $name == NULL) {
      // POSTデータの受信
      $name =$request->getPost('key') ;
    }
    if($name == '' || $name == NULL) {
      $msg = '<span class="red">検索キーを入力してください</span>';
      $request->setParam('msg',$msg);
      // inputアクションにフォアワード
      $this->_forward('index');
    } else {
      // 検索キーをテンプレート変数に設定
      $smarty->assign('name',$name);
      // 電話帳データを取得
      $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
      // 指定ページの電話帳データをテンプレート変数に設定
      $smarty->assign('result',$result);
      $total = $this->_tel->totalNameTel($name);
      // 最終ページ番号計算
      $lastPage = ceil($total/$perPage);
      // fileNmaeパラメータの設定
      $fileName = 'index/search/page/%d' . '/key/' . urlencode($name);
      // ページャオブジェクトの生成
      $p = Pager::factory(array('perPage'=>$perPage
                   ,'totalItems'=>$total
                   ,'path'=>''
                   ,'fileName'=>BASE_DIR.$fileName
                   ,'append'=>FALSE
                   ,'currentPage'=>$page
                   ,'linkClass'=>'xs'
                   ,'prevImg'=>'前のページ'
                   ,'nextImg'=>'次のページ'
                   ,'firstPageText'=>'最初'
                   ,'lastPageText'=>'最後'
                   )
                );
      // ページャ情報を取得
      $pager = $p->getLinks();
      $pageInfo = array('page' => $page
                 ,'lastPage' => $lastPage
                 ,'pager' => $pager);
      // ページ関連情報をテンプレート変数に設定
      $smarty->assign('pageInfo',$pageInfo);
      // 電話帳管理初期画面表示
      $smarty->simpleDisplay($request);
    }
  }
}

 電話帳モデル(M)を再掲します。Smartyの利用することによる変更はありません。

c:\Apache2.2\zendapps\zf\db\26\models\TelModel.class.php

<?php
// 電話帳モデルをクラスとして定義
class telModel {
  // データベースアダプタ用メンバー変数を定義
  private $_db;

  // コンストラクタの定義
  public function __construct() {
    // データベースへの接続
    $this->_db = DbManager::getConnection();
  }

  // 指定ページのレコード検索メソッドの定義
  public function searchNamePageTel($name,$page,$perPage) {
    // オフセット
    $offset = ($page-1)*$perPage;
    // Zend_Db_Selectオブジェクトを生成
    $sel = $this->_db->select();
    // FROM句の追加
    $sel->from('tbl_tel','*');
    if($name != '') {
      // WHERE句の追加
      $sel->where('name like ?','%' . $name . '%');
    }
    // ORDER句の追加
    $sel->order('updated desc' );
    // LIMIT-OFFSET句の追加
    $sel->limit($perPage,$offset);
    // クエリを実行
    $stt = $this->_db->query($sel);
    // 結果取得
    $result = array();
    while($row = $stt->fetch()) {
      array_push($result,$row);
    }
    return $result;
  }

  // 指定ページのレコード検索メソッドの定義
  public function totalNameTel($name) {
    // Zend_Db_Selectオブジェクトを生成
    $sel = $this->_db->select();
    // FROM句の追加
    $sel->from('tbl_tel','count(*) as total');
    if($name != ''){
      // WHERE句の追加
      $sel->where('name like ?','%' . $name . '%');
    }
    // クエリを実行
    $total = $this->_db->fetchOne($sel);
    return $total;
  }

  // 登録メソッドの定義
  public function insertTel(&$tel) {
    // insertメソッド(戻り値は入力レコード数)
    $num = $this->_db->insert(
                 'tbl_tel'            // テーブル名
                 ,array('name'=>$tel['name']   // 入力データ
                 ,'tel_number'=>$tel['tel_number']
                 ,'updated'=>$tel['updated'])
                );
    return $num;
  }

  // 指定IDレコード検索メソッドの定義
  public function searchIdTel($tel_id) {
    // Zend_Db_Selectオブジェクトを生成
    $sel = $this->_db->select();
    // FROM句の追加
    $sel->from('tbl_tel','*');
    // ORDER句の追加
    $sel->order('updated desc' );
    // WHERE句の追加
    $sel->where('tel_id = ?',$tel_id);
    // クエリを実行
    $stt = $this->_db->query($sel);
    // 結果取得
    $row = array();
    $row = $stt->fetch();
    return $row;
  }

  // 指定IDレコード更新メソッドの定義
  public function updateTel(&$tel) {
    // updateメソッド(戻り値は更新レコード数)
    $num = $this->_db->update(
             'tbl_tel' // テーブル名
             ,array('name'=>$tel['name']     // 入力データ
             ,'tel_number'=>$tel['tel_number']
             ,'updated'=>$tel['updated'])
             ,$this->_db->quoteInto('tel_id = ?',$tel['tel_id'])
                               // 条件式
             );
    return $num;
  }

  // 指定IDレコード削除メソッドの定義
  public function deleteTel($tel_id) {
    // deleteメソッド(戻り値は削除レコード数)
    $num = $this->_db->delete(
             'tbl_tel'              // テーブル名
             ,$this->_db->quoteInto('tel_id = ?',$tel_id)
                               // 条件式
             );
    return $num;
  }

  // 全レコード数検索メソッドの定義
  public function totalTel() {
    // クエリの作成
    $sql = 'select count(*) as total from tbl_tel ;';
    // クエリの実行
    $total = $this->_db->fetchOne($sql);
    return $total;
  }
}

 ビュー(V)に対応する各テンプレートを以下に示します。

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\index\index.tpl

<html>
<head>
<title>admin_tel_smarty</title>
{literal}
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
.xs {font-size:x-small
}
.red {color:red
}
-->
</style>
{/literal}
</head>
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
  {$msg}
{/if}

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}index/search">
  <td class="ar">
   <input type="text" name="key" value="{$name}">
   <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}

</div>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\index\search.tpl

<html>
<head>
<title>admin_tel_smarty</title>
{literal}
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
.xs {font-size:x-small
}
-->
</style>
{/literal}
</head>
<body>
<table border="0" width="100%">
 <tr>
  <td width="20%"><a href="{$smarty.const.BASE_DIR}">トップへ</a></td>
  <td class="ac">電話帳管理</td>
  <td width="20%"> </td>
 </tr>
</table>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
  {$msg}
{/if}

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}index/search">
  <td class="ar">
   <input type="text" name="key" value="{$name}">
   <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}

</div>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\EditController.php

<?php
// PEAR::Pagerライブラリのロード
require_once 'Pager/Pager.php';
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';
// デフォルトアクションコントローラクラスを生成
class EditController extends Zend_Controller_Action {
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
  // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
    // 自動レンダリングモードの無効化
    $this->_helper->ViewRenderer->setNoRender();
  }

  // デフォルト(edit/index)アクションの定義
  public function indexAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    // 指定ページの電話帳データを取得
    $name = "";
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    // 全レコード数の取得
    $total = $this->_tel->totalNameTel($name);
    //var_dump($total);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // ページャオブジェクトの生成
    $p = Pager::factory(array('perPage'=>$perPage
                    ,'totalItems'=>$total
                    ,'path'=>''
                    ,'fileName'=>BASE_DIR.'edit/index/page/%d'
                    ,'append'=>FALSE
                    ,'currentPage'=>$page
                    ,'linkClass'=>'xs'
                    ,'prevImg'=>'前のページ'
                    ,'nextImg'=>'次のページ'
                    ,'firstPageText'=>'最初'
                    ,'lastPageText'=>'最後'
                    )
                 );
    // ページャ情報を取得
    $pager = $p->getLinks();
    $pageInfo = array('page' => $page
               ,'lastPage' => $lastPage
               ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    // 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 検索(edit/search)アクションの定義
  public function searchAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // キー受信
    $name = $request->getUserParam('key');
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    if($name == '')
    {
      // POSTデータの受信
      $name =$request->getPost('key') ;
    }
    // 検索キーをテンプレート変数に設定
    $smarty->assign('name',$name);
    // 電話帳データを取得
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    $total = $this->_tel->totalNameTel($name);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // fileNmaeパラメータの設定
    $fileName = 'edit/search/page/%d' . '/key/' . urlencode($name);
    // ページャオブジェクトの生成
    $p = Pager::factory(array('perPage'=>$perPage
                    ,'totalItems'=>$total
                    ,'path'=>''
                    ,'fileName'=>BASE_DIR.$fileName
                    ,'append'=>FALSE
                    ,'currentPage'=>$page
                    ,'linkClass'=>'xs'
                    ,'prevImg'=>'前のページ'
                    ,'nextImg'=>'次のページ'
                    ,'firstPageText'=>'最初'
                    ,'lastPageText'=>'最後'
                    )
                 );
    // ページャ情報を取得
    $pager = $p->getLinks();
    $pageInfo = array('page' => $page
               ,'lastPage' => $lastPage
               ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    // 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 入力(edit/pre-insert)アクションの定義
  public function preInsertAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $errorMsgAll = $request->getUserParam('errorMsgAll');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('errorMsgAll',$errorMsgAll);
    // フォアワード後のPOSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // 受信データをビュー変数に設定
    $smarty->assign('var',$this->_var);
    // 電話帳データ入力画面表示
    $smarty->simpleDisplay($request);
  }

  // 登録(edit/insert)アクションの定義
  public function insertAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "登録") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // inputアクションにフォアワード
        $this->_forward('pre-insert');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを登録
        $num = $this->_tel->insertTel($this->_var);
        $request->setParam('msg',"{$num}レコードを登録しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
      $this->_forward('index');
    }
  }

  // 編集用画面表示(edit/pre-update)アクションの定義
  public function preUpdateAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // 更新対象レコードIDのQueryデータ受信
    $this->_var['tel_id'] = stripslashes($request->getQuery('tel_id')) ;
    if($this->_var['tel_id']) {
      // 新規に更新対象レコード取得
      $result = $this->_tel->searchIdTel($this->_var['tel_id']);
      $this->_var['name'] = $result['name'];
      $this->_var['tel_number'] = $result['tel_number'];
    } else {
      // フォアワード後のエラーメッセージの受信
      $errorMsgAll = $request->getUserParam('errorMsgAll');
      // エラーメッセージをビュー変数に設定
      $smarty->assign('errorMsgAll',$errorMsgAll);
      // フォアワード後のPOSTデータの受信
      $this->getData();
    }
    // 受信データをビュー変数に設定
    $smarty->assign('var',$this->_var);
    // 電話帳データ更新画面表示
    $smarty->simpleDisplay($request);
  }

  // 更新(edit/update)アクションの定義
  public function updateAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "更新") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // editアクションにフォアワード
        $this->_forward('pre-update');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを更新
        $num = $this->_tel->updateTel($this->_var);
        $request->setParam('msg',"{$num}レコードを更新しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
      $this->_forward('index');
    }
  }

  // 削除確認(edit/pre-delete)アクションの定義
  public function preDeleteAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // 削除対象レコードIDのQueryデータ受信
    $this->_var['tel_id'] = stripslashes($request->getQuery('tel_id')) ;
    // 新規に更新対象レコード取得
    $result = $this->_tel->searchIdTel($this->_var['tel_id']);
    // 取得データをビュー変数に設定
    $smarty->assign('var',$result);
    // 電話帳データ更新画面表示
    $smarty->simpleDisplay($request);
  }

  // 削除実行(edit/delete)アクションの定義
  public function deleteAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    $command = stripslashes($request->getPost('command')) ;
    $tel_id = stripslashes($request->getPost('tel_id')) ;
    if($command == "削除") {
      // 電話帳データを削除
      $num = $this->_tel->deleteTel($tel_id);
      // 削除レコード数メッセージをビュー変数に設定
      $msg = $num . "件のレコードを削除しました<br />";
      $request->setParam('msg',$msg);
    }
    // 初期画面にフォアワード
    $this->_forward('index')
  }

  // データ受信
  public function getData() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    if($request->getPost('tel_id') != NULL) {
      $this->_var['tel_id']
        = stripslashes($request->getPost('tel_id')) ;
    }
    $this->_var['name'] = stripslashes($request->getPost('name')) ;
    $this->_var['tel_number']
        = stripslashes($request->getPost('tel_number')) ;
    return;
  }

  // 受信データのチェック
  public function checkData() {
    // POSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // バリデータチェック
    $this->requiredCheck($this->_var['name'],'氏名');
    $this->requiredCheck($this->_var['tel_number'],'電話番号');
    $this->regExCheck($this->_var['tel_number'],'/^[0-9-]+$/','電話番号');
  }

  // 入力値の必須チェックを行う
  public function requiredCheck($value,$varName) {
    // Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/NotEmpty.php';
    // バリデータのインスタンスを生成する
    $validate = new Zend_Validate_NotEmpty();
    $validate->setMessage("{$varName}は必須入力です");
    $this->checkError($validate,$value);
  }

  // 入力値の正規表現チェックを行う
  public function regExCheck($value,$pattern,$varName) {
    // Zend_Validateコンポーネントのロード
    require_once 'Zend/Validate/Regex.php';
    // バリデータのインスタンスを生成する
    $validate = new Zend_Validate_Regex($pattern);
    $validate->setMessage("{$varName}を正しい形式で入力してください");
    $this->checkError($validate,$value);
  }

  // 個々のバリデータによるエラーチェックを行いエラーメッセージを格納する
  public function checkError($validate,$value) {
    if(!$validate->isValid($value)) {
      foreach($validate->getMessages() as $msg) {
      $this->_errorMsg[] = $msg;
      }
    }
  }
}

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\edit\index.tpl

<html>
<head>
<title>admin_tel_smarty</title>
{literal}
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
.xs {font-size:x-small
}
.red {color:red
}
-->
</style>
{/literal}
</head>
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
  {$msg}
{/if}

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/search">
  <td class="ar">
    <input type="text" name="key" value="{$name}">
    <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/pre-insert">
  <td>
    <input type="submit" name="command" value="新規">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>更新</th>
  <th>削除</th>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-update?tel_id={$rows.tel_id}">更新</a></td>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-delete?tel_id={$rows.tel_id}">削除</a></td>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}

</div>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\edit\search.tpl

<html>
<head>
<title>admin_tel_smarty</title>
{literal}
<style type="text/css">
<!--
.ac {text-align:center
}
.ar {text-align:right
}
.xs {font-size:x-small
}
-->
</style>
{/literal}
</head>
<body>
<table border="0" width="100%">
 <tr>
  <td width="20%"><a href="{$smarty.const.BASE_DIR}edit">トップへ</a></td>
  <td class="ac">電話帳管理</td>
  <td width="20%"> </td>
 </tr>
</table>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
 {$msg}
{/if}

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/search">
  <td class="ar">
   <input type="text" name="key" value="{$name}">
   <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/pre-insert">
  <td>
    <input type="submit" name="command" value="新規">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>更新</th>
  <th>削除</th>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-update?tel_id={$rows.tel_id}">更新</a></td>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-delete?tel_id={$rows.tel_id}">削除</a></td>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}

</div>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\edit\pre-insert.tpl

<html>
<head>
<title>admin_tel_smarty</title>
</head>
<body>
<!-- index/insertアクションにPOSTデータを送信-->
<p style="color:red">{$errorMsgAll}</p>
<form method="POST" action="{$smarty.const.BASE_DIR}edit/insert">
<table border="0">
 <tr>
  <th>氏名</th>
  <td><input type="text" name="name" size="10"
        value="{$var.name|escape:'html'}"></td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td><input type="text" name="tel_number" size="10"
        value="{$var.tel_number|escape:'html'}"></td>
 </tr>
 <tr>
  <th></th>
  <td><input type="submit" name="command" value="登録">
    <input type="reset" value="リセット">
    <input type="submit" name="command" value="キャンセル">
  </td>
 </tr>
</table>
</form>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\edit\pre-update.tpl

<html>
<head>
<title>admin_tel_smarty</title>
</head>
<body>
<!-- index/insertアクションにPOSTデータを送信-->
<p style="color:red">{$errorMsgAll}</p>
<form method="POST" action="{$smarty.const.BASE_DIR}edit/update">
<table border="0">
 <tr>
  <th>氏名</th>
  <td><input type="text" name="name" size="10"
        value="{$var.name|escape:'html'}"></td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td><input type="text" name="tel_number" size="10"
        value="{$var.tel_number|escape:'html'}"></td>
 </tr>
 <tr>
  <th></th>
  <td><input type="submit" name="command" value="更新">
    <input type="reset" value="リセット">
    <input type="submit" name="command" value="キャンセル">
    <input type="hidden" name="tel_id"
        value="{$var.tel_id|escape:'html'}">
  </td>
 </tr>
</table>
</form>
</body>
</html>

c:\Apache2.2\zendapps\zf\db\26\views\smarty\template\edit\pre-delete.tpl

<html>
<head>
<title>admin_tel_smarty</title>
</head>
<body>
<!-- index/insertアクションにPOSTデータを送信-->
このレコードを削除してもよろしいですか?
<form method="POST" action="{$smarty.const.BASE_DIR}edit/delete">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>氏名</th>
  <td>{$var.name|escape:'html'}</td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td>{$var.tel_number|escape:'html'}</td>
 </tr>
</table>
<input type="submit" name="command" value="削除">
<input type="submit" name="command" value="キャンセル">
<input type="hidden" name="tel_id"
   value="{$var.tel_id|escape:'html'}">
</form>
</body>
</html>

 サンプルスクリプトへのアクセス例を以下に示します。

■共通部品化

 バリデータ関連メソッドとページャ関連スクリプトは同じアプリケーション内でも複数個所で記述されるとともに、他のアプリケーションでも共用する可能性が高いので、共通部品としてユーザ定義のクラスとして定義し、簡潔に呼び出して利用できるようにしておきます。

 また、ビュースクリプトでも、同じようなHTML(Smartyコード含む)スクリプトを複数のテンプレートで記述しています。そこで、そのようなスクリプトを共有テンプレートとして、共通部品化し、複数のテンプレートで必要に応じてインクルードして使用し、スクリプトの簡潔化と効率化をはかります。

 ディレクトリおよびファイル構成は以下のようにします。

c:\Apache2.2\htdocs\zf\db\27
  .htaccess          
  index.php
  \css
    common.css   
       
c:\Apache2.2\zendapps\db
  zend.ini
  \27
    DbManager.class.php
    MySmarty.class.php
    MyValidate.class.php
    MyPager.class.php
    \controllers        
      IndexController.php   
    \models   
      TelModel.class.php
    \views
      \smarty
        \templates
          head.tpl
          open-list.tpl
          edit-list.tpl
          input.tpl
          \index
            index.tpl
            search.tpl
          \edit
            index.tpl 
            search.tpl
            pre-update.tpl
            pre-insert.tpl
            pre-delete.tpl
        \templates_c
   \templates
   \templates_c  

公開ディレクトリ
Rewriteエンジン制御ファイル
フロントコントローラファイル
スタイルシート用ディレクトリ
共通スタイルシートファイル

アプリケーションディレクトリ
設定ファイル
アプリケーションルートディレクトリ
データベース接続用クラス
MySmartyクラス
MyValidateクラス
MyPagerクラス
コントローラディレクトリ
デフォルトアクションコントローラファイル
モデル用ディレクトリ
電話帳モデル
ビュー用ディレクトリ
Smarty用ディレクトリ
テンプレート用ディレクトリ
head用共通テンプレート
公開リスト用共通テンプレート
編集リスト用共通テンプレート
入力用共通テンプレート
indexアクションコントローラ用ディレクトリ
index/indexアクション用テンプレート
index/searchアクション用テンプレート
editアクションコントローラ用ディレクトリ
indexアクションコントローラ用ディレクトリ
edit/searchアクション用テンプレート
edit/updateアクション用テンプレート
edit/pre-insertアクション用テンプレート
edit/pre-deleteアクション用テンプレート

コンパイル済みテンプレート用ディレクトリ
テンプレート用ディレクトリ(デフォルト)
コンパイル済みテンプレート用ディレクトリ(デフォルト)

 フロントコントローラは次のようにします。

c:\Apache2.2\htdocs\zf\db\27\index.php

<?php
//アプリケーションルートパスの定義
define('APP_DIR','../../../../zendapps/db/26/');
//公開ディレクトリの定義
define('BASE_DIR','/zf/db/26/');
//フロントコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Front.php';
//アクションコントローラ用のコンポーネントをロード
require_once 'Zend/Controller/Action.php';
//データベース接続クラス(ユーザ定義)のロード
require_once APP_DIR . 'DbManager.class.php';
// MySmartyクラス(ユーザ定義)のロード
require_once APP_DIR . 'MySmarty.class.php';
// MyValidateクラス(ユーザ定義)のロード
require_once APP_DIR . 'MyValidate.class.php';
// MyPagerクラス(ユーザ定義)のロード
require_once APP_DIR . 'MyPager.class.php';
/**フロントコントローラのインスタンスの取得
*コントローラのフォルダ指定
*ディスパッチ
*/
Zend_Controller_Front::run(APP_DIR . 'controllers');

 バリデータ関連メソッドは、MyValidateクラスをMyValidate.class.phpファイルに定義します。

c:\Apache2.2\zendapps\zf\db\27\MyValidate.class.php

<?php
// Zend_Validateコンポーネントのロード
require_once 'Zend/Validate.php';
require_once 'Zend/Validate/NotEmpty.php';
require_once 'Zend/Validate/Regex.php';

class MyValidate {
  
// エラーメッセージ格納配列
  public $_errorMsg;

  
// 入力値の必須チェックを行う
  public function requiredCheck($value,$varName) {
    
// バリデータのインスタンスを生成する
    $validate = new Zend_Validate_NotEmpty();
    $validate->setMessage("{$varName}は必須入力です");
    $this->checkError($validate,$value);
  }

  
// 入力値の正規表現チェックを行う
  public function regExCheck($value,$pattern,$varName) {
    // バリデータのインスタンスを生成する
    $validate = new Zend_Validate_Regex($pattern);
    $validate->setMessage("{$varName}を正しい形式で入力してください");
    $this->checkError($validate,$value);
  }

  
// 個々のバリデータによるエラーチェックを行いエラーメッセージを格納する
  public function checkError($validate,$value) {
    if(!$validate->isValid($value)) {
      foreach($validate->getMessages() as $msg) {
        $this->_errorMsg[] = $msg;
      }
    }
  }
}
?>

 ページャ関連スクリプトは、MyPagerクラスとしてMyPager.class.phpファイルに定義します。

c:\Apache2.2\zendapps\zf\db\27\MyPager.class.php

<?php
class MyPager {
  //
  public function pagerSet($currentPage,$totalItems,$perPage,$action,$urlParam) {
    if($urlParam == '' || $urlParam == NULL) {
      $fileName = BASE_DIR . $action . '/page/%d';
    } else {
      $fileName = BASE_DIR . $action . '/page/%d' . $urlParam;
    }
    
// ページャオブジェクトの生成
    $p = Pager::factory(array('perPage'=>$perPage
                  ,'totalItems'=>$totalItems
                  ,'path'=>''
                  ,'fileName'=>$fileName
                  ,'append'=>FALSE
                  ,'currentPage'=>$currentPage
                  ,'linkClass'=>'xs'
                  ,'prevImg'=>'前のページ'
                  ,'nextImg'=>'次のページ'
                  ,'firstPageText'=>'最初'
                  ,'lastPageText'=>'最後'
                 )
              );
    
// ページャ情報を取得
    $pager = $p->getLinks();
    return $pager;
  }
}

?>

 ページャのリンクには任意のパラメータをクエリ情報として記述できるように、pagerSetメソッドでは、$action引数と$urlParam引数を定義しています。$action引数は、アクセスすべきアクション名(アクションコントローラ名/アクション名)で、$urlParamは任意のパラメータをパラメータ名とパラメータ値の対で「(/パラメータ名/パラメータ値/」のように記述した文字列になります)。pagerSetメソッドの構文は次のようになります。$pagerはページャ情報の連想配列、$pはMyPagerオブジェクト(インスタンス)です。

$pager = $p->pagerSet(現在のページ番号,トータル件数,1ページ当たりの表示件数,'アクション名',パラメータの文字列);

【例】

$pager = $p->pagerSet(2,60,10,'index/serch','/key/'. urlencode($name));

 パラメータはurlencode()関数でエンコードしておく必要があります。

 MyValidateクラスとMyPagerクラスを使用した場合のIndexコントローラは次のようになります。

c:\Apache2.2\zendapps\zf\db\27\controllers\IndexController.php

<?php
// PEAR::Pagerライブラリのロード
require_once 'Pager/Pager.php';
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';
// デフォルトアクションコントローラクラスを生成
class IndexController extends Zend_Controller_Action {
  // タイトル
  private $_title;
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
    // タイトルの設定
    $this->_title = "admin-tel-smarty";
    // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
    // 自動レンダリングモードの無効化
    $this->_helper->ViewRenderer->setNoRender();
  }

  // デフォルト(index/index)アクションの定義
  public function indexAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    // 指定ページの電話帳データを取得
    $name = "";
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    // 全レコード数の取得
    $total = $this->_tel->totalNameTel($name);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // MyPagerオブジェクト(インスタンス)の生成
    $p = new MyPager();
    $pageAction = 'index/index';
    $urlParam = '';
    // ページャ情報を取得
    $pager = $p->pagerSet($page,$total,$perPage
               ,$pageAction,$urlParam);

    $pageInfo = array('page' => $page
             ,'lastPage' => $lastPage
             ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    // 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 検索(index/search)アクションの定義
  public function searchAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // キー受信
    $name = $request->getUserParam('key');
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    if($name == '' || $name == NULL) {
      // POSTデータの受信
      $name =$request->getPost('key') ;
    }
    if($name == '' || $name == NULL) {
      $msg = '<span class="red">検索キーを入力してください</span>';
      $request->setParam('msg',$msg);
      // inputアクションにフォアワード
      $this->_forward('index');
    } else {
      // 検索キーをテンプレート変数に設定
      $smarty->assign('name',$name);
      // 電話帳データを取得
      $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
      // 指定ページの電話帳データをテンプレート変数に設定
      $smarty->assign('result',$result);
      $total = $this->_tel->totalNameTel($name);
      // 最終ページ番号計算
      $lastPage = ceil($total/$perPage);
      // fileNmaeパラメータの設定
      $fileName = 'index/search/page/%d' . '/key/' . urlencode($name);
      // MyPagerオブジェクト(インスタンス)の生成
      $p = new MyPager();
      $pageAction = 'index/search';
      $urlParam = '/key/' . urlencode($name);

      // ページャ情報を取得
      $pager = $p->pagerSet($page,$total,$perPage
                 
,$pageAction,$urlParam);
      $pageInfo = array('page' => $page
                 ,'lastPage' => $lastPage
                 ,'pager' => $pager);
      // ページ関連情報をテンプレート変数に設定
      $smarty->assign('pageInfo',$pageInfo);
      // 電話帳管理初期画面表示
      $smarty->simpleDisplay($request);
    }
  }
}

 テンプレートでは、HTMLヘッダー部分のスクリプトを「head.tpl」と共有テンプレート化します。また、電話帳リストを表示するHTMLスクリプト(Smartyスクリプトを含む)は「open-list.tpl」として共有テンプレート化します。

 テンプレート内で、他のテンプレートファイルをインクルードする場合は、以下の構文を記述します。

{include file='ファイル名'}

【例】

{include file="head.tpl"}

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\index\index.tpl

{include file="head.tpl"}
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
 {$msg}
{/if}
{include file="open-list.tpl"}

</body>
</html>

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\index\search.tpl

{include file="head.tpl"}
<body>
<table border="0" width="100%">
 <tr>
  <td width="20%"><a href="{$smarty.const.BASE_DIR}">トップへ</a></td>
  <td class="ac">電話帳管理</td>
  <td width="20%"> </td>
 </tr>
</table>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
 {$msg}
{/if}
{include file="open-list.tpl"}
</body>
</html>

 HTMLヘッダー部の共通テンプレートを以下のようにします。

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\head.tpl

<html>
<head>
<title>{$title}</title>
<meta http-equiv="Content-Style-Type" content="text/css">
<link rel="stylesheet" type="text/css" href="{$smarty.const.BASE_DIR}css/common.css">
</head>

 検索結果表示用の公開用電話帳リストの共通テンプレートは以下のとおりです。

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\open-list.tpl

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}index/search">
  <td class="ar">
   <input type="text" name="key" value="{$name}">
   <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  
<!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}
</div>

 MyValidateクラスとMyPagerクラスを使用した場合のEditコントローラは次のようになります。

c:\Apache2.2\zendapps\zf\db\27\controllers\EditController.php

<?php
// PEAR::Pagerライブラリのロード
require_once 'Pager/Pager.php';
// 電話帳モデルのロード
require_once APP_DIR . 'models/TelModel.class.php';

// デフォルトアクションコントローラクラスを生成
class EditController extends Zend_Controller_Action {
  // タイトル
  private $_title;
  // 電話帳モデル用オブジェクト(インスタンス)のためのメンバー変数の定義
  private $_tel;
  // 変数
  private $_var;
  // エラーメッセージ
  private $_errorMsg;

  // 初期化メソッドの定義
  public function init() {
    // タイトルの設定
    $this->_title = "admin-tel-smarty";
    // 電話帳モデル用オブジェクト(インスタンス)の生成
    $this->_tel = new telModel();
    // 配列の初期化
    $this->_var = array();
    $this->_errorMsg = array();
    // 自動レンダリングモードの無効化
    $this->_helper->ViewRenderer->setNoRender();
  }

  // デフォルト(edit/index)アクションの定義
  public function indexAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    // 指定ページの電話帳データを取得
    $name = "";
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    // 全レコード数の取得
    $total = $this->_tel->totalNameTel($name);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // MyPagerオブジェクト(インスタンス)の生成
    $p = new MyPager();
    $pageAction = 'edit/index';
    $urlParam = '';

    // ページャ情報を取得
    $pager = $p->pagerSet($page,$total,$perPage
               ,$pageAction,$urlParam);

    $pageInfo = array('page' => $page
               ,'lastPage' => $lastPage
               ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    $smarty->assign('title',$this->_title);
    
// 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 検索(edit/search)アクションの定義
  public function searchAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $msg = $request->getUserParam('msg');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('msg',$msg);
    // ページ番号受信
    $page = $request->getUserParam('page');
    if($page == NULL){
      $page = 1;
    }
    // キー受信
    $name = $request->getUserParam('key');
    // 1ページ当たりの表示レコード数の設定
    $perPage = 5;
    if($name == '')
    {
      // POSTデータの受信
      $name =$request->getPost('key') ;
    }
    // 検索キーをテンプレート変数に設定
    $smarty->assign('name',$name);
    // 電話帳データを取得
    $result = $this->_tel->searchNamePageTel($name,$page,$perPage);
    // 指定ページの電話帳データをテンプレート変数に設定
    $smarty->assign('result',$result);
    $total = $this->_tel->totalNameTel($name);
    // 最終ページ番号計算
    $lastPage = ceil($total/$perPage);
    // MyPagerオブジェクト(インスタンス)の生成
    $p = new MyPager();
    $pageAction = 'edit/search';
    $urlParam = '/key/' . urlencode($name);

    // ページャ情報を取得
    $pager = $p->pagerSet($page,$total,$perPage
               ,$pageAction,$urlParam);

    $pageInfo = array('page' => $page
               ,'lastPage' => $lastPage
               ,'pager' => $pager);
    // ページ関連情報をテンプレート変数に設定
    $smarty->assign('pageInfo',$pageInfo);
    $smarty->assign('title',$this->_title);
    // 電話帳管理初期画面表示
    $smarty->simpleDisplay($request);
  }

  // 入力(edit/pre-insert)アクションの定義
  public function preInsertAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // フォアワード後のエラーメッセージの受信
    $errorMsgAll = $request->getUserParam('errorMsgAll');
    // エラーメッセージをビュー変数に設定
    $smarty->assign('errorMsgAll',$errorMsgAll);
    // フォアワード後のPOSTデータの受信(アンエスケープ処理も行う)
    $this->getData();
    // 受信データをビュー変数に設定
    $smarty->assign('var',$this->_var);
    $smarty->assign('action','insert');
    // 電話帳データ入力画面表示
    $smarty->simpleDisplay($request);
  }

  // 登録(edit/insert)アクションの定義
  public function insertAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "登録") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // inputアクションにフォアワード
        $this->_forward('pre-insert');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを登録
        $num = $this->_tel->insertTel($this->_var);
        $request->setParam('msg',"{$num}レコードを登録しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
      $this->_forward('index');
    }
  }

  // 編集用画面表示(edit/pre-update)アクションの定義
  public function preUpdateAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // 更新対象レコードIDのQueryデータ受信
    $this->_var['tel_id'] = stripslashes($request->getQuery('tel_id')) ;
    if($this->_var['tel_id']) {
      // 新規に更新対象レコード取得
      $result = $this->_tel->searchIdTel($this->_var['tel_id']);
      // 更新データをビュー変数に設定
      $smarty->assign('var',$result);
      $smarty->assign('action','update');
    } else {
      // フォアワード後のエラーメッセージの受信
      $errorMsgAll = $request->getUserParam('errorMsgAll');
      // エラーメッセージをビュー変数に設定
      $smarty->assign('errorMsgAll',$errorMsgAll);
      // フォアワード後のPOSTデータの受信
      $this->getData();
      // POST受信データをビュー変数に設定
      $smarty->assign('var',$this->_var);
    }
    // 電話帳データ更新画面表示
    $smarty->simpleDisplay($request);
  }

  // 更新(edit/update)アクションの定義
  public function updateAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    $command = stripslashes($request->getPost('command')) ;
    if($command == "更新") {
      // 受信データチェック
      $this->checkData();
      if(count($this->_errorMsg)) {
        // バリデートでエラーが発生した場合
        $errorMsgAll = implode('<br/>',$this->_errorMsg);
        $request->setParam('errorMsgAll',$errorMsgAll);
        // editアクションにフォアワード
        $this->_forward('pre-update');
      } else {
        // 現在の年月日、時刻を取得
        $this->_var['updated'] = date('Y-m-d H:i:s');
        // 電話帳データを更新
        $num = $this->_tel->updateTel($this->_var);
        $request->setParam('msg',"{$num}レコードを更新しました。");
        // 初期画面にフォアワード
        $this->_forward('index');
      }
    } else {
      // 初期画面にフォアワード
       $this->_forward('index');
    }
  }

  // 削除確認(edit/pre-delete)アクションの定義
  public function preDeleteAction() {
    // MySmartyオブジェクト(インスタンス)の生成
    $smarty = new MySmarty();
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // 削除対象レコードIDのQueryデータ受信
    $this->_var['tel_id'] = stripslashes($request->getQuery('tel_id')) ;
    // 新規に更新対象レコード取得
    $result = $this->_tel->searchIdTel($this->_var['tel_id']);
    // 取得データをビュー変数に設定
    $smarty->assign('var',$result);
    // 電話帳データ更新画面表示
    $smarty->simpleDisplay($request);
  }

  // 削除実行(edit/delete)アクションの定義
  public function deleteAction() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    $command = stripslashes($request->getPost('command')) ;
    $tel_id = stripslashes($request->getPost('tel_id')) ;
    if($command == "削除") {
      // 電話帳データを削除
      $num = $this->_tel->deleteTel($tel_id);
      // 削除レコード数メッセージをビュー変数に設定
      $msg = $num . "件のレコードを削除しました<br />";
      $request->setParam('msg',$msg);
    }
    // 初期画面にフォアワード
    $this->_forward('index');
  }

  // データ受信
  public function getData() {
    // リクエストオブジェクト(インスタンス)の生成
    $request = $this->getRequest();
    // POSTデータの受信(アンエスケープ処理も行う)
    if($request->getPost('tel_id') != NULL) {
      $this->_var['tel_id']
         = stripslashes($request->getPost('tel_id')) ;
    }
    $this->_var['name'] = stripslashes($request->getPost('name')) ;
    $this->_var['tel_number']
         = stripslashes($request->getPost('tel_number')) ;
    return;
  }

  // 受信データのチェック
  public function checkData() {
  // MyValidateオブジェクト(インスタンス)の生成
    $validate = new MyValidate();
  // POSTデータの受信(アンエスケープ処理も行う)
  $this->getData();
  // バリデータチェック
  $validate->requiredCheck($this->_var['name'],'氏名');
  $validate->requiredCheck($this->_var['tel_number'],'電話番号');
  $validate->regExCheck($this->_var['tel_number'],'/^[0-9-]+$/'

                     ,'電話番号');
  $this->_errorMsg = $validate->_errorMsg;
  return;
}

 テンプレートでは、電話データ入力用スクリプトをinput.tplとして、更新データ選択用リスト表示スクリプトをedit-list.tplとしてともに共通テンプレートとして作成し、インクルードして使用します。

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit\index.tpl

{include file="head.tpl"}
<body>
<p class="ac">電話帳管理</p>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
  {$msg}
{/if}
{include file="edit-list.tpl"}
</body>
</html>

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit\search.tpl

{include file="head.tpl"}
<body>
<table border="0" width="100%">
<tr>
<td width="20%"><a href="{$smarty.const.BASE_DIR}edit/">トップへ</a></td>
<td class="ac">電話帳管理</td>
<td width="20%"> </td>
</tr>
</table>
<!-- 処理終了後のメッセージ表示 -->
{if $msg != ""}
  {$msg}
{/if}
{include file="edit-list.tpl"}
</body>
</html>

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit\pre-insert.tpl

{include file="head.tpl"}
<body>
{include file="input.tpl"}
</body>
</html>

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit\pre-updatet.tpl

{include file="head.tpl"}
<body>
{include file="input.tpl"}
</body>
</html>

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit\pre-delete.tpl

{include file='head.tpl'}

<body>
<!-- edit/deleteアクションにPOSTデータを送信-->
このレコードを削除してもよろしいですか?
<form method="POST" action="{$smarty.const.BASE_DIR}edit/delete">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<th>氏名</th>
<td>{$var.name|escape:'html'}</td>
</tr>
<tr>
<th>電話番号</th>
<td>{$var.tel_number|escape:'html'}</td>
</tr>
</table>
<input type="submit" name="command" value="削除">
<input type="submit" name="command" value="キャンセル">
<input type="hidden" name="tel_id"
value="{$var.tel_id|escape:'html'}">
</form>
</body>
</html>

 編集用の電話帳リスト表示用共通テンプレートを以下のようにします。

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\edit-list.tpl

<table border="0" width="100%">
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/search">
  <td class="ar">
   <input type="text" name="key" value="{$name}">
   <input type="submit" name="command" value="検索">
  </td>
  </form>
 </tr>
 <tr>
  <form method="POST" action="{$smarty.const.BASE_DIR}edit/pre-insert">
  <td>
   <input type="submit" name="command" value="新規">
  </td>
  </form>
 </tr>
</table>
<div class="ac">
<table border="1" cellspacing="0" cellpadding="0">
 <tr>
  <th>更新</th>
  <th>削除</th>
  <th>id</th>
  <th>氏名</th>
  <th>電話番号</th>
  <th>更新日</th>
 </tr>
{foreach from=$result item=rows}
 <tr>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-update?tel_id={$rows.tel_id}">更新</a></td>
  <td><a href="{$smarty.const.BASE_DIR}edit/pre-delete?tel_id={$rows.tel_id}">削除</a></td>
  <!-- ユーザ入力データの表示にはサニタイジングを行う -->
  <td>{$rows.tel_id|escape:'html'}</td>
  <td>{$rows.name|escape:'html'}</td>
  <td>{$rows.tel_number|escape:'html'}</td>
  <td>{$rows.updated|escape:'html'}</td>
 </tr>
{/foreach}
</table>
{$pageInfo.pager.first}
{$pageInfo.pager.back}
  ({$pageInfo.page}/{$pageInfo.lastPage})  
{$pageInfo.pager.next}
{$pageInfo.pager.last}
</div>

 電話帳データの入力・更新用フォームの共通テンプレートを以下のようにします。

c:\Apache2.2\zendapps\zf\db\27\views\smarty\template\input.tpl

<!-- POSTデータを送信-->
<p style="color:red">{$errorMsgAll}</p>
{if $action == 'insert'}
 <form method="POST" action="{$smarty.const.BASE_DIR}edit/insert">
{else}
 <form method="POST" action="{$smarty.const.BASE_DIR}edit/update">
{/if}
<table border="0">
 <tr>
  <th>氏名</th>
  <td><input type="text" name="name" size="10"
     value="{$var.name|escape:'html'}"></td>
 </tr>
 <tr>
  <th>電話番号</th>
  <td><input type="text" name="tel_number" size="10"
     value="{$var.tel_number|escape:'html'}"></td>
 </tr>
 <tr>
  <th></th>
   {if $action == 'insert'}
     <td><input type="submit" name="command" value="登録">
   {else}
     <td><input type="submit" name="command" value="更新">
   {/if}
   <input type="reset" value="リセット">
   <input type="submit" name="command" value="キャンセル">
   {if $action == 'update'}
     <input type="hidden" name="tel_id"
         value="{$var.tel_id|escape:'html'}">
   {/if}
  </td>
 </tr>
</table>
</form>

 


前へ | 目次へ |次へ  | Yamada-Lab

執筆 山田豊通
更新日: 2009年4月14日