Last active
December 29, 2015 16:49
-
-
Save yuka2py/7700417 to your computer and use it in GitHub Desktop.
PHP 自体をテンプレートエンジンとして利用するための簡単なユーティリティ。Django 風の extend、block、capture、strip などを備えている。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* echo のエイリアス | |
* @return void | |
*/ | |
function e($text) { | |
echo $text; | |
} | |
/** | |
* htmlspecialchars のエイリアス | |
* @return string | |
*/ | |
function h($text) { | |
return htmlspecialchars($text); | |
} | |
/** | |
* echo + htmlspecialchars のエイリアス | |
* @return void | |
*/ | |
function eh($text) { | |
echo htmlspecialchars($text); | |
} | |
/** | |
* render::display() のエイリアス | |
* @param string $view ビューファイル | |
* @param array $vars このレンダリングで使用する変数 | |
* @return void | |
*/ | |
function render($view, $vars=array()) { | |
render::display($view, $vars); | |
} | |
/** | |
* PHP 自体をテンプレートエンジンとして利用するための簡単なユーティリティ | |
*/ | |
class render | |
{ | |
public static $view_directory = ''; | |
public static $view_file_sufix = ''; | |
private static $vars = array(); | |
private static $extend_view = null; | |
private static $extend_vars = array(); | |
private static $extend_ancestor_blocks = array(); | |
private static $block_stack = array(); | |
private static $block_contents = array(); | |
/** | |
* ビューをレンダリングして結果を文字列で取得する。 | |
* @param string $view ビューファイル | |
* @param array $vars このレンダリングで使用する変数 | |
* @return string | |
*/ | |
public static function to_string($view, $vars=array()) { | |
ob_start(); | |
self::display($view, $vars); | |
return ob_get_clean(); | |
} | |
/** | |
* $view をレンダリングして表示する。 | |
* @param string $view ビューファイル | |
* @param array $vars このレンダリングで使用する変数 | |
* @return void | |
*/ | |
public static function display($view, $vars=array()) { | |
$____view = self::get_view_filepath($view); | |
$____vars = $vars; | |
extract(self::$vars); //デフォルト指定の変数 | |
extract(self::$extend_vars); //継承による変数 | |
extract($____vars); //ここで指定された変数 | |
require $____view; | |
} | |
/** | |
* ビューファイルのパスを取得する。 | |
* @param string $view ビューファイル | |
* @return string | |
*/ | |
private static function get_view_filepath($view) { | |
return self::$view_directory | |
. DIRECTORY_SEPARATOR | |
. $view . self::$view_file_sufix; | |
} | |
/** | |
* レンダラのデフォルト変数を設定する。 | |
* レンダラのデフォルト変数は、全てのレンダリングで利用できる。 | |
* 連想配列、または名前を値を指定して設定できる。 | |
* @param mixed $one | |
* @param mixed $two | |
* @return void | |
*/ | |
public static function setvar($one, $two=null) { | |
if (is_array($one)) { | |
self::$vars = array_merge(self::$vars, $one); | |
} else { | |
self::$vars[$one] = $two; | |
} | |
} | |
/** | |
* レンダラのデフォルト変数を取得する。 | |
* @param string $name 変数名 | |
* @param mixed $default 変数が未定義の時に返される値 | |
* @return mixed | |
*/ | |
public static function getvar($name, $default=null) { | |
return isset(self::$vars[$name]) ? self::$vars[$name] : $default; | |
} | |
/** | |
* 継承を開始する。 | |
* @param string $view ビューファイル | |
* @param array $vars 継承するテンプレートで利用したい変数 | |
* @return void | |
*/ | |
public static function extend($view, $vars=array()) { | |
self::$extend_view = $view; | |
self::$extend_vars = array_merge($vars, self::$extend_vars); //開発注:この順番は正しい。self::$extend_vars の方が、より子で指定された値になる | |
self::capture(); | |
} | |
/** | |
* 継承を終了する | |
* @return void | |
*/ | |
public static function end_extend() { | |
$content = self::end_capture(); | |
$view = self::$extend_view; | |
$vars = self::$extend_vars; | |
self::$extend_view = null; | |
self::$block_contents['__content'] = array($content, 'append'); | |
self::display($view, $vars); | |
} | |
/** | |
* 継承の祖先にブロックがあるか確認する | |
* @param string $block | |
* @return bool | |
*/ | |
private static function exists_block_in_ancestors($block) { | |
if (empty(self::$extend_view)) { | |
return array(); | |
} else { | |
$ancestor_blocks = self::get_ancestor_blocks(self::$extend_view); | |
return in_array($block, $ancestor_blocks); | |
} | |
} | |
/** | |
* 継承の祖先に含まれるブロック名の一覧を返す。 | |
* @param string $parent 継承したビューファイル | |
* @return array<string> | |
*/ | |
private static function get_ancestor_blocks($parent) { | |
$parent = self::get_view_filepath($parent); | |
if (!isset(self::$extend_ancestor_blocks[$parent])) { | |
$blocks = array(); | |
$view = file_get_contents($parent); | |
if (preg_match_all('/render::(?:block|load_block)\(\s*["\']([^"\']+)["\']\s*/', $view, $matches, PREG_PATTERN_ORDER)) { | |
$blocks = $matches[1]; | |
} | |
if (preg_match('/render::extend\(\s*["\']([^"\']+)["\']\s*/', $view, $matches)) { | |
$more_parent = $matches[1]; | |
$ancestor_blocks = self::get_ancestor_blocks($more_parent); | |
$blocks = array_merge($blocks, $ancestor_blocks); | |
$blocks = array_unique($blocks); | |
} | |
self::$extend_ancestor_blocks[$parent] = $blocks; | |
} | |
return self::$extend_ancestor_blocks[$parent]; | |
} | |
/** | |
* ブロックの定義を開始する | |
* @param string $block ブロックの名前 | |
* @param mixed $method 既にブロック変数が定義済みの場合、このブロックの内容を後ろに追加する場合には 'append' を指定、前に追加する場合には 'prepend' を指定する。デフォルトは false で追加せず上書きする | |
* @return void | |
*/ | |
public static function block($block, $method=false) { | |
array_push(self::$block_stack, array($block, $method)); | |
self::capture(); | |
} | |
/** | |
* ブロックの定義を開始する。 | |
* ブロックは継承元ブロックの後ろに追加される。 | |
* @param string $block ブロックの名前 | |
* @return void | |
*/ | |
public static function block_append($block) { | |
array_push(self::$block_stack, array($block, 'append')); | |
self::capture(); | |
} | |
/** | |
* ブロックの定義を開始する。 | |
* ブロックは継承元ブロックの前に追加される。 | |
* @param string $block ブロックの名前 | |
* @return void | |
*/ | |
public static function block_prepend($block) { | |
array_push(self::$block_stack, array($block, 'prepend')); | |
self::capture(); | |
} | |
/** | |
* ブロックの定義を終了する | |
* @return string ブロックの内容 | |
*/ | |
public static function end_block() { | |
$content = self::end_capture(); | |
list($block, $method) = array_pop(self::$block_stack); | |
//オーバーライドされたブロックがある場合(既にブロックデータが存在した場合) | |
if (isset(self::$block_contents[$block])) { | |
list($pre_content, $pre_method) = self::$block_contents[$block]; | |
//前に追加 | |
if ('append' === $pre_method) { | |
$content = $content . $pre_content; | |
} | |
//前に追加 | |
else if ('prepend' === $pre_method) { | |
$content = $pre_content . $content; | |
} | |
//オーバーライド | |
else { | |
$content = $pre_content; | |
} | |
} | |
//ブロックデータとして保存 | |
self::$block_contents[$block] = array($content, $method); | |
//上位にブロックが無いとき、または __content ブロックなら出力 | |
if ($block === '__content' or !self::exists_block_in_ancestors($block)) { | |
echo $content; | |
} | |
return $content; | |
} | |
/** | |
* 登録されているブロックをロードする | |
* @param string $block ブロックの名前 | |
* @return void | |
*/ | |
public static function load_block($block) { | |
render::block($block); | |
render::end_block(); | |
} | |
/** | |
* extend でオーバーライドされたコンテンツをロードする | |
* @return void | |
*/ | |
public static function load_content() { | |
render::block('__content'); | |
render::end_block(); | |
} | |
/** | |
* キャプチャーを開始する | |
* @return void | |
*/ | |
public static function capture() { | |
ob_start(); | |
} | |
/** | |
* キャプチャーを終了する | |
* @return string キャプチャした内容 | |
*/ | |
public static function end_capture() { | |
return ob_get_clean(); | |
} | |
/** | |
* 改行やタブを取り除く範囲を開始する | |
* @return void | |
*/ | |
public static function strip() { | |
self::capture(); | |
} | |
/** | |
* 改行やタブを取り除く範囲を終了する | |
* @return void | |
*/ | |
public static function end_strip() { | |
$content = self::end_capture(); | |
$content = str_replace("\n", '', $content); | |
$content = str_replace("\r", '', $content); | |
$content = str_replace("\t", '', $content); | |
echo $content; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
使い方
require_once 'render.php';
render::$view_directory = '/home/projects/mywebapp/views'; //ビューファイルが配置されるディレクトリ
render('index.html.php');
_partial.html.php
<div class="cute">わたし?</div>
_layout.html.php
<body>
<h1></h1>
</body>
index.html.php
'トップページ')) ?>ほげほーげ。
over ride sidevar contents
OUTPUT
<!DOCTYPE html>
<body>
<h1>トップページ</h1>
ほげほーげ。
<div id="sidevar">
over ride sidevar contents
</div>
<div class="cute">わたし?</div>
</body>