#HTMLoader
HTMLとPHPが混在しているコードって見づらくないですか?
私ダメなんですよあれ。
<div><?php echo $menu["name"]; ?></div>
これをなんとか解決してみようと思います。
多分世の中にはすでにあるんでしょうけど、PHPへの理解を深める勉強と思いHTMLoaderを作ってみました。
--追記 2017.12.28
これってテンプレートエンジンって言われてるものなんですね。知らなかったです。
Twigっていう有名なすごいものがすでにあってビックリしました。
しかもすごく文法( {{data.abc}}とか )似てて、二番煎じ感が恥ずかしいです。
AnglarJSの書き方をイメージしたんですけどね。
#Git
サンプル含めファイルをGitHubに上げました。
HTMLoader
#基本的な処理
いろんなやり方があると思いますが、私が思いついたのはこれだけでした。
- phpファイルとhtmlファイルを用意する。
- phpファイルでhtmlを読み込む。
- html内のとある決められた記号を置き換えていく。(表示内容の流し込み)
#使用方法
##ファイル構造
- www/
- HTMLoader.php
- index.php
- _tmpl.html
- config.json
- parts/
- head.html
- header.html
- footer.html
- info/
- index.php
- _tmpl.html
- config.json
- parts/
- jquery.js
##各ファイル・ディレクトリ説明
- www/
- ドキュメントルート。
- HTMLoader.php
- HTMLoaderファイル。
- index.php
- HTMLoaderのインスタンスを作成し、表示内容を流し込む。
- _tmpl.html
- 通称テンプレートファイル。HTMLoaderに読み込まれる。
- config.json
- 通称設定ファイル。現在の階層や、パーツディレクトリのある階層。サイトタイトルなどの設定を書き込む。
- parts/
- 通称パーツディレクトリ。
- head.html
- 通称ヘッドパーツ。全ページで共通してheadタグ内に書かれるもの。
- header.html
- 通称ヘッダーパーツ。全ページ共通のヘッダーが書かれたHTML。
- footer.html
- 通称フッターパーツ。全ページ共通のフッターが書かれたHTML。
- info/
- infoページディレクトリ。
- jquery.js/
- 例としてJQueryのjsファイルを置いてみる。
##導入の一例
parts/内のファイル
<h2>{{data.page_title}}</h2>
<section id="message" class="content">
<h1>{{data.msg.title}}</h1>
<p>{{data.msg.text}}</p>
</section>
<section id="notice" class="content">
<!-- each data.notices start -->
<section>
<h1>[[data.notices.title]]</h1>
<p>[[data.notices.text]]</p>
</section>
<!-- each data.notices end -->
<!-- if {{ %COUNT data.notices }} == 0 -->
<p>現在、お知らせはありません。</p>
<!-- endif -->
</section>
<!-- if isAprilFools -->
<section id="april_fools" class="content">
<p>本日はエイプリルフールですね。</p>
</section>
<!-- endif isAprilFools -->
<script src="{{$ROOT}}/jquery.js"></script>
###index.php
<?php
include_once($_SERVER["DOCUMENT_ROOT"]."/HTMLoader.php");
// テンプレートファイルのファイル名を指定
// 指定がなければ"_tmpl.html"が読み込まれる。今回はわかりやすいようにあえて記述した。
$loader = new HTMLoader("_tmpl.html");
$msg = [
"title" => "メッセージタイトル",
"text" => "メッセージ内容"
];
$notices = [
[
"title" => "お知らせ1",
"text" => "これはお知らせ1の内容です。"
],
[
"title" => "お知らせ2",
"text" => "これはお知らせ2の内容です。"
],
[
"title" => "お知らせ3",
"text" => "これはお知らせ3の内容です。"
],
];
$loader->setData("site_title",$loader->getTitle());
$loader->setData("page_title","ページタイトル");
$loader->setData("msg",$msg);
$loader->setData("notices",$notices);
$dt = new DateTime();
$loader->setIf("isAprilFools","04/01"===$dt->format("m/d"));
echo $loader->output();
?>
###設定ファイル config.json
{
"layer": 0,
"parts_layer": 0,
"title": "HTMLoaderの使い方"
}
- layer
- 必須。現在の階層。これが0のところが起点となり、そこから下の階層は1ずつ増やしていく。
- parts_layer
- 必須。パーツディレクトリのある階層を入力。
- title
- サイトタイトル。HTMLoaderのsetTitle($title)で設定できる。
- parts_dir
- パーツディレクトリ名。指定がなければ"parts"。HTMLoaderのsetPartsDir($name)で設定できる。
- parts_head_name
- パーツディレクトリ内のヘッドパーツのファイル名。指定がなければ"head.html"。HTMLoaderのsetPartsHeadName($name)で設定できる。
- parts_header_name
- パーツディレクトリ内のヘッダーパーツのファイル名。指定がなければ"header.html"。HTMLoaderのsetPartsHeaderName($name)で設定できる。
- parts_footer_name
- パーツディレクトリ内のフッターパーツのファイル名。指定がなければ"footer.html"。HTMLoaderのsetPartsFooterName($name)で設定できる。
parts/内のファイル
###ヘッドパーツ parts/head.html
<meta charset='utf8'>
<meta name="viewport" content='width=device-width,initial-scale=1'>
###ヘッダーパーツ parts/header.html
<header>
<h1>{{data.site_title}}</h1>
</header>
<nav>
<a href="{{$ROOT}}">Top</a>
<a href="{{$ROOT}}info/">Information</a>
</nav>
###フッターパーツ parts/footer.html
<footer>
Copyright (c) 2017 KotaTakeuchi
</footer>
info/内のファイル
###テンプレートファイル_tmpl.html
<h2>{{data.page_title}}</h2>
<section id="message" class="content">
<h1>{{data.msg.title}}</h1>
<p>{{data.msg.text}}</p>
</section>
<section id="functions" class="content">
<table>
<!-- each data.functions start -->
<tr>
<th>[[data.functions.name]]</th>
<td>[[data.functions.description]]</td>
</tr>
<!-- each data.functions end -->
</table>
</section>
<script src="{{$ROOT}}/jquery.js"></script>
###index.php
<?php
include_once($_SERVER["DOCUMENT_ROOT"]."/HTMLoader.php");
// テンプレートファイルのファイル名を指定
// 指定がなければ"_tmpl.html"が読み込まれる。今回はわかりやすいようにあえて記述した。
$loader = new HTMLoader("_tmpl.html");
$msg = [
"title" => "使用している関数",
"text" => "このページ内で使用している関数のご紹介"
];
$functions = [
[
"name" => 'setData($Symbol,$Data)',
"description" => HTMLoader::h(' "{{ data.$Symbol }}" -> $Data.
If $Data is hash, "{{ data.\$Symbol.key }}"" -> $Data["key"]
If $Data is array, "<!-- each data.$Symbol start --> [[data.$Symbol.key]] <!-- each data.$Symbol end -->" . Repeat count($Data) times. [[data.$Symbol.key]] -> ($Data[0][key],$Data[1][key]...).
'),
],[
"name" => 'setIf($Symbol,$Boolean)',
"description" => HTMLoader::h('"<!-- if $Symbol --> TRUE! <!-- endif $Symbol -->" If $Boolean is true, Display "TRUE!". '),
],[
"name" => "output()",
"description" => 'Output html string.',
],[
"name" => "getTitle()",
"description" => 'Get title is Written in config.json ',
],
];
$loader->setData("site_title",$loader->getTitle());
$loader->setData("page_title","Information");
$loader->setData("msg",$msg);
$loader->setData("functions",$functions);
$dt = new DateTime();
$loader->setIf("isAprilFools","04/01"===$dt->format("m/d"));
echo $loader->output();
?>
###設定ファイル config.json
{
"layer": 1,
"parts_layer": 0,
"title": "Information | HTMLoaderの使い方"
}
#何をしているのか
処理の順序をひたすらに列挙してみます。
- テンプレートファイル(_tmpl.html)の読み込み。
- 設定ファイル(config.json)の読み込み。
- setDataにより記号文字列と値のセットを設定(値として設定できるのは、プリミティブ型・オブジェクト)
- setIfにより記号文字列と真偽値のセットを設定
- ヘッダー前・テンプレート前・テンプレート後・フッター後にそれぞれHTMLを差し込みたい場合、addHtmlBeforeTemplate($html)などのメソッドを使用して設定。(同じパーツを使用してもindex.phpによって自由にmetaタグを追加したりできる)
- パーツディレクトリ内の各種パーツを取得。
- 各種パーツを以下の順につなげて出力HTMLを作る。
- ヘッドパーツ
- ヘッダー前HTML
- ヘッダーパーツ
- テンプレート前HTML
- テンプレート
- テンプレート後HTML
- フッターパーツ
- フッター後
-
<!-- load tmpl 〜〜〜.html -->
という記述があればそこに〜〜〜.htmlの内容を差し込む。(テンプレートファイルの分割が可能になる。) -
{{$ROOT}}
記号を自身の階層nから階層0までの相対パスに置換する。(nが1なら../。nが3なら../../../) -
<!-- if isOk -->hogehoge<!-- endif isOk -->
文字列がHTML内にあれば、setIfで設定された真偽値によって表示あるいは非表示する。 -
{{data.☆☆☆}}
、{{data.◯◯◯.△△△}}
、<!-- each data.□□□ start--> [[data.□□□.◇◇◇]] <!-- each data.□□□ end-->
などの文字列をそれぞれ置換する。 -
{{ %〜〜 }}
は関数となっていて、配列の要素数(%COUNT)やJSONエンコード(%JSON_ENCODE)などができる。 -
<!-- if ◯◯ == △△ --> TRUE <!-- else --> FALSE <!-- endif -->
文字列がHTML内にあれば、真偽値次第で表示を変える。 -
<!-- if ◯◯ == △△ --> TRUE <!-- endif -->
文字列がHTML内にあれば、真偽値次第で表示あるいは非表示する。 -
{{ if ◯◯ == △△ ? A : B }}
文字列がHTML内にあれば、三項演算を行い表示を変える。 - HTMLoaderで特殊文字(値がNullの場合は$NULLという特殊文字に置換される)に置換されたものがあればそれを削除する。
- 出来上がった文字列を画面にechoする。
#作って良かった点
- まみれだったHTMLがすっきり!
- DBから取得したデータを簡単に表示できるようになりました。
- HTMLとPHPが分離したことでデザイナーとプログラマーの分業が進んだ。
- 自由度重視で作ったのでどんなサイトにも意外と使えた。
#悩み
<!-- if isOk -->hogehoge<!-- endif isOk -->
これはネストできる。
<!-- if ◯◯ == △△ --> TRUE <!-- else --> FALSE <!-- endif -->
これはネストできない。
いつか直したい。
[追記 2018-01-20]
IF文ネストできるようになりました。
setDataに渡せる値はArray型のみでしたが、オブジェクトにも多分対応しました。
#ライセンス
This software is released under the MIT License.