デザイナーとの協業での工夫 Smartyプリフィルタの活用法

http://d.hatena.ne.jp/akiraneko/20081113/1226588314
こっちにもう少し読みやすい記事を書き直しました

http://d.hatena.ne.jp/maru_cc/20081112/with_designer
「デザイナーとの協業での工夫 Smartyプリフィルタの活用法」

id:maru_cc さんに記事をぱくってみました! 少し前からいろいろ考えていた仕組みを簡単にまとめて見ました。

基本方針

htmlは極力汚さないようにします。個人的にはSmartyプログラマなんで、デザイン貰ったらあとでがんがんコードを入れていくので、差分は自分で取り込みます。スタイルの修正などもデザインチームに投げないで自分でやったりもします。

ただ今回はTeedaっぽくしてみました!

<html>
    <body>
        <div id="head">head</div>
    </body>
</html>

上記のようなテンプレートが

<html>
    <body>
        <div id="head"><?php echo $head ?></div>
    </body>
</html>

になることを最終地点とします。

設定ファイル

今回はJSON形式にしました。本当はYAMLが良かったのですが、どうもJavaScriptできれいにパースしてくれるライブラリってないみたいです。。。

{
    "head" : "ヘッダ<b>JS</b>"
}

こんな感じの設定ファイルをテンプレートと同じ場所に入れておきます。このへんはMayaaっぽですね。XMLはちょっと書きたくなかったのでJSONで!

作ってみた!

展開速いです(笑)

test.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>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>タイトル</title>
        <script id="domjs" type="text/javascript" src="js/dom.js"></script>
    </head>
    <body>
        <div id="head">head</div>
        <div id="foot">foot</div>
    </body>
</html>

これがテンプレートです。このファイルをそのまま表示すると

headとfootが表示されます(当たり前)。

test.json

{
    "head" : "ヘッダ<b>JS</b>"
    "foot" : "フッター<b>JS</b>"
}

この設定ファイルをjs/dom.jsで処理させると

<?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>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>タイトル</title>
        <script id="domjs" type="text/javascript" src="js/dom.js"></script>
    </head>
    <body>
        <div id="head">ヘッダ<b>JS</b></div>
        <div id="foot">フッター<b>JS</b></div>
    </body>
</html>

idの部分がJSONのデータで置換されています!

どういうことかというと!

テンプレートモックの時点でidをふって、デザイナーさんに置換される場所を指定してもらいます。モックをそのまま表示した場合にはJavaScriptを通してJSONのサンプルの文字列に置換されて表示されます。

プログラマJSONの部分のデータをプログラムで用意して、テンプレートエンジンで置換して送り出します。

EthnaSmartyへ組み込み

Smartyの置換用プレフィルターファイルを読み込み

Project/app/Project_Controller.php

<?php
require_once 'Users/Smarty/prefilter.dom.php';

上の方でプラグインファイルを読み込ませます。

<?php
    var $ext = array(
        'php'           => 'php',
        'tpl'           => 'html',
    );

拡張子はtplからhtmlに変更します。

<?php
    var $smarty_prefilter_plugin = array(
        'smarty_prefilter_dom'
    );

下の方にあるプレフィルターのリストに追加。

Project/app/Project_ViewClass.php

<?php
    function _setDefault(&$renderer)
    {
        //Rendererからテンプレートエンジンを取得
        $smarty =& $renderer->getEngine();

        // smartyテンプレートのデリミタを変更
        $smarty->left_delimiter = '<{';
        $smarty->right_delimiter = '}>';

        // デバッグの時にはコンパイルを毎回する
        if( $this->config->get('debug') ){
            $smarty->clear_compiled_tpl();
        }
    }

今回はJSONファイルを変更した場合にコンパイルしなおさないといけないので、デバッグ中はつねにリコンパイルのモードにします。デリミタは趣味です。

Project/etc/project-ini.php

<?php
$config = array(
    // site
    'url' => '',

    // debug
    // (to enable ethna_info and ethna_unittest, turn this true)
    'debug' => true,

デバッグモードをONにします。

データリストの表示

ここまでで普通のデータはモックではダミーデータ、プログラムでは正式なデータが表示できるようになりました。

次は良くあるデータリストの表示方法です。

{
  "app" : {

    "head" : "ヘッダ<b>JS</b>"

    ,"btn" : {
      "value" : "ボタンJS"
      ,"onclick" : "alert('JSの処理を入れてね');"
    }

  },

  "app_ne" : {

    "btn2" : {
      "value" : "ボタン2JS"
      ,"onclick" : "alert('JS2の処理を入れてね');"
    }

    ,"foot" : "フッター<b>JS</b>"

    ,"dataItems" : [
      {
        "data" : "data line 1"
      }
      ,{
        "data" : "data line 2"
      }
      ,{
        "data" : "data line 3"
        }
    ]
  }
}

一気にデータが増えましたが、appはエスケープした文字が出力されます。app_neはエスケープされていない文字が出力されます。

オブジェクトで指定するとvalueとかonclickとか複数の要素を指定する場合に利用します。
dataItemsはリスト表示用のデータで、最後がItemsで終わる物は、配列分のデータを処理します。

<?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>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>タイトル文</title>
        <script id="domjs" type="text/javascript" src="js/dom.js"></script>
    </head>
    <body>
        <div id="head">he</div>
        <input type="button" id="btn" value="btn" />
        <input type="button" id="btn2" value="btn2" />
        <div id="foot">foot</div>
        <hr />
        <div id="dataItems">
          <span>Title</span><br />
          <div id="data">data</div><br />
          <span>memo</span><br />
          <hr />
        </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>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>タイトル文</title>
        <script id="domjs" type="text/javascript" src="js/dom.js"></script>
    </head>
    <body>
        <div id="head">ヘッダ&lt;b&gt;JS&lt;/b&gt;</div>
        <input onclick="alert('JSの処理を入れてね');" type="button" id="btn" value="ボタンJS" />
        <input onclick="alert('JS2の処理を入れてね');" type="button" id="btn2" value="ボタン2JS" />
        <div id="foot">フッター<b>JS</b></div>
        <hr />
        <div id="dataItems">
          <span>Title</span><br><div id="data-0">data line 1</div><br /><span>memo</span><br /><hr />
          <span>Title</span><br><div id="data-1">data line 2</div><br /><span>memo</span><br /><hr />
          <span>Title</span><br><div id="data-2">data line 3</div><br /><span>memo</span><br /><hr />
        </div>
    </body>
</html>

たぶんこんな感じにJavaScriptで置換されます。

画面だとこんな感じ。

ボタンを押すと

JSもちゃんと動きます。

Ethnaだと

<?php
$this->af->setApp('head', 'ヘッダ<b>PHP</b>');
$this->af->setApp('btn', array( 'value' => 'ボタンPHP', 'onclick' => "alert('PHP')" ) );
$this->af->setAppNE('btn2', array( 'value' => 'ボタン2PHP', 'onclick' => "alert('PHP2')" ) );
$this->af->setAppNE('foot', 'フッタ<b>PHP</b>');

$this->af->setAppNE('dataItems', array(
                  array( 'data' => "php Line 1" ),
                  array( 'data' => "php Line 2" ),
                  array( 'data' => "php Line 3" ),
                  array( 'data' => "php Line 4" ),
                  array( 'data' => "php Line 5" ),
                ) );

こんな感じでデータを投入します。

こんな感じに表示されます。

感想

結構いい感じじゃないでしょうか?
実はもう少し作りこまないと実用的じゃなかったりします、、、

もう少し機能を載せればデザインのみである程度動かしてチェックできて、テンプレートを変更しないままプログラムが乗ったりするんじゃないかな?

あとたぶん画像とかはテンプレートフォルダと、wwwフォルダ両方に入れます。両方のフォルダで同じように動くのが理想です。

http://akira.info/labs/domtest/ethna250.lzh

Ethnaの全て入ったプロジェクトです。

http://akira.info/labs/domtest/test.html
http://akira.info/labs/domtest/test.json

テンプレートとデータです。

ちなみにモックは一瞬デフォルトのが見えてから、置換が走ります!(上のファイルだとわかりやすいよう100ミリ秒から3秒に変更してあります。更新をして3秒まつとわかりやすいと思います)
EthnaSmartyで動かしていますが、実はサーバー側はなんでもかまいません。Smartyじゃなくって生PHPテンプレートにも利用できると思いますし、Teedaとかでもモック側に使うのであれば結構すぐ使えるようになると思います。

ここも参考にしました!
http://blog.xole.net/article.php?id=577