メソッドチェーンでHTMLを組み立てるView Helper

メソッドチェーンを用いて複雑なHTMLを組み立てることができるMarkup Helperを公開しました。(実用上)PHP 5.2以上が必須です。

cakephp-markup-helper – GitHub

例1:単純なdiv,pタグを出力

echo $markup->div('section')->p->text('これは<テスト>です')->end->end;
/*
出力されるHTML:
<div class="section">
 
これは&lt;テスト&gt;です
</div>
 
*/

例2:HtmlHelperと併用し、「ユーザ一覧」テーブルを構築

echo $markup->div('list')
->table
->thead
->html($html->tableHeaders(a('id', 'ユーザ名', '操作')))
->end
->tbody->nl;
 
foreach ($users as $user) {
  echo $markup->tr
    ->td->text($user['User']['id'])->end
    ->td->text($user['User']['username'])->end
    ->td('actions')
    ->html($html->link('編集',array('action'=>'edit', $user['User']['id'])))
    ->end
    ->endtr->nl;
}
 
echo $markup->endAllTags;

使い方は上の例からほとんど想像がつくだろうと思います。特徴は次の通りです。

  • ほとんど全てのメソッドがインスタンス自身を返すので、延々メソッドチェーンを繋げていくことでどんな複雑なHTMLも構築することができます。
  • 内部で「どのタグがまだ閉じられていないか」という情報を管理しているため、タグ名を明示しなくてもタグを閉じることが出来ます。逆に敢えてタグ名を明示して、構造が正しいことを確認することもできます。
  • 生成されたHTMLは内部のバッファに蓄えられ、__toString で文字列として返却されます。PHP 5.2以降ではオブジェクトが文字列として使用される際に自動的に __toString が呼ばれるため、違和感なく echo(またはその他の関数)で出力することができます。

省略記法の種類

できる限り短く、書きやすくするため、__get と __call を活用した省略記法が多数用意されています。

  省略記法 実際のメソッド呼び出し
プロパティ $markup->{method_name}; $markup->{method_name}();
メソッド $markup->{tag_name}(arg1, arg2, …); $markup->startTag({tag_name}, arg1, arg2, …);
$markup->end{tag_name}(); $markup->endTag({tag_name});
$markup->nl(); $markup->newline();
$markup->end(); $markup->endTag();

これらの省略記法を用いることで、例えば次のような記述が

$markup->div('css-class')->p->end->enddiv->nl;

次のようなメソッド呼び出しに変換されます。

$markup->startTag('div', 'css-class')
  ->startTag('p')->endTag()->endTag('div')->newline();

主要なメソッド

細かい動作についてはユニットテストも参考にしてください。

startTag($tag, [$attrs, $content $escapeContent]) $tagの開始タグを生成してバッファに追加します。$contentが与えられた場合は終了タグも追加します。

$tag string 必須 タグ名
$attrs string or array null HTML属性。文字列が与えられた場合はclass属性の値と見なされる
$content string null 要素の内容
$escapeContent boolean true trueの場合は$contentをHTMLエスケープする
endTag([$tag]) 終了タグを生成してバッファに追加します。$tagが与えられなかった場合は最も内側のタグを、$tagが与えられた場合は最も内側の$tagタグとその内側の全てのタグを閉じます。$tagが与えられ、かつ閉じるべき$tagが存在しない場合はE_USER_WARNINGとなります。

$tag string null タグ名
endAllTags() 全てのタグの終了タグを生成してバッファに追加します。
text([arg1, arg2, ...]) 任意の数の文字列をHTMLエスケープしてバッファに追加します。
html([arg1, arg2, ...]) 任意の数の文字列をそのままバッファに追加します。
newline() 改行(0x0A)をバッファに追加します。
renderElement([arg1, arg2, ...]) エレメントをレンダリングしてバッファに追加します。下記の説明を参照してください。

エレメントのレンダリング

エレメントをレンダリングするための専用メソッドとして、renderElement が用意されています。

echo $markup->div('search-result')->renderElement('search/result')->end;

もちろん html メソッドを使って、View の elementメソッドの戻り値をそのまま埋め込むこともできます。

echo $markup->div('search-result')->html($this->element('search/result'))->end;

ただしこの方法では MarkupHelper が内部で保持している文脈情報がそのままエレメント内に引き継がれます。エレメント内で endAllTags メソッドなどを呼んだ場合、意図しないタグまで閉じられてしまうことがあります。

MarkupHelper には文脈情報を隔離するために pushNewContext/popContext メソッドが用意されています。renderElement メソッドでは自動的にそれらのメソッドを呼び出し、エレメントのレンダリングが独立した文脈の中で実行されるようになっています。

echo $markup->div;   //
<div>
 
$markup->pushContext();
echo $markup->p->strong->text('foo')->endAllTags; //
 
<strong>foo</strong>
 
$markup->popContext();
 
echo $markup->end;  //</div>

他のヘルパーの中から使う

この pushNewContext/popContext メソッドを活用することで、他のヘルパーの中でも安全に MarkupHelper を使用できます。「生成したHTMLをバッファ変数に溜めておいて、最後にreturnする」という典型的なヘルパーの処理は、全て MarkupHelper が肩代わりしてくれます。

<?php
class YourHelper extends AppHepler
{
  var $helpers = array('markup');
  /**
   * 定義リスト
<dl>..</dl>
 
 を作るヘルパーメソッド
   */
  function defList($data)
  {
    $this->Markup->pushNewContext->dl->nl;
    foreach($data as $term => $desc) {
      $this->Markup
        ->dt->text($term)->end
        ->dd->html($desc)->end->nl;
    }
    return $this->Markup->endAllTgs->popContext;
  }
}
 
/* 使用例 */
echo $your->defList(aa('用語1', '<strong>説明1</strong>', '用語2', '説明2'));
 
/* 出力(改行もこの通りになります)
<dl>
<dt>用語1</dt>
<dd><strong>説明1</strong></dd>
<dt>用語2</dt>
<dd>説明2</dd>
</dl>
 
*/

One Response

  1. [...] MarkupHelper を更新。他のヘルパーのメソッドをチェーンして、戻り値をそのままHTMLの中に配置できるようになりました。 [...]

Leave a Reply