개요[편집 / 원본 편집]
템플릿 문법 v2는 라이믹스 2.1.8부터 프리뷰 형식으로 제공되고, 라이믹스 2.2부터 정식 지원할 템플릿 문법이다.[1]
Laravel Blade 문법을 기반으로 하되, 라이믹스의 구조와 기능에 맞게 여러 지시자(directive)가 추가되었다. 기존 v1 문법 중 안정성과 편리함이 검증된 요소도 상당수 그대로 유지되어 두 문법을 섞어 쓸 수 있다.[1]
다만 Laravel Blade를 그대로 가져다 쓰는 것이 아니다. PHP 지원 범위, 서로 다른 출처의 모듈과 스킨을 조합하는 라이믹스의 특성, Context 변수 참조 방식, v1 문법 유지 등의 이유로 Laravel의 코드를 그대로 쓰기 어려워, "Blade 스타일"의 문법만 차용하고 컴파일러는 자체 구현하였다. 따라서 세부 해석 방식에 차이가 있을 수 있다.[1]
이 문서에서는 공식 매뉴얼의 표현을 따라 Blade 스타일 문법을 v2 정규 문법, v1과 호환되는 문법을 v1 호환 문법으로 부른다. 두 문법은 충돌하지 않지만, 가능하면 v2 정규 문법만 쓰는 것이 권장된다.[1]
버전 표기[편집 / 원본 편집]
확장자가 .blade.php인 파일은 모두 v2로 인식한다. VSCode, PHPStorm, IntelliJ 등 대부분의 편집기에서 Blade 플러그인을 설치하면 문법 강조와 자동 완성을 쓸 수 있다.[1]
확장자가 .html인 파일에서 v2 문법을 쓰려면 최상단에 버전을 표기해야 한다.
@version(2)
<config version="2" />
v1과의 차이[편집 / 원본 편집]
문법 비교[편집 / 원본 편집]
v1의 조건문·루프문에서 좌우의 주석을 지우면 Blade 지시자와 거의 같은 형태가 된다. 라이믹스가 차기 템플릿 문법으로 Blade를 채택한 이유 중 하나다.[1]
@if ($condition)
<div class="comment">{{ $comment }}</div>
@endif
<!--@if($condition)-->
<div class="comment">{$comment}</div>
<!--@end-->
문맥에 맞는 자동 이스케이프[편집 / 원본 편집]
템플릿에서 출력하는 모든 데이터는 자동으로 escape되며, 이를 일괄 해제하는 옵션은 제공하지 않는다. 필요한 곳에서만 noescape 필터나 {!! $var !!} 문법으로 개별 해제한다. 이미 escape된 데이터를 이중 인코딩하지는 않는다.[1]
<script> 태그 안에서는 문맥을 자동으로 인식하여 HTML이 아닌 JS 문법에 맞게 escape한다. 예를 들어 <는 HTML 문맥에서 <, JS 문맥에서 <로 변환된다.[1]
일관성 있는 Context 참조[편집 / 원본 편집]
v1에서는 <?php ?>로 PHP 코드를 직접 쓰면 Context를 참조하지 않는 로컬 변수가 생겨 {@ ...} 문법의 변수와 연동되지 않는 불편이 있었다. v2에서는 템플릿에서 쓰는 모든 변수가 항상 일관되게 Context를 참조한다.[1]
제거된 문법[편집 / 원본 편집]
XE 1.4.4 이후 수많은 템플릿 해석 오류의 원인이 되어 온 <block> 가상 태그, loop 속성, cond 속성을 지원하지 않는다. 사용하면 출력물에 소스가 그대로 남거나 오류가 발생할 수 있다.[1]
<include>의 cond 속성과 |cond="" 문법은 계속 지원하지만, @class, @style, @selected 등으로 바꾸는 것이 권장된다.
데이터 출력[편집 / 원본 편집]
표준은 중괄호 두 쌍이다. v1처럼 한 쌍만 써도 되지만, 중괄호 바로 안쪽에 공백이 있으면 안 된다.
{{ $var }}
{{ $oDocument->getNickName() }}
한 쌍만 쓰면 클로저처럼 중괄호가 포함된 코드를 쓸 수 없고, 중괄호 안에서 줄바꿈을 할 수 없다.
단일 중괄호가 금지되는 위치[편집 / 원본 편집]
v1 호환 문법은 일반적인 CSS·JS 문법과 충돌하는 경우가 많아, 라이믹스 2.1.22부터 CSS·JS 문맥에서는 허용하지 않는다. 아래 위치에서는 반드시 중괄호 두 쌍을 써야 한다.[1]
<script>태그 안<style>태그 안onclick등 이벤트 핸들러 속성 안pattern속성 안 (2.1.25~)<a href="javascript:...">등 JS를 쓰는 속성 안- 모든 태그의
style속성 안
변수의 유효 범위[편집 / 원본 편집]
템플릿의 변수는 모두 Context와 연동된다. 모듈이나 위젯에서 Context::set('foo', $value)로 설정했거나 $_GET['foo']로 들어온 값을 템플릿에서 $foo로 참조할 수 있고, 반대로 템플릿에서 $foo를 조작하면 다른 자료에서 Context::get('foo')로 바뀐 값을 읽을 수 있다. 즉 Context를 공용 상태 저장소로 쓴다.[1]
다음은 Context와 연동되지 않는다.
- 변수와 함께 인클루드한 템플릿 안의 변수
$_SERVER,$_SESSION,$GLOBALS등 초전역변수Template인스턴스를 가리키는$this- 변수 앞에
\를 붙인\$foo— 로컬 변수가 된다. 클로저를 선언할 때도 이 방법을 써야 한다
{{ implode(', ', array_map(function(\$i) { return \$i * 1000; }, $list)) }}
- ※ 템플릿 컴파일러가 내부적으로 쓰는 로컬 변수는
$__tmp처럼 언더바 두 개로 시작하는 것이 많다. 충돌을 피하려면 그런 이름은 쓰지 말자.[1]
출력 필터[편집 / 원본 편집]
v1과 같은 출력 필터를 지원하며, | 좌우에 공백을 허용하는 점이 다르다. 필터명과 옵션은 :로 구분한다.
{{ $var|lower|escape }}
{{ $timestamp|date:'n/j H:i' }}
| 필터 | 기능 | 옵션 |
|---|---|---|
| autoescape | 자동 escape (이중 인코딩 안 함) | |
| autolang | 자동 escape하되 언어코드는 escape하지 않음 | |
| escape | 강제 escape (이중 인코딩) | |
| escapejs | JS 문자열에 넣을 수 있는 형태로 escape | |
| noescape | escape하지 않음 | |
| json | JSON으로 인코딩 (@json 권장) |
|
| strip / strip_tags | strip_tags() |
|
| trim | trim() |
|
| urlencode | rawurlencode() |
|
| lower / upper | 대소문자 변환 | |
| nl2br | 개행을 <br>로 변환 |
|
| join | 배열을 문자열로 합침 | 구분자 (기본 ,)
|
| date | 타임스탬프 포맷 | 포맷 (기본 Y-m-d H:i:s)
|
| format / number_format | 천 단위 쉼표 | 소수점 자릿수 (기본 0) |
| shorten / number_shorten | 123.4K 형태로 표시 |
소수점 자릿수 (기본 2) |
| link | 문자열을 링크로 표시 | 링크 텍스트 |
|를 필터가 아닌 뜻으로 쓸 때는 || 연산자, 문자열 안의 '|', \| 이스케이프 세 가지만 허용된다.[1]
조건문과 루프문[편집 / 원본 편집]
PHP의 대체 문법(alternative syntax)에 @를 붙인 형태가 원칙이다. @if와 괄호 사이를 띄어도 되고, @endif를 @end로 줄여도 된다.
@if ($condition1)
<div class="foo"></div>
@elseif ($condition2)
<div class="bar"></div>
@else
<div class="baz"></div>
@endif
- “ 괄호를 쓰는 Blade 스타일 지시자는 모두 정규식(PCRE)으로 해석된다. 복잡한 자료 구조를 즉석에서 선언하거나 문자열 안에 괄호를 넣어 해석을 방해하면 v1의
loop,cond속성처럼 오작동할 수 있다. 복잡한 자료 구조는 따로 선언한 뒤 변수만 넘기자.”
forelse[편집 / 원본 편집]
if문과 foreach문을 결합한 형태로, 배열이 비었을 때 표시할 내용을 쉽게 지정한다. 중간 지시자가 @else가 아니라 @empty임에 유의해야 한다.
@forelse ($array as $key => $val)
<div class="item">{{ $val->name }}</div>
@empty
<div class="noitem">항목이 없습니다.</div>
@endforelse
루프 변수[편집 / 원본 편집]
@foreach, @forelse에서 $loop 변수를 쓸 수 있다.
| 속성 | 타입 | 의미 |
|---|---|---|
$loop->index |
int | 현재 인덱스 (0부터) |
$loop->iteration |
int | 현재 반복 횟수 (1부터) |
$loop->remaining |
int | 남은 횟수 |
$loop->count |
int | 총 반복 횟수 |
$loop->first |
bool | 첫 번째 항목인가 |
$loop->last |
bool | 마지막 항목인가 |
$loop->even / odd |
bool | 짝수·홀수번째인가 |
$loop->depth |
int | 중첩 루프의 깊이 (1부터) |
$loop->parent |
object 또는 null | 상위 루프 변수 |
@for, @while, @switch도 지원하며 @continue, @break, @default를 쓸 수 있다.
라이믹스 전용 조건문[편집 / 원본 편집]
Blade 10.x의 조건문은 @hasSection을 제외하고 모두 지원하며, @auth와 @can 등은 라이믹스의 권한 체계에 맞게 재해석되었다. 마치는 지시자는 모두 @end로 줄일 수 있다.[1]
| 지시자 | 조건 |
|---|---|
@admin |
최고관리자 |
@auth |
로그인한 회원 |
@auth('admin') |
최고관리자 |
@auth('manager') |
게시판 관리자 |
@guest |
로그인하지 않음 |
@can('view') |
$grant->view 권한 있음
|
@cannot('view') |
해당 권한 없음 |
@canany(['view', 'write_comment']) |
나열한 권한 중 하나 이상 있음 |
@desktop |
PC |
@mobile |
모바일 |
@isset($foo) / @unset($foo) / @empty($foo) |
Context 변수의 존재 여부 |
@env('foo') |
환경변수 존재 |
- ※
@mobile의 판정 기준이 바뀌었다. 2.1.21 이전은 모바일 뷰 설정과m파라미터의 영향을 받았지만, 2.1.22 이후는 접속한 User-Agent와 "태블릿도 모바일 취급" 설정만 따른다.[1]
템플릿 인클루드[편집 / 원본 편집]
경로는 현재 파일 기준 상대경로이다. 여러 디렉터리를 거슬러 올라가야 한다면 ^로 라이믹스 설치 디렉터리 기준 경로를 쓸 수 있다. 리소스 로딩에서도 마찬가지다.
@include ('dir/filename')
@include ('^/common/tpl/default_layout')
조건부 인클루드[편집 / 원본 편집]
@includeIf— 파일이 있을 때만 인클루드하고, 없어도 오류를 내지 않는다@includeWhen— 조건이 참일 때만@includeUnless— 조건이 거짓일 때만
변수 전달과 컴포넌트[편집 / 원본 편집]
인클루드할 때 연관배열이나 오브젝트를 함께 넘기면, 인클루드된 템플릿은 Context를 참조하지 않고 전달받은 데이터만 쓴다. 없는 키를 참조하면 경고가 발생한다. 이를 이용해 외부 변수에 영향받지 않는 독립적인 컴포넌트를 만들 수 있다.[1]
@include ('B', ['title' => '제목', 'content' => '내용'])
자식 템플릿은 부모의 변수를 상속받으며, 직접 전달받은 변수가 우선한다. 다만 인클루드된 템플릿이 Context::get()으로 외부 데이터에 접근하는 것을 막지는 않는다. 그런 시도가 눈에 잘 띄게 될 뿐이다.[1]
리소스 로딩[편집 / 원본 편집]
<script>나 <link>로 직접 불러올 수도 있지만, @load로 코어에 맡기면 CSS·JS 압축 및 합치기와 자동 연동되고, SCSS·LESS가 자동 컴파일되며, 로딩 순서 조절과 언로딩이 가능하다.[1]
@load ('styles.css')
@load ('styles.css', 'print', 20)
@load ('css/styles.scss', $vars)
파라미터 순서는 파일명, media, 로딩 순서, 변수이다. media와 로딩 순서는 생략할 수 있으나 각각 문자열과 정수여야 하며 변수를 쓸 수 없다.
JS도 같은 문법이되 media 대신 type을 넘기며, 변수 전달 기능은 없다. head(기본값)는 본문 로딩 전, body는 본문 로딩 후 실행된다.
v1 호환 문법은 각 파라미터의 역할이 더 분명하게 드러나므로 굳이 피할 필요는 없다.[1]
<load src="^/modules/foo/bar/styles.scss" media="screen" vars="$vars" />
<load target="../../../styles.css" index="-3" />
HTML 속성 도우미[편집 / 원본 편집]
@class와 @style[편집 / 원본 편집]
배열을 넘기면 단순 값은 그대로, 키/값 형태는 값이 참일 때만 출력된다.
<div @class([
'project-item',
'project-complete' => $is_complete,
'featured' => $is_featured,
])></div>
@style도 같은 방식이지만, 꼭 필요한 경우가 아니면 스타일은 별도 CSS·SCSS 파일에 쓰는 것이 권장된다.[1]
불리언 속성[편집 / 원본 편집]
@checked, @selected, @disabled, @readonly, @required를 쓸 수 있다.
<input type="checkbox" @checked($is_checked)>
<option value="1" @selected($val == 1)>ONE</option>
지원하지 않는 속성에 조건을 걸어야 한다면 v1의 |cond="" 문법이나 if문을 쓴다.
PHP 코드와 주석[편집 / 원본 편집]
@php
Hello::world();
$foo = 'bar';
@endphp
v1의 {@ ... } 문법도 쓸 수 있으나 중괄호가 포함된 코드는 작성할 수 없다.
일반 HTML 주석은 결과물에 그대로 출력된다. 출력되지 않는 주석은 다음과 같이 쓴다.
{{-- 이 주석은 출력되지 않습니다 --}}
<!--// 이 주석은 출력되지 않습니다 -->
그 밖의 지시자[편집 / 원본 편집]
| 지시자 | 기능 |
|---|---|
@use |
긴 클래스명을 alias로 줄여 쓴다 |
@csrf |
폼에 CSRF 토큰 필드를 자동 주입한다 |
@json |
JSON으로 출력한다 |
@lang('msg_file_not_found') |
번역문을 불러온다. @lang('file.msg_...')처럼 모듈을 지정할 수도 있다
|
@url('act', 'dispMemberInfo') |
URL을 생성한다. 배열로 넘길 수도 있다 |
@widget('content', $args) |
위젯을 삽입한다 |
@dump / @dd |
변수를 출력한다. @dd는 출력 후 중단한다
|
@once ... @endonce |
한 번만 실행한다 |
@error ... @enderror |
오류 처리 |
@verbatim ... @endverbatim |
안쪽의 지시자를 해석하지 않고 그대로 출력한다 |
@push / @prepend / @stack |
여러 곳에서 모은 내용을 한 지점에 출력한다 |
@fragment ... @endfragment |
템플릿의 일부만 잘라내어 렌더링한다 |
미지원 기능[편집 / 원본 편집]
Blade 10.x의 기능 중 템플릿 상속과 컴포넌트화 관련 지시자는 적용되지 않았다. @extends, @yield, @section, @show, @inject, @slot 등이 여기에 해당한다.[1]
공식 문서가 밝힌 이유는 이렇다. 하나의 개발팀이 하나의 코드베이스를 관리한다고 가정하는 대다수 웹 프레임워크와 달리, 라이믹스는 각 모듈과 스킨을 독립적으로 개발하고 배포할 수 있어야 한다. 전문 개발자가 아닌 사용자와 자료 제작자가 많은데, 스킨에서 쓸 컴포넌트 하나를 만들려고 별도 .php 파일에서 클래스를 선언하거나 터미널에서 명령을 실행해야 하는 개발 방식은 받아들이기 곤란하다는 것이다.[1]
따라서 Laravel Blade의 컴포넌트 설계는 라이믹스와 맞지 않다고 판단하여, 적절한 대안이 마련될 때까지 적용을 보류하였다. 대신 인클루드시 변수 전달 기능으로 상당히 독립적인 컴포넌트를 구현할 수 있으며, 복잡한 기능이 필요하다면 위젯을 활용하는 것이 권장된다.[1]
같이 보기[편집 / 원본 편집]
- 라이믹스/매뉴얼
- 라이믹스/릴리즈 노트/2.1.8
- 라이믹스/매뉴얼/라이믹스 프레임워크 — Template 클래스
- 라이믹스/버전
출처[편집 / 원본 편집]
이 문서는 라이믹스 공식 매뉴얼의 템플릿 문법 v2 문서를 바탕으로 작성되었다. 공식 매뉴얼은 CC BY-SA 4.0 라이선스로 배포된다.[2]
전체 지시자 목록과 상세한 예제는 공식 매뉴얼을 참고하자.