XpressEngine

[기초] XE구조의 비밀 그 여덟번째 - XE만의 언어?..XE문법속으로..

일반적으로 PHP 작업시 아래처럼 프로그래밍과 디자인을 동시합니다.


<?php
      $point  = $sum['point'];
      $sell_price = $sum['price'];
?>

<tr>
    <td class="sod_img"><?php echo $image; ?></td>
     <td>
           <input type="hidden" name="it_id[<?php echo $i; ?>]"    value="<?php echo $row['it_id']; ?>">
           <input type="hidden" name="it_name[<?php echo $i; ?>]"  value="<?php echo get_text($row['it_name']); ?>">
           <?php echo $it_name.$mod_options; ?>
     </td>
</tr>

<?php if ($send_cost > 0) { // 배송비가 0 보다 크다면 (있다면) ?>
<dt class="sod_bsk_dvr">배송비</dt>
<dd class="sod_bsk_dvr"><strong><?php echo number_format($send_cost); ?> 원</strong></dd>
<?php } ?>


그렇기에 전문분야가 각기 다른 개발자들은 프로그래밍도 하고, 디자인도 해야합니다.

만약 한 디자이너가 프로그래밍을 못할 경우 개발참여를 할 수 없습니다.

왜냐면 디자이너가 디자인만 하고, 중간에서 손 놓아버리면 프로그래머는 어디서 부터 시작해야 될지 모르기때문에 개발이 느려집니다.


하지만, XE에서는 프로그래밍 작업과 디자인 작업을 분리해서 할 수 있습니다.

즉, 프로그래머는 프로그래밍만 ,디자이너는 디자인만 담당할 수 있다는 말입니다.

그렇게 하면 각각 전문분야만 다루게 되므로 개발의 효율을 높일 수 있습니다.


그 이유는 무엇일까요?

프로그래밍을 할 수 있는 PHP파일과 디자인을 할 수 있는 HTML 템플릿 파일이 나누어져있습니다.

HTML 템플릿 파일이란? 페이지 구성을 할 수 있는 HTML 파일입니다. XE에서 그 템플릿 파일을 불려와 화면출력을 합니다.

그 템플릿에서는 HTML과 XE문법이 존재합니다. 그 XE문법으로 PHP처럼 동적인 페이지를 구현할 수 있습니다.


XE문법이 정확히 무엇인가요?

HTML 템플릿 파일에서만 사용할 수 있는 XE전용 문법이라고 할 수 있습니다.

XE문법을 사용하면 HTML 템플릿 파일에서 PHP처럼 동적인 페이지를 구현할 수 있습니다.

XE는 최종결과물에서 쓰일 HTML 템플릿 파일을 읽을 때 XE문법을 해석하여 PHP코드로 컴파일하게 됩니다.

바로 아래처럼 말입니다.


Before 템플릿 파일에서 XE문법사용

<section cond="count($lang->find_account_question_items)>1">
	<h1>{$lang->cmd_find_member_account_with_email_question}</h1>
	<p>{$lang->about_find_account_question}</p>
	<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/member/skin/default/find_member_account/2'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
		<p>{$XE_VALIDATOR_MESSAGE}</p>
	</div>
	<form action="/" method="get" ruleset="@find_member_account_by_question">
		<input type="hidden" name="module" value="member" />
		<input type="hidden" name="mid" value="{$mid}" />
		<input type="hidden" name="document_srl" value="{$document_srl}" />	
		<input type="hidden" name="act" value="procMemberFindAccountByQuestion" />
		<input type="hidden" name="success_return_url" value="{getUrl('', 'act', 'dispMemberGetTempPassword')}" />
		<input type="hidden" name="page" value="{$page}" />
		<input type="hidden" name="xe_validator_id" value="modules/member/skin/default/find_member_account/2" />
		<div>
			<input type="text" name="user_id" required placeholder="{$lang->user_id}" title="{$lang->user_id}" cond="$identifier == 'user_id'" />

		</div>



After 컴파일 (XE문법 -> PHP 코드로 변환) 

<?php if(count($__Context->lang->find_account_question_items)>1){ ?><section>
	<h1><?php echo $__Context->lang->cmd_find_member_account_with_email_question ?></h1>
	<p><?php echo $__Context->lang->about_find_account_question ?></p>
	<?php if($__Context->XE_VALIDATOR_MESSAGE && $__Context->XE_VALIDATOR_ID == 'modules/member/skin/default/find_member_account/2'){ ?><div class="message <?php echo $__Context->XE_VALIDATOR_MESSAGE_TYPE ?>">
		<p><?php echo $__Context->XE_VALIDATOR_MESSAGE ?></p>
	</div><?php } ?>
	<?php Context::addJsFile("./files/ruleset/find_member_account_by_question.xml", FALSE, "", 0, "body", TRUE, "") ?><form action="/" method="get" ><input type="hidden" name="error_return_url" value="<?php echo htmlspecialchars(getRequestUriByServerEnviroment(), ENT_COMPAT | ENT_HTML401, 'UTF-8', false) ?>" /><input type="hidden" name="vid" value="<?php echo $__Context->vid ?>" /><input type="hidden" name="ruleset" value="@find_member_account_by_question" />
		<input type="hidden" name="module" value="member" />
		<input type="hidden" name="mid" value="<?php echo $__Context->mid ?>" />
		<input type="hidden" name="document_srl" value="<?php echo $__Context->document_srl ?>" />	
		<input type="hidden" name="act" value="procMemberFindAccountByQuestion" />
		<input type="hidden" name="success_return_url" value="<?php echo getUrl('', 'act', 'dispMemberGetTempPassword') ?>" />
		<input type="hidden" name="page" value="<?php echo $__Context->page ?>" />
		<input type="hidden" name="xe_validator_id" value="modules/member/skin/default/find_member_account/2" />
		<div>
			<?php if($__Context->identifier == 'user_id'){ ?><input type="text" name="user_id" required placeholder="<?php echo $__Context->lang->user_id ?>" title="<?php echo $__Context->lang->user_id ?>" /><?php } ?>
		</div>


참고로 컴파일된 코드는 속도를 위해 캐시폴더에 저장되니, 살펴보세요. (경로 : ./files/cache/template_compiled)


XE의 화면출력(HTML)의 요약하자면 아래와 같습니다.

템플릿 파일지정 -> 템플릿 파일 Load -> 템플릿 파일 Compile (XE문법 -> PHP 코드로 변환) ->(레이아웃이 있으면 합침) -> 출력


XE 문법은 크게 3가지 종류로 나뉩니다.


1. HTML 주석형태 (XE 전버전에서 사용가능)

<!--#include("불려올 템플릿 파일")--> : 다른 템플릿파일을 컴파일하여 불려와 삽입합니다.

예) <!--#include("./item_apply.html")-->


<!--%load_js_plugin("플러그인 이름")--> : ./common/js/plugins에 있는 자바스크립트 플러그인들을 불려올 수 있습니다.

./common/js/plugins에 있는 폴더이름이 플러그인 이름이 됩니다.

Context::loadJavascriptPlugin("플러그인 이름") 과 같은 역할을 합니다.

예) <!--%load_js_plugin("filebox")-->


<!--%import("불려올 파일")--> : js , xml, css 파일을 불려올 수 있습니다.

Context::loadFile("불려올 파일") 과 같은 역할을 합니다.

XML일경우 Filter XML로 인식해  Filter XML을 자바스크립트로 컴파일해서 불려옵니다.

다만, 파일이름이 lang.xml 일경우 언어파일로 인식해 불려옵니다. Context::loadLang("불려올 파일") 과 같은 역할을 합니다.

예) <!--%import("./css/common.css")-->


<!--%unload("불려온 파일")--> : 이미 불려온 js , css 파일을 불려오지못하게 합니다.

Context::unloadFile("불려온 파일") 과 같은 역할을 합니다.

예) <!--%unloadFile("./css/common.css")-->


<!--@PHP문--> : php의 if, switch, for, foreach, while문을 사용합니다.

{@ PHP코드}에다 if,for,for등.. PHP문을 쓸 경우 if{  .. }(if문 괄호)와 같이 PHP괄호,XE 괄호가 서로 겹쳐 오작동이 일어납니다.

오류의 예 : {@ if(1==1){}  1은 1이다 {@ }} 


그래서 <!--@PHP문-->을 사용해 "<!--@if(1==1)-->1은 1이다<!--@end-->"와 같이 사용하면 오류도 없고, 보기에도 좋습니다.

* 사용가능한 <!--@PHP문-->

  • <!--@foreach( ... )-->
  • <!--@for( ... )-->
  • <!--@switch( ... )-->
  • <!--@break-->
  • <!--@case( ... )-->
  • <!--@default-->
  • <!--@if( ... )-->
  • <!--@elseif( ... )->
  • <!--@else-->
  • <!--@end-->



2. HTML 가상 속성 형태 (XE Core 1.5부터 사용가능)

HTML태그에 가상 속성을 붙여 if문과 foreach,for,while 문과 같은 동작을 수행합니다.

사용할 수 있는 가상 속성은 두가지입니다.

  • cond : if문과 같이 조건에 따라 해당 태그를 표시합니다.

예) <div cond="$a == 1" class="ay">변수a는 1이다.</div>

  • loop : foreach,for,while 문과 같이 조건에 따라 해당 태그를 반복적으로 표시합니다.

for 예) <div loop="$i = 1; $i<=10; $i++" class="ay">10번 반복된다. 현재순번 : {$i}</div>

foreach 예) <div loop="$list => $key,$val" class="ay">{$key}번 제목 : {$val->title}</div> ("$list => $val" 식으로도 가능)

while 예) <div loop="$a <= 10" class="ay">변수a가 100이 될때까지 멈추지않아! {@ $a++}</div>


아래와 같은 형식으로 사용합니다. (가상속성과 조건에 따라 태그자체가 표시됨 or 표시안됨)

<태그 가상속성(cond,loop)="조건">

내용 

</태그>


* 이 문법형태는 태그 가상속성 형태이므로 태그가 없으면 사용하지못합니다. (태그가 있어야 속성도 쓰지요...;;)


-> 마땅히 사용할 태그가 없을 때는 <block>라는 가상태그를 쓰면 됩니다. 이 태그는 컴파일시 자동제거되어, 출력시 표시되지않습니다.

예) <block cond="$oDocument->hasUploadedFiles()" class="fileList"> ... </block>


* HTML태그의 속성에 XE가상속성을 부여할 수도 있습니다. 


속성|cond=" 조건 " 형식으로 쓰면 조건에 따라 속성이 표시되거나 표시되지 않습니다.

단, 속성과 |cond=" 속건 " 사이는 뛰워쓰면 안됩니다.

예) <a href="#" class="category"|cond="$category=='Y'">category사용시 빨간색 테두리가 생깁니다.</a>


! 속성 "cond"만 가능합니다. 속성|loop=" 조건 " 형식은 없습니다.



3. {} 형태 (XE 전버전에서 사용가능)

템플릿 파일에서 php코드를 사용할 수 있습니다.

{$변수명} : 변수에 담긴 값 출력  -(컴파일)-> <?php echo $변수명 ?>

{@ PHP코드} : PHP 코드 실행  -(컴파일)-> <?php PHP코드 ?>



& 참고사항

*  ./classes/template/TemplateHandler.class.php에서 HTML 템플릿 파일의 컴파일을 담당합니다.

* 레이아웃도 일종의 템플릿파일이므로 XE문법을 사용할 수 있습니다.

* 컴파일된 것을 보면 $__Context라는 변수가 있는 데.. 이 변수에는 Context::set(변수이름,값)으로 저장한 모든 변수가 담겨있습니다


그래서 act메서드에서 템플릿 파일에 변수를 넘겨줄때는 Context::set(변수이름,값)으로 저장해 변수를 사용하면 됩니다.


자세한 구조는 다음과 같습니다.

$__Context변수에는 $GLOBALS['__Context__'] 라는 글로벌 변수가 저장되어있습니다.

$__Context = &$GLOBALS['__Context__'];

그리고 $GLOBALS['__Context__']는 ./classes/context/Context.class.php의 set()으로 저장한 모든변수들을 담고있습니다.


* 템플릿 파일 지정은 모듈에서 아래와 같이 할 수 있습니다.

  • $this->setTemplatePath(템플릿파일 위치경로);
  • $this->setTemplateFile(템플릿파일이름 (.html은 붙일필요없음));


* "<!--//주석-->"형태로 템플릿 파일에서 주석을 작성할 수 있습니다. 물론 컴파일시 이 주석은 제외됩니다.

* 컴파일시 ruleset 코드도 실제 자바스크립트로 변환됩니다.

* 컴파일시 이미지 상대경로도 실제 경로로 변환됩니다.


  • ?
    날아라 2014.03.15 03:32:51
    흠... 점점 어려워지네요... 이건 두고두고 봐서 이해를 해야할듯...어렵다... ~_~
  • ?
    디스타임 2014.03.15 20:58:34
    어렵네요...
  • ?
    다이오니 2015.02.02 01:23:20
    메뉴 구성에 대해서 강의도 알 수 있을까요? 레이아웃 파일에서 메뉴를 불러내는데 2차 3차 메뉴로 구성되면 XE문법을 점점 알아보기 힘들더라구요 ㅠㅠ
  • ?
    애니원 2022.07.27 18:29:09
    레이아웃내 카피된 문서에대한 링크태그가 궁금합니다 운영자님

    혹시 레이아웃 폴더에 카피한 html 문서를 레이아웃에 불러올려면 어떤식으로 문법을 구성할수 있을까요?

    예를들어 모바일 메뉴 전체보기 항목의

    <li class="m_yes_inline"><a href="{getUrl('act','dispMenuMenu','menu_srl',$layout_info->menu->main_menu->menu_srl)}"><strong>{$lang->cmd_view_all}</strong></a></li>

    경로에 포함된 문서를 코어 업데이트시에도 유지가능하도록
    루트 /modules/menu/tpl/menu.html

    경로에서 layout 폴더경로로 관련문서를 카피해서 레이아웃에 출력 하려 합니다.

    이럴때 원래 경로인 getUrl('act','dispMenuMenu','menu_srl',$layout_info->menu->main_menu->menu_srl)

    이 변수명을 어떻게 경로변경 해줘야 템플릿 오류가 안나고 레이아웃에 출력해 줄수 있는지 조언을 부탁 드립니다.

    해당 문법에 대한 힌트를 찾으려 오랜시간 구글링을 해봐도 딱히 조건에 맞는 제시글을 찾을수가 없네요
?