UnphptagViewRenderer作ってみた その2

前エントリの続き。
新たに3つのタグ *{}, @{}, @part{} をサポートしてみました。つっても置換を足しただけですが。

UnphptagViewRenderer.php

<?php
/**
 * UnphptagViewRenderer
 *
 * configuration:
 * <pre>
 * array(
 *     'components'=>array(
 *         ......
 *         'viewRenderer'=>array(
 *             'class'=>'path.to.class.UnphptagViewRenderer',
 *         ),
 *     ),
 * )
 * </pre>
 *
 * echo:
 *   %{ Yii::app()->name} -> <?php echo Yii::app()->name; ?>
 * encode echo:
 *   %%{Yii::app()->name} -> <?php echo CHtml::encode(Yii::app()->name); ?>
 * code:
 *   #{ $name = Yii::app()->name } -> <?php $name = Yii::app()->name; ?>
 * comment:
 *   *{**** comment ****} -> 
 * renderPartial with PHP TAG:
 *   @{'/parts/part1', $param} -> <?php $this->renderPartial('/parts/part1', $param); ?>
 * renderPartial whthout PHP TAG:
 *   @part{'/parts/part1', $param} -> $this->renderPartial('/parts/part1', $param)
 *
 */
class UnphptagViewRenderer extends CViewRenderer
{
	protected function generateViewFile($sourceFile, $viewFile)
	{
		$source = file_get_contents($sourceFile);
		file_put_contents($viewFile, $this->parse($source));
	}

	protected function parse($s) {
		$s = preg_replace('/\*\{([\s\S]*?)\}/', '', $s);
		$s = preg_replace('/%%\{([\s\S]*?)\}/', '<?php echo CHtml::encode($1); ?>', $s);
		$s = preg_replace('/%\{([\s\S]*?)\}/', '<?php echo $1; ?>', $s);
		$s = preg_replace('/#\{([\s\S]*?)\}/', '<?php $1; ?>', $s);
		$s = preg_replace('/\@\{([\s\S]*?)\}/', '<?php $this->renderPartial($1); ?>', $s);
		$s = preg_replace('/\@part\{([\s\S]*?)\}/', '$this->renderPartial($1)', $s);
		return $s;
	}
}

PlayFrameworkのカスタムテンプレートタグ

yiiから離れますが、PlayFrameworkのカスタムテンプレートタグは使えるなーという印象があります。Aタグを生成する小さなものから、そこそこ凝ったDIVブロックを生成するものまでテンプレート化していました。

PlayFramework カスタムテンプレートタグ

一方、yiiではそこそこのものはテンプレートにしますが、小さいのまではテンプレートにしていない。この違いはなんだろう。
$this->renderPartial は長いです。小さいテンプレート達一つ一つに $this->renderPartial, $this->renderPartial, $this->renderPartial と書きたくない。これがテンプレート化しない原因の一つじゃないかと考えました。
前回はview上にあふれるPHPタグを減らしました。今回は $this->renderPartial を減らします。

@{}タグ

「@{}」は$this->renderPartial省略記法その1です。次のように使います。引数はrenderPartialと同じです。というか「@{'aaa', bbb, ccc}」を置換して「$this->renderPartial('aaa', bbb, ccc)」にしているだけ。
サンプルはyii/demos/blogです。ここには3つの $this->renderPartial がありました。

blog/protected/views/post/view.php

#{
$this->breadcrumbs=array(
    $model->title,
);
$this->pageTitle=$model->title;
}
<?php // $this->renderPartial('_view', array(
//    'data'=>$model,
//)); ↓↓↓ ?>
@{'_view', array('data'=>$model,)} 

<div id="comments">
    #{if($model->commentCount>=1):}
        <h3>
            %{$model->commentCount>1 ? $model->commentCount . ' comments' : 'One comment'}
        </h3>

        <?php // $this->renderPartial('_comments',array(
        //    'post'=>$model,
        //    'comments'=>$model->comments,
        //)); ↓↓↓ ?>
        @{'_comments',array(
            'post'=>$model,
            'comments'=>$model->comments,
        )}
    #{endif;}

    <h3>Leave a Comment</h3>

    #{if(Yii::app()->user->hasFlash('commentSubmitted')):}
        <div class="flash-success">
            %{Yii::app()->user->getFlash('commentSubmitted')}
        </div>
    #{else:}
        <?php //$this->renderPartial('/comment/_form',array(
        //    'model'=>$comment,
        //)); ↓↓↓ ?>
        @{'/comment/_form',array('model'=>$comment,)}
    #{endif;}

</div><!-- comments -->

パラメータをarrayで包んで渡すのはイケてないですね。「@_view{compact('model')}」などどしたいところです。

@part{}

$this->renderPartial の省略記法その2です。

YiiのCDetailViewに複雑なHTMLを表示させたいとき

↑のように $this->renderPartial で生成した文字列を使う場合もあります。この場合、次のように書けます。勝手に引用してすみません。

<?php $this->widget('zii.widgets.CDetailView', array(
    'data'=>$model,
    'attributes'=>array(
        'id',
        'name',
        //'poor_content',  // 文字列表示じゃかっこ悪い
        array(
            'label'=>'Complex Content',
            'type'=>'raw',
            'value'=> @part{'_complex_content', array('data'=>$model,), true}
        ),
),
)); ?>

こちらも「@_complex_content{compact('model')}」などとしたいですね。

というわけで

コメントを除くと20行足らずのプリプロセッサでて、PlayFrameworkカスタムテンプレートタグっぽいものを実現してみました。
yiiの素のviewはPHPタグがあふれるけどプリプロセッサによって改善できそうだなーと思いました。