5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HTMLoader作ってみた - HTMLとPHPを分離したい一心で -

Last updated at Posted at 2017-12-25

#HTMLoader
HTMLとPHPが混在しているコードって見づらくないですか?
私ダメなんですよあれ。

hoge.php
<div><?php echo $menu["name"]; ?></div>

これをなんとか解決してみようと思います。
多分世の中にはすでにあるんでしょうけど、PHPへの理解を深める勉強と思いHTMLoaderを作ってみました。

--追記 2017.12.28
これってテンプレートエンジンって言われてるものなんですね。知らなかったです。
Twigっていう有名なすごいものがすでにあってビックリしました。
しかもすごく文法( {{data.abc}}とか )似てて、二番煎じ感が恥ずかしいです。
AnglarJSの書き方をイメージしたんですけどね。

#Git
サンプル含めファイルをGitHubに上げました。
HTMLoader

#基本的な処理
いろんなやり方があると思いますが、私が思いついたのはこれだけでした。

  1. phpファイルとhtmlファイルを用意する。
  2. phpファイルでhtmlを読み込む。
  3. html内のとある決められた記号を置き換えていく。(表示内容の流し込み)

#使用方法
##ファイル構造

  • www/
    • HTMLoader.php
    • index.php
    • _tmpl.html
    • config.json
      • parts/
        • head.html
        • header.html
        • footer.html
      • info/
        • index.php
        • _tmpl.html
        • config.json
    • 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/内のファイル
###テンプレートファイル_tmpl.html
_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="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

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

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

parts/head.html
<meta charset='utf8'>
<meta name="viewport" content='width=device-width,initial-scale=1'>

###ヘッダーパーツ parts/header.html

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

parts/footer.html
<footer>
	Copyright (c) 2017 KotaTakeuchi
</footer>
info/内のファイル

###テンプレートファイル_tmpl.html

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

info/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

info/config.json
{
	"layer": 1,
	"parts_layer": 0,
	"title": "Information | HTMLoaderの使い方"
}

#何をしているのか
処理の順序をひたすらに列挙してみます。

  1. テンプレートファイル(_tmpl.html)の読み込み。
  2. 設定ファイル(config.json)の読み込み。
  3. setDataにより記号文字列と値のセットを設定(値として設定できるのは、プリミティブ型・オブジェクト)
  4. setIfにより記号文字列と真偽値のセットを設定
  5. ヘッダー前・テンプレート前・テンプレート後・フッター後にそれぞれHTMLを差し込みたい場合、addHtmlBeforeTemplate($html)などのメソッドを使用して設定。(同じパーツを使用してもindex.phpによって自由にmetaタグを追加したりできる)
  6. パーツディレクトリ内の各種パーツを取得。
  7. 各種パーツを以下の順につなげて出力HTMLを作る。
    1. ヘッドパーツ
    2. ヘッダー前HTML
    3. ヘッダーパーツ
    4. テンプレート前HTML
    5. テンプレート
    6. テンプレート後HTML
    7. フッターパーツ
    8. フッター後
  8. <!-- load tmpl 〜〜〜.html -->という記述があればそこに〜〜〜.htmlの内容を差し込む。(テンプレートファイルの分割が可能になる。)
  9. {{$ROOT}}記号を自身の階層nから階層0までの相対パスに置換する。(nが1なら../。nが3なら../../../)
  10. <!-- if isOk -->hogehoge<!-- endif isOk -->文字列がHTML内にあれば、setIfで設定された真偽値によって表示あるいは非表示する。
  11. {{data.☆☆☆}}{{data.◯◯◯.△△△}}<!-- each data.□□□ start--> [[data.□□□.◇◇◇]] <!-- each data.□□□ end-->などの文字列をそれぞれ置換する。
  12. {{ %〜〜 }}は関数となっていて、配列の要素数(%COUNT)やJSONエンコード(%JSON_ENCODE)などができる。
  13. <!-- if ◯◯ == △△ --> TRUE <!-- else --> FALSE <!-- endif -->文字列がHTML内にあれば、真偽値次第で表示を変える。
  14. <!-- if ◯◯ == △△ --> TRUE <!-- endif -->文字列がHTML内にあれば、真偽値次第で表示あるいは非表示する。
  15. {{ if ◯◯ == △△ ? A : B }}文字列がHTML内にあれば、三項演算を行い表示を変える。
  16. HTMLoaderで特殊文字(値がNullの場合は$NULLという特殊文字に置換される)に置換されたものがあればそれを削除する。
  17. 出来上がった文字列を画面に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.

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?