本文へスキップ
ドキュメント

開発者ガイド

テンプレート構文 v2

テンプレート v2 は、Zittme の推奨テンプレート構文です。Blade スタイルのディレクティブに Zittme 独自の機能を加えたもので、v1 構文と同じファイル内で互換性があります。

バージョンの宣言

  • .html ファイル:1 行目に @version(2)(または <config version="2" />)
  • .blade.php ファイル:自動的に v2(IDE の構文ハイライトを受けられます)
@version(2)
<div class="my-skin">
	<h1>{{ $title }}</h1>
</div>

出力

構文意味
{{ $var }}HTML エスケープして出力(基本)
{!! $var !!}エスケープせずそのまま出力
{$var}v1 互換の出力

{!! !!} は、エディターの本文のようにコアがすでにサニタイズした HTML にだけ使ってください。ユーザー入力をそのまま出力すると XSS になります。エスケープは文脈(HTML/JS)を認識して自動で処理されます。

フィルター

出力に |filter を続けて付けることができ、複数つなげることもできます。

{{ $title|upper }}
{{ $timestamp|date:'Y-m-d' }}
{{ $price|number_format }}
{{ $tags|join:', ' }}

主なフィルター:autoescape escape noescape escapejs json strip_tags trim urlencode lower upper nl2br join:separator date:format number_format:decimals number_shorten link

条件

@if ($is_logged)
	...
@elseif ($guest_allowed)
	...
@else
	...
@endif

専用の条件ディレクティブもあります。

ディレクティブ意味
@isset($var) ~ @endisset変数が存在すれば
@empty($var) ~ @endempty空であれば
@admin ~ @endadmin最高管理者であれば
@auth ~ @endauthログイン状態であれば(@auth('manager') は管理権限)
@guest ~ @endguest未ログインであれば
@can('view') ~ @endcanその権限があれば(@cannot、@canany([...]) もサポート)
@desktop / @mobileデバイスの区別

繰り返し

@foreach ($list as $key => $item)
	<li>{{ $item->title }}</li>
@endforeach

@forelse ($list as $item)
	<li>{{ $item->title }}</li>
@empty
	<li>항목이 없습니다</li>
@endforelse

@for @while @switch/@case/@break/@default @continue もサポートしています。

繰り返しの中では $loop 変数を使えます:$loop->index(0 から)$loop->iteration(1 から)$loop->count $loop->first $loop->last $loop->even $loop->odd $loop->depth $loop->parent

@foreach ($list as $item)
	<li class="@if ($loop->first) is-first @endif">{{ $loop->iteration }}. {{ $item->title }}</li>
@endforeach

HTML 属性ヘルパー

<div @class(['base', 'is-on' => $active, 'is-mine' => $item->mine])>...</div>
<div @style(['color: red', 'display: none' => $hidden])>...</div>
<input type="checkbox" @checked($is_checked) />
<option value="1" @selected($val == 1)>하나</option>
<input @disabled($locked) @readonly($readonly) @required($must) />

v1 の checked="checked"|cond="..." 表記も引き続き動作します。

PHP コード

@php
$count = count($list);
$first = $count ? reset($list) : null;
@endphp

{@ $total = $count + 1; }
  • テンプレート変数は、基本的に Context を参照する共有状態です。\$var のようにバックスラッシュを付けると、そのテンプレートだけのローカル変数になります。クロージャーの引数・use バインディングにも \$ を使います。
  • {@ ... } の中で foreach (...): / endforeach; スタイルでブロックを開いたり閉じたりすることもできます。

コメント

{{-- 템플릿 주석: 출력에서 제거됩니다 --}}
<!--// v1 스타일 주석: 역시 제거됩니다 -->
<!-- 일반 HTML 주석: 출력에 남습니다 -->

注意:{{-- --}} コメントは必ず 1 行で書いてください。 複数行にまたがって書くとパーサーが完全に除去できず、サーバーエラー(500)が発生することがあります。この問題による障害が実際にありました。複数行の説明は HTML コメント(<!-- -->)で書いてください。

他のテンプレートを含める

@include('_header')
@include('sub/box')
@include('_card', ['title' => $t, 'body' => $b])   {{-- 변수 전달 --}}

<include src="_promo" if="$show_promo" />          {{-- 조건부 포함 --}}
<include src="_banner" unless="$is_admin" />
  • 変数を渡すと、含められたテンプレートは Context の代わりに渡された変数だけを使います(コンポーネントのように使えます)。
  • 条件付きの読み込みは、<include> タグの if / when / cond / unless 属性で行います。
  • v1 の <include target="..." /> も動作します。

リソースの読み込み:@load

@load('css/skin.css')
@load('css/skin.scss', $vars)            {{-- SCSS 변수 전달 --}}
@load('js/skin.js')
@load('js/lazy.js', 'body')              {{-- body 끝에서 로드 --}}
@load('^/common/js/plugins/URI.js')      {{-- ^ 는 사이트 루트 --}}
@load('../lang/')                        {{-- 언어 파일 디렉터리 --}}
@unload('foo/bar.js')                    {{-- 로드 취소 --}}

CSS は media・順序、JS は head/body・順序を追加の引数で指定できます。

URL の作成

<a href="@url('act', 'dispMemberInfo')">내 정보</a>
<a href="{{ getUrl('', 'mid', $mid, 'act', 'dispBoardWrite') }}">글쓰기</a>

@url(...) と getUrl(...) は同じ働きをします。ルールを一つだけ覚えておいてください。

  • 現在のページのパラメーターだけを変えるリンク(ページネーション・並べ替え):最初の引数なしで getUrl('page', $n)
  • 別の画面へ移動するリンク:必ず最初の引数に '' を渡し、空の URL から新しく作ります。そうしないと、現在のリクエストのパラメーターがすべて付いていきます。

アクションにルートが宣言されていれば、自動的に短縮 URL が作られます。

その他のディレクティブ

ディレクティブ意味
@csrfフォーム内に CSRF トークンのフィールドを挿入
@json($array)JS で安全な JSON を出力(文脈を自動認識)
@lang('key')言語文字列を出力(@lang('module.key'))
@use('Namespace\Class', 'Alias')クラスのエイリアスを宣言。以後 {{ Alias::method() }}
@widget('widget_name', $args)ウィジェットを挿入
@once ~ @endonce繰り返しの中でも一度だけ実行
@verbatim ~ @endverbatimこの区間はテンプレート構文を解釈しない
@dump($var) / @dd($var)デバッグ出力(dd は出力後に停止)
@push('name') ~ @endpush / @stack('name')内容を集めて一か所に出力
@error('validator_id') ~ @enderrorフォーム検証エラーの表示

v2 でサポートしていないもの

  • Blade のテンプレート継承(@extends @yield @section)とスロット(@slot @inject)
  • v1 の <block> タグ、任意のタグの loop/cond 属性(<include> の条件属性は例外)

v1 構文が必要な既存ファイルは、そのままにしておけば大丈夫です。一つのファイルで二世代の構文を混ぜて使うことは避けてください。

実践でよく引っかかる落とし穴

これらの項目は、実際の障害事例から得られたものです。

  • 複数行の {{-- --}} コメントは禁止(上のコメントの節を参照)。サーバー 500 のよくある原因です。
  • テンプレートで静的メソッドを直接呼び出すときは @use でエイリアスを宣言し、エイリアスで呼び出してください。名前空間のフルパスを属性値の中で直接呼び出すとコンパイルがずれ、%7B...%7D のような壊れたリンクが出ることがあります。コントローラーで Context::set() を使って値を渡すのが最も安全です。
  • Context::set() は同じ名前のリクエスト変数を上書きします。 proc アクションでフォームの値を読むときは、$_POST を直接読む方が安全です。
  • CSS セレクターの優先順位:共通 CSS の .wrap a { color: inherit } は、新しく作った .my-link 一つよりも強いです。リンクの色が効かない場合は、.wrap a.my-link のように優先順位を上げてください。