템플릿 문법 v2
템플릿 v2는 Zittme의 권장 템플릿 문법입니다. Blade 스타일 디렉티브에 Zittme 고유 기능을 더한 것으로, v1 문법과 한 파일에서 호환됩니다.
버전 선언
.html파일: 첫 줄에@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)을 인식해 자동으로 처리됩니다.
필터
출력에 |필터 를 이어 붙일 수 있고, 여러 개를 연결할 수 있습니다.
{{ $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:구분자 date:형식 number_format:소수자릿수 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>
@endforeachHTML 속성 헬퍼
<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 주석: 출력에 남습니다 -->주의: {{-- --}} 주석은 반드시 한 줄로 쓰세요. 여러 줄에 걸쳐 쓰면 파서가 온전히 제거하지 못해 서버 오류(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에서 새로 만들기. 그러지 않으면 현재 요청의 파라미터가 전부 딸려 갑니다.
액션에 라우트가 선언되어 있으면 자동으로 짧은 주소가 만들어집니다.
그 밖의 디렉티브
| 디렉티브 | 뜻 |
|---|---|
@csrf | 폼 안에 CSRF 토큰 필드 삽입 |
@json($array) | JS에 안전한 JSON 출력 (문맥 자동 인식) |
@lang('키') | 언어 문자열 출력 (@lang('module.키')) |
@use('네임스페이스\클래스', '별칭') | 클래스 별칭 선언. 이후 {{ 별칭::method() }} |
@widget('위젯이름', $args) | 위젯 삽입 |
@once ~ @endonce | 반복문 안에서도 한 번만 실행 |
@verbatim ~ @endverbatim | 이 구간은 템플릿 문법을 해석하지 않음 |
@dump($var) / @dd($var) | 디버깅 출력 (dd는 출력 후 중단) |
@push('이름') ~ @endpush / @stack('이름') | 내용을 모아 한 곳에 출력 |
@error('검사기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처럼 우선순위를 올리세요.