개발자 가이드

템플릿 문법 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>
@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 주석: 출력에 남습니다 -->

주의: {{-- --}} 주석은 반드시 한 줄로 쓰세요. 여러 줄에 걸쳐 쓰면 파서가 온전히 제거하지 못해 서버 오류(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 처럼 우선순위를 올리세요.