コンテンツにスキップ

Smartyの基本

2.5.x: Smarty 3 4.0.x: Smarty 4

Smartyは、開発者がプレゼンテーション(HTML/CSS)をアプリケーションロジックから分離することを可能にするPHP用テンプレートエンジンです。XOOPSはすべてのテンプレート処理にSmartyを使用し、PHPコードとHTML出力の間にきれいな分離を実現しています。

  • テーマ開発 - XOOPSテーマの作成
  • テンプレート変数 - テンプレートで利用可能な変数
  • Smarty 4マイグレーション - Smarty 3からSmarty 4へのアップグレード

Smartyが提供するもの:

  • 関心の分離: HTMLをテンプレートに、PHPロジックをクラスに保持
  • テンプレート継承: シンプルなブロックから複雑なレイアウトを構築
  • キャッシング: コンパイルされたテンプレートでパフォーマンスを向上
  • 修飾子: 組み込みまたはカスタム関数で出力を変換
  • セキュリティ: テンプレートがアクセスできるPHP関数を制御

XOOPSはカスタムデリミタでSmartyを設定しています:

デフォルトSmarty: { と }
XOOPSでのSmarty: <{ と }>

これはテンプレート内のJavaScriptコードの競合を防ぎます。

変数はPHPからテンプレートに渡されます:

// PHP内
$GLOBALS['xoopsTpl']->assign('title', 'My Page Title');
$GLOBALS['xoopsTpl']->assign('count', 42);
{* テンプレート内 *}
<h1><{$title}></h1>
<p>Total items: <{$count}></p>
// PHP
$item = [
'id' => 1,
'title' => 'Article Title',
'author' => 'John Doe'
];
$GLOBALS['xoopsTpl']->assign('item', $item);
{* テンプレート *}
<h2><{$item.title}></h2>
<p>By: <{$item.author}></p>
// PHP
$GLOBALS['xoopsTpl']->assign('user', $xoopsUser);
{* テンプレート *}
<p>Welcome, <{$user->getVar('uname')}>!</p>

SmartyのコメントはHTMLに表示されません:

{* このコメントはHTML出力に表示されません *}
{*
複数行コメント
もサポートされています
*}
<{if $user_logged_in}>
<p>お帰りなさい!</p>
<{elseif $is_guest}>
<p>こんにちは、ゲスト!</p>
<{else}>
<p>ログインしてください。</p>
<{/if}>
{* 等号 *}
<{if $status == 'published'}>公開<{/if}>
<{if $status eq 'published'}>公開<{/if}>
{* 不等号 *}
<{if $count != 0}>アイテムがあります<{/if}>
<{if $count neq 0}>アイテムがあります<{/if}>
{* より大きい/小さい *}
<{if $count > 10}>多くのアイテム<{/if}>
<{if $count gt 10}>多くのアイテム<{/if}>
<{if $count < 5}>少ないアイテム<{/if}>
<{if $count lt 5}>少ないアイテム<{/if}>
{* 以上/以下 *}
<{if $count >= 10}>10以上<{/if}>
<{if $count gte 10}>10以上<{/if}>
<{if $count <= 5}>5以下<{/if}>
<{if $count lte 5}>5以下<{/if}>
{* 論理演算子 *}
<{if $logged_in && $is_admin}>管理パネル<{/if}>
<{if $logged_in and $is_admin}>管理パネル<{/if}>
<{if $option1 || $option2}>1つのオプションが選択されました<{/if}>
<{if $option1 or $option2}>1つのオプションが選択されました<{/if}>
<{if !$is_banned}>アクセス許可<{/if}>
<{if not $is_banned}>アクセス許可<{/if}>
{* 変数が存在し、値を持っているかを確認 *}
<{if $title}>
<h1><{$title}></h1>
<{/if}>
{* 配列が空でないことを確認 *}
<{if $items|@count > 0}>
<ul>
<{foreach $items as $item}>
<li><{$item.name}></li>
<{/foreach}>
</ul>
<{/if}>
{* issetを使用 *}
<{if isset($description)}>
<p><{$description}></p>
<{/if}>
{* 基本的なforeach *}
<ul>
<{foreach $items as $item}>
<li><{$item.name}></li>
<{/foreach}>
</ul>
{* キー付き *}
<{foreach $options as $key => $value}>
<option value="<{$key}>"><{$value}></option>
<{/foreach}>
{* @index、@first、@lastとともに *}
<{foreach $items as $item}>
<{if $item@first}><ul><{/if}>
<li class="item-<{$item@index}>"><{$item.name}></li>
<{if $item@last}></ul><{/if}>
<{/foreach}>
{* 行の色を交互に *}
<{foreach $rows as $row}>
<tr class="<{if $row@iteration is odd}>odd<{else}>even<{/if}>">
<td><{$row.name}></td>
</tr>
<{/foreach}>
{* 空配列の場合 *}
<{foreach $items as $item}>
<li><{$item.name}></li>
<{foreachelse}>
<li>アイテムが見つかりません。</li>
<{/foreach}>
<{for $i=1 to 10}>
<p>アイテム <{$i}></p>
<{/for}>
<{for $i=10 to 1 step -1}>
<p>カウントダウン: <{$i}></p>
<{/for}>
<{while $count > 0}>
<p><{$count}></p>
<{$count = $count - 1}>
<{/while}>

修飾子は変数出力を変換します:

{* HTMLエスケープ(ユーザー入力には常に使用!) *}
<{$title|escape}>
<{$title|escape:'html'}>
{* URLエンコード *}
<{$url|escape:'url'}>
{* 大文字/小文字 *}
<{$name|upper}>
<{$name|lower}>
<{$name|capitalize}>
{* テキストを切り詰める *}
<{$content|truncate:100:'...'}>
{* HTMLタグを削除 *}
<{$html|strip_tags}>
{* 置換 *}
<{$text|replace:'old':'new'}>
{* 単語折り返し *}
<{$text|wordwrap:80:"\n"}>
{* デフォルト値 *}
<{$optional_var|default:'No value'}>
{* 数値フォーマット *}
<{$price|string_format:"%.2f"}>
<{$count|number_format}>
{* 日付フォーマット *}
<{$timestamp|date_format:"%B %e, %Y"}>
<{$timestamp|date_format:"%Y-%m-%d %H:%M"}>
{* アイテムをカウント *}
<{$items|@count}> items
{* 配列を結合 *}
<{$tags|@implode:', '}>
{* JSONエンコード *}
<{$data|@json_encode}>
<{$content|strip_tags|truncate:200:'...'|escape}>

ファイルのインクルードと挿入

Section titled “ファイルのインクルードと挿入”

他のテンプレートをインクルード

Section titled “他のテンプレートをインクルード”
{* テンプレートファイルをインクルード *}
<{include file="db:mymodule_header.tpl"}>
{* 変数付きでインクルード *}
<{include file="db:mymodule_item.tpl" item=$currentItem}>
{* 割り当てられた変数でインクルード *}
<{include file="db:sidebar.tpl" assign="sidebar_content"}>
<div class="sidebar"><{$sidebar_content}></div>
{* 動的コンテンツ用のPHP関数を呼び出す *}
<{insert name="getBanner"}>

テンプレート内で変数を割り当て

Section titled “テンプレート内で変数を割り当て”
{* シンプルな割り当て *}
<{assign var="page_title" value="Welcome"}>
<{$page_title = "Welcome"}>
{* 式からの割り当て *}
<{assign var="full_name" value="`$first_name` `$last_name`"}>
{* ブロックコンテンツをキャプチャ *}
<{capture name="sidebar"}>
<h3>サイドバー</h3>
<ul>
<li>Link 1</li>
<li>Link 2</li>
</ul>
<{/capture}>
<div class="sidebar"><{$smarty.capture.sidebar}></div>
{* 現在のタイムスタンプ *}
<{$smarty.now|date_format:"%Y-%m-%d"}>
{* リクエスト変数 *}
<{$smarty.get.page}>
<{$smarty.post.username}>
<{$smarty.request.id}>
<{$smarty.cookies.session_id}>
<{$smarty.server.HTTP_HOST}>
{* 定数 *}
<{$smarty.const.XOOPS_URL}>
{* 設定変数 *}
<{$smarty.config.var_name}>
{* テンプレート情報 *}
<{$smarty.template}>
<{$smarty.current_dir}>
{* Smartyバージョン *}
<{$smarty.version}>
{* セクション/Foreachプロパティ *}
<{$smarty.foreach.items.index}>
<{$smarty.foreach.items.iteration}>
<{$smarty.foreach.items.first}>
<{$smarty.foreach.items.last}>

JavaScriptで波括弧を使用する場合:

<{literal}>
<script>
var config = {
url: 'https://example.com',
count: 10
};
if (config.count > 5) {
console.log('Many items');
}
</script>
<{/literal}>

またはSmarty変数をJavaScript内で使用:

<script>
var moduleUrl = '<{$xoops_url}>/modules/mymodule';
var items = <{$items_json}>;
</script>

XOOPSはカスタムSmarty関数を提供します:

{* XOOPSイメージURL *}
<img src="<{xoImgUrl}>images/logo.png" alt="Logo">
{* XOOPSモジュールURL *}
<a href="<{xoModuleUrl}>">Module Home</a>
{* アプリURL *}
<a href="<{xoAppUrl 'item.php'}>?id=<{$item.id}>">View Item</a>
{* ユーザー生成コンテンツの場合は常にエスケープ *}
<p><{$user_comment|escape}></p>
{* HTMLコンテンツの場合は適切なメソッドを使用 *}
<div><{$content}></div> {* コンテンツが事前にサニタイズされている場合のみ *}
// 良い
$GLOBALS['xoopsTpl']->assign('article_title', $title);
$GLOBALS['xoopsTpl']->assign('article_items', $items);
// 避けるべき
$GLOBALS['xoopsTpl']->assign('t', $title);
$GLOBALS['xoopsTpl']->assign('arr', $items);

テンプレートはプレゼンテーションに焦点を当てるべきです。複雑なロジックはPHPに移動してください:

{* テンプレートで複雑なロジックを避ける *}
{* 悪い *}
<{if $user && $user->getVar('level') > 5 && $user->getVar('status') == 'active' && $permissions|in_array:'edit'}>
{* 良い - PHPで計算して単純なフラグを渡す *}
<{if $can_edit}>

一貫したレイアウトのために、テンプレート継承を使用してください(テーマ開発を参照)。

{* 割り当てられたすべての変数を表示 *}
<{debug}>
{* 特定の変数をデバッグ *}
<pre><{$variable|@print_r}></pre>
<pre><{$variable|@var_export}></pre>

一般的なXOOPSテンプレートパターン

Section titled “一般的なXOOPSテンプレートパターン”
{* モジュールヘッダー *}
<div class="mymodule">
<h2><{$module_name}></h2>
{* パンくずリスト *}
<{if $breadcrumb}>
<nav class="breadcrumb">
<{foreach $breadcrumb as $crumb}>
<{if $crumb@last}>
<span><{$crumb.title}></span>
<{else}>
<a href="<{$crumb.link}>"><{$crumb.title}></a> &raquo;
<{/if}>
<{/foreach}>
</nav>
<{/if}>
{* コンテンツ *}
<div class="content">
<{$content}>
</div>
</div>
<{if $page_nav}>
<div class="pagination">
<{$page_nav}>
</div>
<{/if}>
<{if $form}>
<div class="form-container">
<{$form}>
</div>
<{/if}>

#smarty #テンプレート #xoops #フロントエンド #テンプレートエンジン