애드온 구조¶
라이믹스 애드온의 파일 구조와 핵심 구성 요소를 학습합니다.
기본 파일 구조¶
애드온 디렉토리 구성¶
addons/
└── my_addon/
├── my_addon.addon.php # 메인 애드온 파일 (필수)
├── conf/
│ └── info.xml # 애드온 정보 파일 (필수)
├── schemas/
│ └── install.xml # 데이터베이스 스키마
├── queries/
│ ├── insertData.xml # XML 쿼리 파일들
│ ├── updateData.xml
│ └── selectData.xml
├── lang/
│ ├── ko.lang.php # 한국어 언어팩
│ └── en.lang.php # 영어 언어팩
├── tpl/
│ ├── config.html # 설정 템플릿
│ └── admin.html # 관리 템플릿
├── js/
│ └── addon.js # JavaScript 파일
├── css/
│ └── addon.css # CSS 파일
└── README.md # 문서
필수 파일 구성¶
1. info.xml - 애드온 정보 파일¶
<?xml version="1.0" encoding="UTF-8"?>
<addon version="0.2">
<!-- 기본 정보 -->
<title xml:lang="ko">나의 애드온</title>
<title xml:lang="en">My Addon</title>
<description xml:lang="ko">애드온에 대한 상세 설명입니다.</description>
<description xml:lang="en">Detailed description of the addon.</description>
<!-- 버전 및 날짜 -->
<version>1.0.0</version>
<date>2024-01-01</date>
<!-- 제작자 정보 -->
<author email_address="developer@example.com" link="https://example.com">
<name xml:lang="ko">개발자</name>
<name xml:lang="en">Developer</name>
</author>
<!-- 의존성 정의 -->
<dependency>
<!-- 필수 모듈 -->
<module name="member" />
<module name="board" version="1.0.0" />
<!-- 필수 애드온 -->
<addon name="mobile" />
<!-- 라이믹스 버전 요구사항 -->
<rhymix version="2.0.0" />
</dependency>
<!-- 설정 변수 정의 -->
<extra_vars>
<!-- 텍스트 입력 -->
<var name="site_name" type="text" default="My Site">
<title xml:lang="ko">사이트명</title>
<title xml:lang="en">Site Name</title>
<description xml:lang="ko">사이트 이름을 입력하세요.</description>
</var>
<!-- 선택 박스 -->
<var name="enable_cache" type="select" default="Y">
<title xml:lang="ko">캐시 사용</title>
<title xml:lang="en">Enable Cache</title>
<options value="Y">Yes</options>
<options value="N">No</options>
</var>
<!-- 체크박스 -->
<var name="enabled_features" type="checkbox">
<title xml:lang="ko">활성화할 기능</title>
<title xml:lang="en">Features to Enable</title>
<options value="feature1">기능 1</options>
<options value="feature2">기능 2</options>
<options value="feature3">기능 3</options>
</var>
<!-- 텍스트 영역 -->
<var name="custom_css" type="textarea">
<title xml:lang="ko">커스텀 CSS</title>
<title xml:lang="en">Custom CSS</title>
<description xml:lang="ko">추가 CSS 코드를 입력하세요.</description>
</var>
</extra_vars>
</addon>
2. 메인 애드온 파일 구조¶
<?php
/**
* 애드온명: My Addon
* 설명: 라이믹스용 커스텀 애드온
* 버전: 1.0.0
* 제작자: Developer
*/
// 보안 검사
if(!defined("__XE__")) exit();
// 애드온 클래스 정의
class MyAddon
{
private $config;
private $addon_path;
public function __construct()
{
$this->addon_path = __XE_PATH__ . 'addons/my_addon/';
$this->loadConfig();
}
/**
* 설정 로드
*/
private function loadConfig()
{
// 애드온 설정 가져오기
$oAddonModel = getModel('addon');
$this->config = $oAddonModel->getAddonConfig('my_addon');
// 기본값 설정
if(!$this->config) {
$this->config = new stdClass();
}
$this->setDefaultConfig();
}
/**
* 기본 설정값 설정
*/
private function setDefaultConfig()
{
$defaults = array(
'enabled' => 'Y',
'cache_time' => 3600,
'max_items' => 10
);
foreach($defaults as $key => $value) {
if(!isset($this->config->{$key})) {
$this->config->{$key} = $value;
}
}
}
/**
* 애드온이 실행되어야 하는지 확인
*/
public function shouldExecute()
{
// 비활성화된 경우
if($this->config->enabled !== 'Y') {
return false;
}
// 관리자 페이지에서는 실행하지 않음
if(Context::get('module') === 'admin') {
return false;
}
return true;
}
/**
* 모듈 실행 전 처리
*/
public function beforeModuleProc()
{
if(!$this->shouldExecute()) return;
// 요청 데이터 검증
$this->validateRequest();
// 권한 확인
$this->checkPermissions();
}
/**
* 모듈 실행 후 처리
*/
public function afterModuleProc()
{
if(!$this->shouldExecute()) return;
// 결과 데이터 처리
$this->processResults();
// 추가 데이터 설정
$this->setAdditionalData();
}
/**
* 화면 출력 전 처리
*/
public function beforeDisplayContent()
{
if(!$this->shouldExecute()) return;
// CSS/JavaScript 파일 추가
$this->addAssets();
// 메타태그 추가
$this->addMetaTags();
}
/**
* 요청 데이터 검증
*/
private function validateRequest()
{
// 입력값 검증 로직
}
/**
* 권한 확인
*/
private function checkPermissions()
{
// 권한 확인 로직
}
/**
* 결과 데이터 처리
*/
private function processResults()
{
// 결과 처리 로직
}
/**
* 추가 데이터 설정
*/
private function setAdditionalData()
{
// 추가 데이터 설정 로직
}
/**
* CSS/JS 파일 추가
*/
private function addAssets()
{
// CSS 파일 추가
if(file_exists($this->addon_path . 'css/addon.css')) {
Context::addCSSFile($this->addon_path . 'css/addon.css');
}
// JavaScript 파일 추가
if(file_exists($this->addon_path . 'js/addon.js')) {
Context::addJSFile($this->addon_path . 'js/addon.js');
}
}
/**
* 메타태그 추가
*/
private function addMetaTags()
{
// 메타태그 추가 로직
}
}
// 애드온 인스턴스 생성
$my_addon = new MyAddon();
// 트리거 포인트별 실행
switch($called_position) {
case 'before_module_proc':
$my_addon->beforeModuleProc();
break;
case 'after_module_proc':
$my_addon->afterModuleProc();
break;
case 'before_display_content':
$my_addon->beforeDisplayContent();
break;
}
?>
데이터베이스 스키마¶
schemas/install.xml¶
<?xml version="1.0" encoding="UTF-8"?>
<schema version="0.3">
<!-- 메인 테이블 -->
<table name="addon_my_addon_data">
<column name="data_srl" type="number" size="11" notnull="notnull" primary_key="primary_key" />
<column name="member_srl" type="number" size="11" index="idx_member" />
<column name="title" type="varchar" size="250" index="idx_title" />
<column name="content" type="text" />
<column name="status" type="varchar" size="10" default="active" index="idx_status" />
<column name="view_count" type="number" size="11" default="0" />
<column name="regdate" type="date" index="idx_regdate" />
<column name="last_update" type="date" />
</table>
<!-- 설정 테이블 -->
<table name="addon_my_addon_config">
<column name="config_srl" type="number" size="11" notnull="notnull" primary_key="primary_key" />
<column name="config_key" type="varchar" size="100" unique="unique" />
<column name="config_value" type="text" />
<column name="regdate" type="date" />
</table>
<!-- 로그 테이블 -->
<table name="addon_my_addon_logs">
<column name="log_srl" type="number" size="11" notnull="notnull" primary_key="primary_key" />
<column name="member_srl" type="number" size="11" index="idx_member" />
<column name="action" type="varchar" size="50" index="idx_action" />
<column name="target_srl" type="number" size="11" />
<column name="ip_address" type="varchar" size="45" />
<column name="user_agent" type="text" />
<column name="data" type="text" />
<column name="regdate" type="date" index="idx_regdate" />
</table>
</schema>
XML 쿼리 파일¶
queries/insertData.xml¶
<?xml version="1.0" encoding="UTF-8"?>
<query id="insertData" action="insert">
<tables>
<table name="addon_my_addon_data" />
</tables>
<columns>
<column name="member_srl" var="member_srl" />
<column name="title" var="title" />
<column name="content" var="content" />
<column name="status" var="status" default="active" />
<column name="regdate" var="regdate" />
<column name="last_update" var="last_update" />
</columns>
</query>
queries/selectDataList.xml¶
<?xml version="1.0" encoding="UTF-8"?>
<query id="selectDataList" action="select">
<tables>
<table name="addon_my_addon_data" alias="d" />
<table name="member" alias="m" />
</tables>
<columns>
<column name="d.*" />
<column name="m.nick_name" />
<column name="m.email_address" />
</columns>
<conditions>
<condition operation="equal" column="d.status" var="status" default="active" />
<condition operation="like" column="d.title" var="search_keyword" />
<condition operation="more" column="d.regdate" var="start_date" filter="date" />
<condition operation="less" column="d.regdate" var="end_date" filter="date" />
</conditions>
<navigation>
<index var="sort_index" default="d.regdate" order="order_type" />
<list_count var="list_count" default="20" />
<page_count var="page_count" default="10" />
<page var="page" default="1" />
</navigation>
<joins>
<join type="left" table="member" alias="m" on="d.member_srl = m.member_srl" />
</joins>
</query>
언어팩 파일¶
lang/ko.lang.php¶
<?php
/**
* 한국어 언어팩
*/
// 기본 문구
$lang->my_addon = '나의 애드온';
$lang->my_addon_description = '애드온 설명';
// 설정 관련
$lang->my_addon_config = '애드온 설정';
$lang->my_addon_enabled = '애드온 활성화';
$lang->my_addon_cache_time = '캐시 시간';
$lang->my_addon_max_items = '최대 항목 수';
// 메시지
$lang->msg_my_addon_success = '작업이 성공적으로 완료되었습니다.';
$lang->msg_my_addon_error = '오류가 발생했습니다.';
$lang->msg_my_addon_no_permission = '권한이 없습니다.';
$lang->msg_my_addon_invalid_data = '잘못된 데이터입니다.';
// 버튼
$lang->cmd_my_addon_save = '저장';
$lang->cmd_my_addon_cancel = '취소';
$lang->cmd_my_addon_delete = '삭제';
$lang->cmd_my_addon_modify = '수정';
// 필드명
$lang->my_addon_title = '제목';
$lang->my_addon_content = '내용';
$lang->my_addon_author = '작성자';
$lang->my_addon_regdate = '등록일';
$lang->my_addon_status = '상태';
// 상태값
$lang->my_addon_status_active = '활성';
$lang->my_addon_status_inactive = '비활성';
$lang->my_addon_status_pending = '대기';
?>
설정 템플릿¶
tpl/config.html¶
<!-- 애드온 설정 페이지 -->
<form action="{getUrl()}" method="post" class="addon-config-form">
<input type="hidden" name="addon" value="my_addon" />
<input type="hidden" name="act" value="procAddonAdminSetup" />
<div class="config-section">
<h3>기본 설정</h3>
<!-- 활성화 여부 -->
<div class="form-group">
<label for="enabled">애드온 활성화</label>
<select name="enabled" id="enabled">
<option value="Y" selected="selected"|cond="$addon_config->enabled=='Y'">예</option>
<option value="N" selected="selected"|cond="$addon_config->enabled=='N'">아니오</option>
</select>
</div>
<!-- 캐시 시간 -->
<div class="form-group">
<label for="cache_time">캐시 시간 (초)</label>
<input type="number" name="cache_time" id="cache_time"
value="{$addon_config->cache_time}" min="0" max="86400" />
<p class="help-text">0으로 설정하면 캐시를 사용하지 않습니다.</p>
</div>
<!-- 최대 항목 수 -->
<div class="form-group">
<label for="max_items">최대 표시 항목 수</label>
<input type="number" name="max_items" id="max_items"
value="{$addon_config->max_items}" min="1" max="100" />
</div>
</div>
<div class="config-section">
<h3>고급 설정</h3>
<!-- 제외할 페이지 -->
<div class="form-group">
<label for="excluded_pages">제외할 페이지 (mid, 콤마로 구분)</label>
<textarea name="excluded_pages" id="excluded_pages" rows="3">{$addon_config->excluded_pages}</textarea>
<p class="help-text">예: admin, private, test</p>
</div>
<!-- 커스텀 CSS -->
<div class="form-group">
<label for="custom_css">커스텀 CSS</label>
<textarea name="custom_css" id="custom_css" rows="10">{$addon_config->custom_css}</textarea>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">설정 저장</button>
<button type="button" class="btn btn-secondary" onclick="history.back()">취소</button>
</div>
</form>
<style>
.addon-config-form {
max-width: 800px;
margin: 0 auto;
}
.config-section {
background: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
}
.config-section h3 {
margin-top: 0;
margin-bottom: 20px;
color: #333;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input[type="text"],
.form-group input[type="number"],
.form-group select,
.form-group textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.form-group textarea {
resize: vertical;
font-family: 'Consolas', 'Monaco', monospace;
}
.help-text {
margin-top: 5px;
font-size: 12px;
color: #666;
}
.form-actions {
text-align: center;
padding-top: 20px;
border-top: 1px solid #eee;
}
.btn {
padding: 10px 20px;
margin: 0 5px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
</style>
모범 사례¶
- 파일 구조: 명확한 디렉토리 구조로 파일 관리
- 네이밍: 일관된 명명 규칙 사용
- 설정 관리: 유연한 설정 시스템 구축
- 에러 처리: 적절한 예외 처리 구현
- 문서화: 상세한 주석과 README 작성
다음 단계¶
애드온 구조를 이해했다면, 애드온 기초를 학습하세요.