2007年刊行の『Smarty動的Webサイト構築入門』のサンプルコードをモダンにリファクタリングするシリーズ。今回は、各チャプターに散在していたテンプレートディレクトリの整理と、SmartyFactoryの導入によるインスタンス生成の一元化について解説します。
1. 修正前の課題と見直しのきっかけ
修正前のサンプルコードでは、チャプターごとに独立したディレクトリを切っており、それぞれの配下に templates や templates_c、そして index.php が配置されていました。
./
├── smartybook
│ ├── chapter4_1
│ │ ├── templates
│ │ │ └── index.tpl
│ │ ├── templates_c
│ │ └── index.php
│ └── chapter5_6
│ ├── templates
│ │ └── index.tpl
│ ├── templates_c
│ └── index.php
エンドポイントのPHPでも、以下のように個別に Smarty をインスタンス化してパスを設定していました。
$smarty = new Smarty();
$smarty->setTemplateDir('templates');
$smarty->setCompileDir('templates_c');
$smarty->assign('siteName', $siteName);
// 略
$smarty->display('index.tpl');
なぜ集約しようと考えたのか
リファクタリングを進める中で、一番最初に気になったのは各チャプター配下に templates_c が散在していることでした。まずはコンパイル済みのファイルが集まる templates_c をプロジェクトルートへ集約しようと考えたのが始まりです。
さらにAIと壁打ち(対話)しながら構造を吟味していたところ、「せっかくなら templates 自体もプロジェクトルート側に集約したほうが、現代的なディレクトリ設計(Pages / Components の分離など)に適合していてスマートだ」 という結論に至りました。そこで、コンパイル先だけでなくテンプレートそのものの置き場所もルート直下に集約することを決めました。
2. 修正後のディレクトリ構造とコード
集約後は、テンプレートおよびコンパイルディレクトリをルート直下に配置し、templates 内を components(共通部品)と pages(画面・チャプターごと)に整理しました。
./
└── smartybook
├── chapter4_1
│ └── index.php
├── chapter4_2_1
│ └── index.php
├── templates
│ ├── components
│ └── pages
│ ├── chapter4_1
│ │ └── index.tpl
│ └── chapter4_2_1
│ └── index.tpl
└── templates_c
設定と初期化のモダン化
設定定数を bootstrap/app.php にまとめ、Smarty のインスタンス生成を SmartyFactory クラスにカプセル化しました。
bootstrap/app.php https://github.com/ninton/smartybook/blob/main/bootstrap/app.php
define('SMARTY_CACHE_DIR', PROJECT_ROOT . '/cache');
define('SMARTY_COMPILE_DIR', PROJECT_ROOT . '/templates_c');
define('SMARTY_TEMPLATE_DIR', PROJECT_ROOT . '/templates');
app/Smarty/SmartyFactory.php https://github.com/ninton/smartybook/blob/main/app/Smarty/SmartyFactory.php
final readonly class SmartyFactory
{
public static function create(): Smarty
{
$smarty = new Smarty();
$smarty->setTemplateDir(SMARTY_TEMPLATE_DIR);
$smarty->setCompileDir(SMARTY_COMPILE_DIR);
$smarty->setCacheDir(SMARTY_CACHE_DIR);
return $smarty;
}
}
エンドポイントPHPでの呼び出し 例 https://github.com/ninton/smartybook/blob/main/smartybook/chapter4_1/index.php
use App\Smarty\SmartyFactory;
require_once dirname(__DIR__, 2) . '/bootstrap/app.php';
// 略
// テンプレートエンジン初期化・変数アサイン・描画
$smarty = SmartyFactory::create();
$smarty->assign('siteName', $siteName);
// 略
$smarty->display('pages/chapter4_1/index.tpl');
3. このリファクタリングのメリット
- ディレクトリ構造の集約と関心事の分離 (保守性の向上)
- 修正前: チャプターごとに
templatesやtemplates_cが散在しており、共通パーツの置き場所がなく、ファイルの重複や管理コスト増を招いていました。また公開ディレクトリ配下であり、ディレクトリごとに.htaccessを置いてアクセス拒否を書く必要があるので、設定ミスのリスクが増えます。 - 修正後: ルート直下に
templatesとtemplates_cを集約し、さらにcomponents(共通部品)とpages(画面ごと)に明確に階層分離されました。どこに何のファイルがあるかが一目でわかり、共通テンプレートの再利用が容易になります。
- 設定の一元化と DRY 原則の徹底
- 修正前: 各エンドポイントのPHPファイルで個別に Smarty のインスタンス化やパス設定を行っていました。設定変更時に修正するファイルが多いため、修正漏れのリスクがありました。
- 修正後:
bootstrap/app.phpでパス定数を一元定義し、共通設定として切り出したことで、ボイラープレートコード(重複コード)が削減されました。
- SmartyFactory によるカプセル化と拡張性の向上
- 修正前: インスタンス生成のロジックが各エンドポイントに直書きされていました。
- 修正後: ファクトリーパターン(
SmartyFactory::create())を導入したことで、インスタンスの初期化手順が一箇所に集約されています。今後、カスタムプラグインの登録やキャッシュ設定などを追加したい場合も、ファクトリー側を修正するだけで全エンドポイントに一括適用できます。
まとめ
プラシーボ効果(気分的なもの)も多少はあるかもしれませんが、「templates と templates_c をチャプター外に追い出して集約する」というたったこれだけの作業で、各 chapter ディレクトリの見通しが劇的に良くなりました。
各チャプターはエンドポイントPHPが目立つようになり、コードを読む際も「どの画面の処理か」「どのテンプレートを描画しているか」に集中できるようになります。レガシーコードの改善において、ファイルを整理して視覚的なノイズを減らすことのインパクトを改めて実感したリファクタリングでした。
参考コード
- https://github.com/ninton/smartybook/blob/main/bootstrap/app.php
- https://github.com/ninton/smartybook/blob/main/app/Smarty/SmartyFactory.php
- https://github.com/ninton/smartybook/blob/main/smartybook/chapter4_1/index.php

