Yiiをつかう:その3

Yiiを使うYii その1YIIをつかう:その2の続き。ここでは独自簡易記法についてのメモ。同時にYiiのCWidgetに使い方についての若干のメモとなっている。

独自記法例

このサイトの独自記法は、二重の波括弧(brace/curl)で囲うということにした。まあ、なんちゃってスクリプトなので、二重括弧をつかって他で困らないか、という風なことは一切考えていないしエラー処理などもしない(キッパリ。

{{記法名称=なにか=なにか}}

上の「なにか」は引数である。引数は=で複数加えられる。イコール記号を使って後から困らないかという風なことは一切考えていない(キッパリ。

記法名称は呼び出すメソッド。たとえばhtmlをエスケープしたいときは {{escape=<pre>}}とすると、<pre>となる。

リンクをつけたいときは{{href=yii-2.html}}とすれば、YIIをつかう:その2となる。

site logo

このサイトのロゴを表示させてみる。


などは複数の引数を使って{{img=/a.png=50=site logo}}としている。

また画像の最後をclear:bothしたいので{{clear}}命令を作っている(*1)。

二つ目の引数はwidth,heightのパーセンテージ指定。最後のものはalt属性の値。生成されるhtmlは

<img width="108" height="91" src="/a.png" alt="site logo" />

CWidgetを使った記法解析クラスの作成

このような文字列をパースするために、簡単なライブラリを作る。どこにおくか迷ったがとりあえず、extensionsディレクトリにhtmlparseというディレクトリを作る。

クラス名はRadioHtmlParserと、ハッタリでものものしいものにして、CWidgetの拡張にする。

class RadioHtmlParser extends CWidget

同様の名称のphpをつくって、config/main.phpのcomponentsのところに読み込むクラスを設定(*2)。

'htmlparse' =>array('class'=>'application.extensions.htmlparse.RadioHtmlParser');

以下、パースされる行が既に配列で取得されているものとする。

波括弧をチェックする正規表現。

public $tag_regex = '#\{\{([^{]*)\}\}#';

各行から二重波括弧を取り出すループ

やっていることは簡単である。

$array = $this->line;//行配列
  foreach($array as $k=>$string) //special tag
  {
     preg_match_all($this->tag_regex, $string, $matches);
       if(!$matches[0])
        {
           $line[$k] = $string;
           continue;
        }
        else
        {
           foreach($matches[1] as $k2=>$v)
           {
              $r=explode("=",$v);
              $func = array_shift($r);
              $string = str_replace($matches[0][$k2],$this->$func($r),$string);
            }
           $line[$k] = $string;
        }
  }

上の

$string = str_replace($matches[0][$k2],$this->$func($r),$string);

だけがミソ。クラスの中にマジックメソッド__callを作っておき、$this->$func($r)の処理は__callに全て任せる。

public function __call($func,$arg)
{
   if(file_exists($this->getViewPath().'/'.$func.'.php'))
      return $this->render($func,array('arg'=>$arg[0]),true);
   else      
      return '{{'.$func.'='.implode("=",$arg[0])."}}";
}

最初はcall_user_func_arrayで、それぞれメソッドを書いてたのだが、どう考えてもこっちのほうが簡便にあることに気づいた。 それというのもYiiのCWidgetクラスはCControllerクラス同様簡単にviewsをもてるからである。単にファイルを呼び出すだけでおk。本体クラスには一切手を付けないで記法を拡張出来るし。

簡易記法毎のview phpをviewパスに書く。

あとは、

protected/extensions/htmlparse/views/なにか.php

を書けばいい。

$arg名で配列変数がviewに渡されているのでそれを利用する。

escape記法を作りたいなら、

protected/extensions/htmlparse/views/escape.php

として

echo htmlspechialchars($arg[0]);

の一行だけでいい。空白行をつくる記法は

{{blank=立て幅数値}}

で、たとえばblank=3とすると

---

程度の空白の立て幅が得られるのだが、これは

protected/extensions/htmlparse/views/blank.php

の中で

if(isset($arg[0]))
    $line = $arg[0];
else
    $line = 1;
echo '<div style="visibility:hidden;margin-bottom:'.$line.'em;">---</div>';

とお間抜けなことをしているに過ぎないのである(*3)。

拡張記法は思い立ったときにすぐつくれる

かくして、

protected/extensions/htmlparse/views/なにか.php

だけ書けば、いくらでも{{なにか=}}名の簡易「タグ」を作れる。

wikipedia自動検索リンクというのを作りたいと思えば

{{wikipedia=検索語句=サイト場所(日本語なのか英語なのか、その他)}}

protected/extensions/htmlparse/views/wikipedia.php

$word = $arg[0];
if(isset($arg[1]))
    $lang = $arg[1];
else
    $lang = 'ja';
$link = CHtml::link("wiki","http://".$lang.".wikipedia.org/wiki/".$word);
$link = CHtml::tag('sup',array(),$link);
echo $word.$link;

これで

{{wikipedia=波括弧}}

を二重波括弧で囲むと、波括弧wikiという名称をwikiで調べるリンクを生成。

{{wikipedia=bracket=en}}

を二重波括弧で囲んで、英語のbracketwikiという名称をwikiで調べるリンクを生成。

を、意外とべんりやんw。

いずれにせよ、viewsの下にファイルを作ればそれでいくらでも拡張可能ってのは少し気に入ってしまったのである。

なお本ページのソース(popup)

---

*1: <br style='clear:both;' / >を返すだけ

*2: 実際はYIIをつかう:その2で書いたように、yamlファイルで設定。

*3: html正規化論者からは嫌がられるやりかたです。すみません。

this file --> last modified:2012-03-31 13:57:51