KohanaフレームワークでPHPTALを利用してみた2

By | 2008/1/31 木曜日

前回の記事ではとりあえずKohanaフレームワークからPHPTALを呼び出すところまで試してみた。
なんとなく繋がったので今度はより実践向きに共通ヘッダーやフッターを利用できるバージョンにしてみる。

共通のヘッダーやフッターを表示させるには主に2パターン
・コンテンツのテンプレートを書いてそこからヘッダーとフッターを呼ぶ
・共通のレイアウトから内部だけくり抜いてコンテンツを当て込む

なんとなくCakePHP使ったときにやりやすかった共通のレイアウトの中身くり抜いて内部のコンテンツを当て込む方法を採用。

PHPTALを調べていたらちょうど良さそうなのを発見!
METAL(Macro Extension for TAL)、コンテンツの中身を書き換えてくれるらしいのでこれを使って作ってみる。

悩ましいのが2パターンどちらの方法を使ってもhtmlソースがちぎられた状態で存在してしまうこと。
テンプレートファイルがいきなりdivから始まってたりするとデザーナーさんでも読みやすいPHPTALのテンプレート特性を生かせない。
とりあえずはコンテンツ用のテンプレートにはダミーのヘッダー、フッターを書いてもらうことにする。
これで極端なテンプレートにはならないと思うけど、いまいちかな?

■設定ファイルとライブラリ

/system/application/config/ptal.php

<?php defined('SYSPATH') or die('No direct access allowed.');
/*
 * File: Ptal
 *
 * Options:
 *  dir     - 
 *  suffix   - 
 *  layout   - 
 *  title-default   - 
 *  title-format   - 
 */
$config = array
(
  'dir' => APPPATH.'views/',
  'suffix' => '.html',
  'layout' => APPPATH.'views/common/layout.html',
  'title-default' => 'せつないぶろぐ',
  'title-format' => '%s / せつないぶろぐ'
);

/system/libraries/Ptal.php

<?php if (!defined('SYSPATH')) exit('No direct script access.');
/*
 * Class: Ptal
 *
 *  author    - t@setunai.net
 *  license   - 
 */
require 'PHPTAL.php';

class Ptal_Core {

  protected static $config;

  /*
   * Constructor: __construct
   *
   */
  public function __construct()
  {
    // Load config
    self::$config = Config::item('ptal');
  }

  /*
   * Method: fetch
   *
   * Parameters:
   *  tmpl - 
   *  data - title, any
   *  options - meta-http, meta-name, js, css
   * 
   */
  function fetch($tmpl, $data, $options=array()) {
    $dir = self::$config['dir'];
    $suffix = self::$config['suffix'];
    $layout = self::$config['layout'];

    $tmplPath = sprintf('%s%s%s', $dir, $tmpl, $suffix);

    // title
    if (isset($data['title'])) {
      $data['title'] = sprintf(self::$config['title-format'], $data['title']);
    } else {
      $data['title'] = self::$config['title-default'];
    }

    // data
    $phptal = new PHPTAL($layout);
    foreach($data as $p => $value) {
      $phptal->$p = $value;
    }
    $phptal->tmpl = $tmplPath;

    // meta
    if (!isset($options['meta-http'])) {
      $options['meta-http'] = array();
    }
    if (!isset($options['meta-name'])) {
      $options['meta-name'] = array();
    }

    // css
    if (!isset($options['css'])) {
      $options['css'] = array();
    }

    // js
    if (!isset($options['js'])) {
      $options['js'] = array();
    }
    $phptal->options = $options;

    $result = '';
    try {
      $result = $phptal->execute();
    }
    catch (Kohana_Exception $e){
      throw new Kohana_Exception('phptal error');
    }

    return $result;
  }

  /*
   * Method: view
   *
   * Parameters:
   *  tmpl - 
   *  data - title, any
   *  options - meta-http, meta-name, js, css
   * 
   */
  function view($tmpl, $data, $options=array()) {
    echo $this->fetch($tmpl, $data, $options);
  }

} // End Ptal Class

■サンプル

コントローラ:/application/controllers/test.php

<?php defined('SYSPATH') or die('No direct script access.');

class Test_Controller extends Controller {

  function index()
  {
    $days["sun"] = "日曜日";
    $days["mon"] = "月曜日";
    $days["tue"] = "火曜日";
    $days["wed"] = "水曜日";

    $data["title"] = "PHPTALテスト";
    $data["days"] = $days;
    $data["bol"] = false;

    $options["meta-http"] = array("pragma" => "no-cache");
    $options["meta-name"] = array("keywords" => "テスト, test");
    $options["meta-name"] = array("desctiption" => "これはテストです。");

    $options["css"] = array("/css/test.css", "/css/hoge.css");
    $options["js"]  = array("/js/test.js", "/js/hoge.js");

    $this->load->library("Ptal");
    $this->Ptal->view("test/index", $data, $options);
  }

}

共通テンプレート:/application/views/common/layout.html

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<tal:block repeat="m options/meta-http">
<meta http-equiv="${repeat/m/key}" content="${m}" />
</tal:block>
<tal:block repeat="m options/meta-name">
<meta name="${repeat/m/key}" content="${m}" />
</tal:block>
<title tal:content="title">タイトル</title>
<link rel="stylesheet" type="text/css" href="/css/default.css" />
<tal:block repeat="href options/css">
<link rel="stylesheet" type="text/css" href="${href}" />
</tal:block>
<script type="text/javascript" src="/js/lib/jquery.js"></script>
<tal:block repeat="src options/js">
<script type="text/javascript" src="${src}"></script>
</tal:block>
</head>
<body>
<div id="header">
  <p>共通ヘッター</p>
</div>
<div id="content" metal:use-macro="${tmpl}/content">
  コンテンツ
</div>

<div id="footer">
  <p>共通フッター</p>
</div>
</body>
</html>

テンプレート:/application/views/test/index.html

<html>
  <head>
    <title>レイアウト用</title>
  </head>
  <body>
    <!-- ここから上はダミー -->
    <div id="content" metal:define-macro="content">
      <table>
        <tr>
          <th>キー</th>
          <th>値</th>
          <th>index</th>
          <th>number</th>
        </tr>
        <tr tal:repeat="day days">
          <td tal:content="repeat/day/key">英字</td>
          <td tal:content="day">曜日</td>
          <td tal:content="repeat/day/index" />
          <td tal:content="repeat/day/number" />
        </tr>
      </table>

      <p tal:condition="bol">bolがtrueなら表示</p>
      <p tal:condition="not:bol">bolがfalseなら表示</p>
    </div>
  <!-- ここから下はダミー -->
  </body>
</html>

実行結果のソース

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-Script-Type" content="text/javascript"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta http-equiv="pragma" content="no-cache"/>
<meta name="desctiption" content="これはテストです。"/>
<title>PHPTALテスト / せつないぶろぐ</title>
<link rel="stylesheet" type="text/css" href="/css/default.css"/>
<link rel="stylesheet" type="text/css" href="/css/test.css"/>
<link rel="stylesheet" type="text/css" href="/css/hoge.css"/>
<script type="text/javascript" src="/js/lib/jquery.js"></script>
<script type="text/javascript" src="/js/test.js"></script>

<script type="text/javascript" src="/js/hoge.js"></script>
</head>
<body>
<div id="header">
  <p>共通ヘッター</p>
</div>
<div id="content">
      <table>
        <tr>
          <th>キー</th>

          <th>値</th>
          <th>index</th>
          <th>number</th>
        </tr>
        <tr>
          <td>sun</td>
          <td>日曜日</td>

          <td>0</td>
          <td>1</td>
        </tr><tr>
          <td>mon</td>
          <td>月曜日</td>
          <td>1</td>

          <td>2</td>
        </tr><tr>
          <td>tue</td>
          <td>火曜日</td>
          <td>2</td>
          <td>3</td>

        </tr><tr>
          <td>wed</td>
          <td>水曜日</td>
          <td>3</td>
          <td>4</td>
        </tr>      </table>

            <p>bolがfalseなら表示</p>    </div>
<div id="footer">
  <p>共通フッター</p>
</div>
</body>
</html>

ちょっとは使えるようになったかな?

コメントを残す

メールアドレスが公開されることはありません。