애드온
XE에서 애드온은 후킹(hooking)을 수행합니다. 후킹이란 다른 정상적인 액션을 가져오는 행위를 말합니다. 후킹은 PHP 같은 인터프리터 기반 언어에서 사용하는 'include'를 사용합니다. XE에서는 애드온을 XE의 컨텍스트에 네이티브 코드로 삽입할 수 있도록 함수나 클래스 형태로 작성하지 않습니다. 이 때문에 XE의 애드온은 호출된 순간부터 강력한 효과를 발휘할 수 있습니다. 하지만 애드온은 XE의 전체 운영에 부하를 줄 수 있으므로 조심해서 생성해야 합니다.
애드온을 생성하려면 다음의 규칙을 따라야 합니다.
- 애드온은 addons 폴더 아래의 addon_name 폴더에 저장해야 합니다.
- 애드온 실행 파일의 이름은 addon_name.addon.php여야 합니다.
- info.xml 파일에 제작자 정보, 애드온 설명, 관리자(필요한 경우)로부터 받은 애드온 변수를 저장해야 합니다.
애드온을 호출하는 시점은 다음과 같습니다.
- before_module_init: 모듈 객체 생성 전: 사용자가 요청한 모듈을 찾은 후, 해당 모듈의 객체를 생성하기 전
- before_module_proc: 모듈 실행 전: 모듈의 객체를 초기화한 후, 해당 모듈을 실행하기 전
- after_module_proc: 모듈 실행 후: 생성된 모듈 객체를 실행하고 결과를 얻은 직후
- before_display_content: 결과 출력 전: 레이아웃이 적용된 모듈의 결과를 출력하기 직전
각 후크가 어떤 역할을 하고, 왜 XE 제어 경로(control path)에서 일부 애드온이 특정 시점만 사용하는지 이해하기 위해 몇 가지 예를 들어보겠습니다.
- 태그 목록 - After module proc
모든 문서의 태그 목록을 한 페이지에 출력하는 애드온이 있다고 가정해 봅시다. 이런 태그 목록을 생성하려면 먼저 현재 페이지의 module_srl이 포함된 문서를 가져와야 하고, 그 전에 module_srl을 알아야 합니다. 이를 위해 after_module_proc라는 지점을 선택해야 합니다. 모듈 정보가 처리된 후에 이전에 정의된 모든 작업을 실행할 수 있습니다.
- 메타 태그 - Before module proc
이 애드온은 메타 설명과 키워드, 제작자 등의 메타 태그를 모든 페이지에 삽입하는 역할을 합니다. 콘텐츠가 모듈 처리 작업에서 생성되기 전에 메타 태그를 삽입해야 하기 때문에 before_module_proc 지점을 후크로 사용합니다.
- 포인트 레벨 아이콘 - before display content
특정 회원이 쌓은 포인트 레벨에 따라 각 사용자에게 아이콘을 표시하는 애드온이 필요합니다. 이 애드온은 이미 처리된 일부 파라미터에 따라 콘텐츠 내의 HTML 코드를 수정해야 하기 때문에 before_display_content 지점을 후크로 사용합니다.
- 카운터- Before Module Init
이 애드온은 XE를 사용해서 구축한 웹사이트의 방문 통계를 보기 위해 개발됐습니다. 이 애드온은 카운터 모듈을 사용합니다. 카운터 애드온은 $is_logged 변수의 정보를 사용해서 웹사이트 방문 횟수를 계산합니다. 모듈 처리 작업으로부터 더 이상 정보를 얻을 필요가 없으므로, 이 모듈은 시간상으로 첫 번째 후크인 before_module_init을 사용합니다.
앞에서 설명한 네 번의 호출 시점에 XE core는 다음과 같은 공통 변수를 애드온에 전달합니다.
- $called_position: 호출 시간 정보를 포함합니다. 값은 before_module_init, before_module_proc, after_module_proc, before_display_content 네 가지 중 하나입니다.
- $addon_path: 호출된 애드온의 경로를 포함합니다.
- $addon_info: XE의 애드온은 독립적으로 설정할 수 있고, 해당 애드온이 동작할 대상 모듈을 지정할 수 있습니다. $addon_info 변수는 애드온에서 선언된 extra_vars(info.xml 내)의 정보를 포함하며, 이는 애드온마다 다릅니다.
addons 폴더에 다양한 이름으로 된 파일을 저장할 수 있고, 폴더 내에서 클래스를 사용할 수도 있습니다. 하지만 함수 선언은 네이티브 코드로 동작하는 include 구조를 사용하기 때문에 허용되지 않습니다.
- config/Info.xml
info.xml 파일은 다음과 같이 작성합니다.
<?xml version="1.0" encoding="UTF-8"?>
<addon version="0.2">
<title xml:lang="en">Addon title</title>
<description xml:lang="en">Addon description</description>
<version>Addon version</version>
<date>Year-Month-Date</date>
<author email_address="The email address of an author" link="The homepage address of an author">
<name xml:lang="en">Author name</name>
</author>
<extra_vars>
<var name="Variable name" type="textarea">
<title xml:lang="en">Variable name (for output)</title>
<description xml:lang="en">Variable description</description>
</var>
</extra_vars>
</addon>
필요하면 extra_vars를 생성합니다. 세부 내용이 없으면 "<extra_vars />" 명령어를 사용해서 생략합니다. 위와 같이 작성한 파일을 info.xml이라는 이름으로 conf 폴더 아래에 저장합니다.
- addon_name.addon.php
애드온이 어떤 액션을 수행하기로 되어 있다면 PHP 형식으로 애드온 파일을 작성합니다. 단, 애드온은 대개 클래스 객체의 메서드 내에서 호출되므로 함수는 선언할 수 없습니다. 애드온 내에서 클래스를 정의하고 사용할 수 있습니다.
애드온 파일의 시작 부분은 다음과 같아야 합니다.
<?php
/**
* @file addon name.addon.php
* @author author name (email address)
* @brief description
**/
if(!defined('__ZBXE__')) exit();
XE의 모든 기능은 index.php를 통해 실행되며, index.php는 __ZBXE__상수가 true로 설정되면 시작됩니다. 따라서, index.php에 선언되어 있는 __ZBXE__상수가 true로 설정되어 있는지 기능을 실행하기 전에 확인합니다. 애드온 실행 시점은 called_position으로 확인할 수 있으며, 이 작업은 반드시 해당 애드온에서 수동으로 해야 합니다.
예를 들어 페이지 아래에 모든 문서의 태그 목록을 출력하는 애드온이 있다고 가정해 보겠습니다. 우선 애드온을 호출하려면 어떤 후크가 적당한지 확인해야 합니다. 문서의 목록을 얻으려면 다음 코드와 같이 페이지 모듈을 처리해서 'after_module_proc'를 사용해야 합니다.
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file tag_list.addon.php
* @author Author (author@authorland.com)
* @brief Description of the addon
**/
if($called_position != 'after_module_proc' || Context::getResponseMethod()!=='HTML') return;
$obj->module_srl=Context::get('module_srl');
$document_list=executeQueryArray('addons.tag_list.getModuleDocumentTags',$obj);
$tags='';
foreach ($document_list->data as $val) {
$tags=$tags.','.$val->tags;
}
$tags=explode(',', $tags);
for($i=1;$i<count($tags);$i++) {
$tags[$i]='<a href="'.getUrl('act','TS','is_keyword',$tags[$i]).'">'.$tags[$i].'</a>';
}
$tags=implode(' ', $tags);
$tags='<div class="tags" align="center">'.$tags.'</div>';
$content=Context::get('page_content');
$content=$content.$tags;
Context::set('page_content',$content);
?>
위의 코드는 현재 보이는 HTML 페이지에 태그 목록 HTML 코드를 삽입합니다.
XE 애드온에서 다른 모듈이 생성한 DB에 있는 데이터는 XML 쿼리를 통해 사용할 수 있습니다. 이 경우 addon 폴더 아래에 queries라는 폴더를 하나 생성하고 XML 쿼리문을 정의한 XML 파일을 저장합니다. 쿼리를 실행하는 방법은 다음과 같습니다.
$document_list=executeQueryArray('addons.tag_list.getModuleDocumentTags',$obj);
애드온을 생성할 때 고려 사항은 다음과 같습니다.
- XE의 애드온은 모든 모듈의 여러 부분에 삽입되므로 <?php ... ?> 앞뒤로 공백이 없어야 합니다. 공백이 포함되면 before_display_content가 호출되어도 제대로 동작하지 않습니다.
- XE core는 애드온을 프로그래밍할 때 발생할 수 있는 예외를 별도로 처리하지 않습니다. 따라서 현재 호출 상황을 확인하는 루틴을 잘 구현해서 예외가 발생하지 않도록 해야 합니다.
- 애드온 코드 에러로 인해 웹 사이트에 심각한 에러가 발생한다면 files/cache/activated_addons.cache.php 파일을 수정해서 다시 업로드합니다.
XE 애드온은 강력한 액션을 수행할 수 있습니다. 하지만 코드를 적절하게 작성하지 않으면 예기치 않은 결과가 나오거나 XE가 중단될 수도 있습니다. 따라서 애드온을 생성할 때는 기본 애드온을 참조하는 것을 권장합니다.