読者です 読者をやめる 読者になる 読者になる

そろそろ本気でSmartyを使いたい

PHP Piece

 Piece FrameworkではSmartyはなんだか使い難く、「関西方面ではFlexyを使っているんだろうな」と思いながら、騙し騙しSmartyを使い続けてきたのですが、Pieceで快適にSmartyを使うために、そろそろ本気で取り組んでみようと思います。(でも、もしかしたら、Smartyを使わない方が効率が良いという結論に達するかもしれません。)


 まず、SpringのVelocity/FreeMarkerマクロを参考に、こんなSmartyブロック関数を書いてみました。


【追記】
 最終バリデーションの結果を表示するために、パラメタを一個追加。が、ちょっと方法に確信が持てないなぁ。

<?php
function smarty_block_piece_bind($params, $content, &$smarty, &$repeat)
{
    if (isset($content)) {
        $smarty->clear_assign('piece');
        echo $content;
    } else {
        if (isset($params['results']) && isset($params['name'])) {
            $resultName = "__{$params['results']}Results";
            $results = &$smarty->get_template_vars($resultName);
            $name = $params['name'];

            if ($results !== null) {
            
                $smarty->assign('piece', array('status' => array(
                    'name'   => $name,
                    'value'  => $results->getFieldValue($name),
                    'error'  => $results->getErrorMessage($name)
                )));
            } else {
                if (isset($params['container'])) {
                    $container = &$smarty->get_template_vars($params['container']);
                    if ($container) {
                        $value = $container->$name;
                    } else {
                        $value = null;
                    }
                } else {
                    $value = null;
                }
            
            
                 $smarty->assign('piece', array('status' => array(
                    'name'   => $name,
                    'value'  => $value,
                    'error'  => null
                )));
            }
        }
    }
}
?>


 こんな感じで使います。

<p>
{piece_bind name="yourname" results="Comment" container="comment"}
<!-- パラメータの名称はyourname, 結果セットの名前(Validatorの名前)はComment-->
<input type="text" name="{$piece.status.name}" value="{$piece.status.value|escape}" />
{if $piece.status.error}<span class="error">{$piece.status.error|escape}</span>{/if}
{/piece_bind}
</p>

<p>
{piece_bind name="comment" results="Comment" container="comment"}
<textarea name="{$piece.status.name}">{$pice.status.value|escape}</textarea>
{if $piece.status.error}<span class="error">{$piece.status.error|escape}</span>{/if}
{/piece_bind}
</p>


 次のようなHTMLが出力されます。

<p>
<input type="text" name="yourname" value="" />
<span class="error">氏名は入力必須です。</span>
</p>

<p>
<textarea name="comment"></textarea>
<span class="error">コメントは入力必須です。</span>
</p>


 フィールド・レンダリング用、エラー表示用のヘルパー関数を登録するのも良いやり方だと思ったのですが、「入力値とエラー」をHTMLタグから分離できた方が、input, textarea, etc.要素の属性(例えば、classやonfocus等)をテンプレートで指定できる分、柔軟性があるかな、と。


 Springのマクロをそのまま持ってきたので、{$piece.status.value}のように、ちょっと冗長な式になっていますが、{piece_bind to="p" ...}のように束縛する変数を指定できれば、もっとテンプレートを簡潔にできそうです。