고급 템플릿 문법

고급 템플릿 문법

PHP 코드 직접 사용

템플릿에서 PHP 코드를 직접 사용할 수 있습니다:

{@ 
    // PHP 코드 블록
    $total = 0;
    foreach($list as $item)
        $total += $item->price;
}

<p>총액: {number_format($total)}원</p>

{@ 블록의 제한사항

❌ 중요: {@ 블록 내에서는 중괄호 {}를 중첩해서 사용할 수 없습니다.

잘못된 예:

{@ 
    if($condition) {  // ❌ 오류! 중괄호 사용 불가
        $value = 'yes';
    }
}

올바른 예:

{@ 
    if($condition)    // ✅ 중괄호 생략
        $value = 'yes';
    else
        $value = 'no';
}

복잡한 로직은 별도 파일로:

// includes/calculate_total.php
$total = 0;
foreach($list as $item) {
    $total += $item->price;
}
return $total;
{@ $total = include 'includes/calculate_total.php'}
<p>총액: {number_format($total)}원</p>

인라인 PHP 표현식

<!-- 삼항 연산자 -->
<div class="{$is_mobile ? 'mobile' : 'desktop'}">

<!-- 함수 호출 -->
<p>현재 시간: {date('Y-m-d H:i:s')}</p>

<!-- 복잡한 표현식 -->
<p>{sprintf($lang->welcome_msg, $logged_info->nick_name)}</p>

고급 조건문

switch문 구현

<!--@switch($document->status)-->
    <!--@case('PUBLIC')-->
        <span class="public">공개</span>
    <!--@break-->

    <!--@case('SECRET')-->
        <span class="secret">비밀</span>
    <!--@break-->

    <!--@default-->
        <span class="temp">임시저장</span>
<!--@endswitch-->

복잡한 if-elseif-else

<!--@if($point >= 1000)-->
    <span class="level gold">골드 회원</span>
<!--@elseif($point >= 500)-->
    <span class="level silver">실버 회원</span>
<!--@elseif($point >= 100)-->
    <span class="level bronze">브론즈 회원</span>
<!--@else-->
    <span class="level basic">일반 회원</span>
<!--@endif-->

고급 반복문 기법

foreach with 조건

{@ $published_count = 0}
<ul>
    <block loop="$documents => $document">
        <li cond="$document->status == 'PUBLIC'">
            {$document->title}
            {@ $published_count++}
        </li>
    </block>
</ul>
<p>공개 문서: {$published_count}개</p>

반복문 제어

<block loop="$items => $i, $item">
    <!--@if($i >= 10)-->
        <!--@break-->
    <!--@endif-->

    <!--@if($item->is_deleted)-->
        <!--@continue-->
    <!--@endif-->

    <div>{$item->title}</div>
</block>

필터와 파이프

기본 필터

<!-- 자동 이스케이프 (기본) -->
<p>{$user_input}</p>

<!-- HTML 허용 -->
<div>{$html_content|noescape}</div>

<!-- 자동 링크 변환 -->
<p>{$text|autoescape}</p>

<!-- 줄바꿈을 <br>로 변환 -->
<p>{$text|nl2br|noescape}</p>

커스텀 필터 체인

{@ 
    // 필터 함수 정의
    function truncate($str, $len = 100)
        return cut_str($str, $len, '...');
}

<!-- 필터 체인 적용 -->
<p>{$document->content|strip_tags|truncate:200}</p>

주의: {@ 블록 내에서는 중괄호를 사용할 수 없으므로 함수 정의에서도 중괄호를 생략해야 합니다.

템플릿 상속과 블록

레이아웃 정의

<!-- layout.html -->
<!DOCTYPE html>
<html>
<head>
    <title><!--@block('title')-->기본 제목<!--@endblock--></title>
    <!--@block('head')--><!--@endblock-->
</head>
<body>
    <header>
        <!--@block('header')-->
        <h1>사이트 제목</h1>
        <!--@endblock-->
    </header>

    <main>
        <!--@block('content')--><!--@endblock-->
    </main>

    <footer>
        <!--@block('footer')-->
        <p>Copyright © 2024</p>
        <!--@endblock-->
    </footer>
</body>
</html>

레이아웃 상속

<!-- page.html -->
<!--@extends('layout.html')-->

<!--@block('title')-->게시판 - {$module_info->browser_title}<!--@endblock-->

<!--@block('head')-->
<load target="board.css" />
<!--@endblock-->

<!--@block('content')-->
<div class="board">
    <include target="list.html" />
</div>
<!--@endblock-->

매크로와 함수

매크로 정의

<!--@macro('pagination', $page, $total_page)-->
<ul class="pagination">
    <li cond="$page > 1">
        <a href="{getUrl('page', $page-1)}">이전</a>
    </li>

    <block loop="$i=1;$i<=$total_page;$i++">
        <li class="active"|cond="$i == $page">
            <a href="{getUrl('page', $i)}">{$i}</a>
        </li>
    </block>

    <li cond="$page < $total_page">
        <a href="{getUrl('page', $page+1)}">다음</a>
    </li>
</ul>
<!--@endmacro-->

<!-- 매크로 사용 -->
<!--@call('pagination', $page_navigation->cur_page, $page_navigation->total_page)-->

캐싱과 최적화

템플릿 캐싱

<!--@cache('sidebar', 3600)-->
<aside class="sidebar">
    <!-- 무거운 연산이나 쿼리가 필요한 내용 -->
    <include target="widgets/recent_posts.html" />
    <include target="widgets/popular_tags.html" />
</aside>
<!--@endcache-->

조건부 캐싱

<!--@cache('user_info_' . $member_srl, 1800, $is_logged)-->
<div class="user-info">
    {@ $member_info = getMemberInfo($member_srl)}
    <img src="{$member_info->profile_image}" />
    <p>{$member_info->nick_name}</p>
</div>
<!--@endcache-->

보안 고려사항

XSS 방지

<!-- 위험: 사용자 입력을 그대로 출력 -->
<div>{$user_content|noescape}</div>  <!-- 위험! -->

<!-- 안전: HTML 이스케이프 -->
<div>{$user_content}</div>

<!-- 안전: 허용된 태그만 허용 -->
<div>{$user_content|removeHackTag|noescape}</div>

CSRF 토큰

<form method="post">
    <input type="hidden" name="csrf_token" value="{$csrf_token}" />
    <!-- 폼 필드들 -->
</form>

디버깅 도구

변수 덤프

<!--@if(__DEBUG__)-->
<div class="debug">
    <pre>{var_dump($variable)}</pre>
    <pre>{print_r($array, true)}</pre>
</div>
<!--@endif-->

실행 시간 측정

{@ $start_time = microtime(true)}

<!-- 템플릿 내용 -->

{@ $execution_time = microtime(true) - $start_time}
<!-- 실행 시간: {$execution_time}초 -->

모범 사례

  1. 변수 검증: 사용 전에 항상 변수 존재 여부 확인
<div cond="isset($document) && $document">
    {$document->title}
</div>
  1. 기본값 설정: null 가능성이 있는 변수에 기본값 제공
<p>{$document->title ?: '제목 없음'}</p>
  1. 반복문 최적화: 불필요한 연산은 반복문 밖에서
{@ $total_count = count($list)}
<ul>
    <li loop="$list => $item">
        {$item->title} ({$total_count}개 중)
    </li>
</ul>
  1. 템플릿 분리: 복잡한 로직은 별도 파일로
<include target="_item.html" loop="$list => $item" />