---
title: "ビューと Smarty"
description: ".tplテンプレートの解決、View::assignパイプライン、キャッシュ、および共有部分テンプレートについて。"
---

Nibiruのビューは**Smarty 3**テンプレートです。各コントローラーにはデフォルトのテンプレートがあり、ネストされたアクションはそれぞれ独自のテンプレートを持つことができます。`View`シングルトンはSmartyエンジンをラップし、1つのグローバルヘルパーを公開しています：`View::assign()`。

## テンプレートの場所
```
application/view/
├── templates/                # source .tpl files (you write these)
│   ├── index.tpl             # → indexController::pageAction()
│   ├── products.tpl          # → productsController::pageAction()
│   ├── products/
│   │   └── detail.tpl        # → productsController::detailAction()
│   ├── shared/
│   │   ├── header.tpl
│   │   ├── footer.tpl
│   │   └── meta.tpl
│   ├── navigation.tpl
│   └── pageination.tpl       # (note the spelling)
├── templates_c/              # Smarty compile cache (auto)
├── cache/                    # rendered HTML cache (when caching=true)
└── mockup/                   # static design mockups
```
`templates_c/` は Smarty によって作成および管理されます。**ウェブサーバーのユーザーが書き込み可能である必要があります。** `cache/` は、`[ENGINE] caching = true` の場合のみ使用されます。

## 解決ルール

表示層は、マッチしたコントローラからテンプレートパスを解決します。

- `pageAction()` に対しては `templates/<controller>.tpl`。
- 名前付きアクション `fooAction()` に対しては、存在する場合は `templates/<controller>/foo.tpl`、存在しない場合は `templates/<controller>.tpl`。

どちらも解決しない場合、[ソフトウェア404](/core/dispatcher/#soft-404) エラーテンプレートが表示されます。

## 最小限のテンプレート
```smarty
{include 'shared/header.tpl'}
<body>
{include file="navigation.tpl"}

<main class="container">
  <h1>{$title|escape}</h1>
  <ul>
    {foreach $products as $p}
      <li><a href="/products/detail/{$p.id}">{$p.name|escape}</a></li>
    {/foreach}
  </ul>
</main>

{include 'shared/footer.tpl'}
</body>
```
`{include 'shared/header.tpl'}` と `{include file="navigation.tpl"}` はどちらも有効な Smarty のインクルード形式です。

## View::assign

`View::assign()` は、PHP データがテンプレートに到達する方法です。これは静的で、冪等であり、配列にも対応しています：
```php
View::assign(['title' => 'Products']);
View::assign([
    'products' => $list,
    'count'    => count($list),
]);
```
後続の呼び出しは同じキーに対する前回の呼び出しが上書きされます。テンプレート内でこれらは `{$title}`, `{$products}`, `{$count}` になります。

`View::display()` を手動で呼び出すことはありません — ディスパッチャは、`pageAction()` が返った後、自動的に `Display::display()` を呼び出します。

## 共有 CSS/JS 挿入

デモンストレーションアプリケーション全体で使用されている規則は、設定されたアセットリストをテンプレートにプッシュすることです。
```php
View::assign([
    'css' => Config::getInstance()->getConfig()[View::NIBIRU_SETTINGS]['smarty.css'],
    'js'  => Config::getInstance()->getConfig()[View::NIBIRU_SETTINGS]['smarty.js'],
]);
``````smarty
{* shared/header.tpl *}
<head>
  <meta charset="utf-8">
  <title>{$title|escape}</title>
  {foreach $css as $stylesheet}
    <link rel="stylesheet" href="{$stylesheet}">
  {/foreach}
</head>
```
その後、INIファイルの`[SETTINGS] smarty.css[]`がスタイルシートの唯一の真実源となります。

## キャッシング

キャッシュはオプトインです：
```ini
[ENGINE]
caching = true
```
When enabled, Smarty caches the rendered HTML in `application/view/cache/` with the lifetime `Smarty::CACHING_LIFETIME_CURRENT` (default ≈ 1 hour). Clear the cache with:
```bash
./nibiru -cache-clear
```
これにより、`templates_c/` と `cache/` が安全に削除されます。

::: caution
キャッシュされたページではコントローラーが実行されません。ユーザー固有のコンテンツやCSRFトークンを含むページはキャッシュしないでください。
:::

## Smarty の基本要素

毎日のもの:
```smarty
{* variables *}
{$user.name}
{$products[0].title}

{* iteration *}
{foreach $items as $item}
  ...
{foreachelse}
  No items.
{/foreach}

{* conditionals *}
{if $count > 0}…{else}…{/if}

{* string filters *}
{$body|escape}              {* HTML escape *}
{$date|date_format:"%Y-%m-%d"}
{$price|string_format:"%.2f"}

{* includes *}
{include file="shared/header.tpl" title=$title}

{* assigning *}
{assign var="now" value=time()}
```
## JSON レスポンス

アクションが `View::forwardToJsonHeader()` を呼び出すと、Smarty はバイパスされ、Nibiru は割り当てられた `data` キーを JSON として発行します。AJAX エンドポイントに便利です：
```php
public function searchAction() {
    View::forwardToJsonHeader();
    $results = $this->index->search($_REQUEST['q'] ?? '');
    View::assign(['data' => $results]);
}
```
## ナビゲーションには含まれています

`{include file="navigation.tpl"}` は、`[SETTINGS] navigation` で設定された JSON ファイルから読み込みます。生産アプリケーションでは、多くの名前付きナビゲーション配列を読み込むことがよくあります：
```php
public function navigationAction() {
    JsonNavigation::getInstance()->loadJsonNavigationArray('headnavigation');
    JsonNavigation::getInstance()->loadJsonNavigationArray('mainnavigation');
    JsonNavigation::getInstance()->loadJsonNavigationArray('footer');
}
```
各名前付き配列は、同じ名前の Smarty 変数になります。これにより、対応する部分テンプレートでレンダリングできます。

## 一般的な落とし穴

- **`templates_c/` の権限** — Smarty が書き込めない場合、致命的なエラーになります。一度 `./nibiru -s` を実行して修正してください。
- **値のない `{$variable}`** — Smarty のデフォルトモードでは何も表示せず、例外を投げません。開発中に `error_reporting = E_ALL` と `[ENGINE] debug = true` をオンにしてタイポを見つけることができます。
- **HTML エスケープ** — Smarty は自動的にエスケープしません。ユーザー制御の文字列には `|escape` を使用してください。
