Laravel을 알고 있다면 DXCMS는 금방 읽힙니다. 이 문서는 Laravel의 개념•문법과 DXCMS의 대응 구조를 1:1로 비교해 불필요한 학습 시간을 줄여줍니다.
| 항목 | Laravel | DXCMS | 체감 난이도 |
|---|---|---|---|
| 라우터 | Route::get(), Route::post() | DxRouter::get(), DxRouter::post() | ★☆☆ 거의 동일 |
| 미들웨어 | ->middleware('auth') | ->middleware('auth') | ★☆☆ 문법 동일 |
| QueryBuilder | DB::table()->where()->get() | $db->table()->where()->get() | ★☆☆ 거의 동일 |
| DI 컨테이너 | app()->bind(), app()->make() | dx_app()->bind(), dx_make() | ★☆☆ 거의 동일 |
| 이벤트/훅 | Event::dispatch(), listen() | dx_run_hook(), dx_add_hook() | ★★☆ 개념 동일, 문법 다름 |
| 템플릿 | Blade @extends / @section | PHP include 직접 | ★☆☆ 더 단순 |
| 환경 설정 | .env + config() | data/config.php + dx_config() | ★☆☆ 거의 동일 |
| 플래시 메시지 | session()->flash() | dx_flash() / dx_get_flash() | ★☆☆ 거의 동일 |
| JSON 응답 | response()->json() | dx_json() | ★☆☆ 거의 동일 |
| Artisan | php artisan make:controller | 없음 — 파일 직접 생성 | ★★☆ 수동 생성 |
| Eloquent ORM | User::find($id) | 없음 — QueryBuilder 직접 사용 | ★★☆ SQL 익숙하면 쉬움 |
| Service Provider | AppServiceProvider::boot() | plugin.php + manifest.php | ★★☆ 비슷한 개념 |
1. 라우팅
문법이 거의 동일합니다. routes/ 폴더에 PHP 파일을 만들면 자동으로 로드됩니다.
1.1 기본 라우트 등록
Laravel (routes/web.php)
// GET 라우트
Route::get('/mypage', 'MemberController@index')
->middleware('auth');
// POST 라우트
Route::post('/api/update', 'MemberController@update')
->middleware(['auth', 'verified']);
// 클로저 라우트
Route::get('/health', function() {
return response()->json(['status'=>'ok']);
});
DXCMS (routes/web.php)
// GET 라우트
DxRouter::get('/mypage', 'MemberController@index')
->middleware('auth');
// POST 라우트
DxRouter::post('/api/update', 'MemberController@update')
->middleware(array('auth', 'csrf'));
// 클로저 라우트
DxRouter::get('/health', function() {
dx_json(array('status' => 'ok'));
exit;
});
1.2 라우트 그룹Laravel
Route::group([
'prefix' => '/shop',
'middleware' => 'auth'
], function() {
Route::get('/cart', 'ShopController@cart');
Route::post('/order', 'ShopController@order');
});
DXCMS
DxRouter::group(array(
'prefix' => '/shop',
'middleware' => 'auth'
), function() {
DxRouter::get('/cart', 'ShopController@cart');
DxRouter::post('/order', 'ShopController@order')
->middleware('csrf');
});
1.3 미들웨어 목록
| DXCMS 미들웨어 | Laravel 대응 | 설명 |
|---|---|---|
| auth | auth | 로그인 필수. 미로그인 → 로그인 페이지 리다이렉트. |
| admin | can('admin') / role('admin') | 관리자 필수. 비관리자 → 403. |
| guest | guest | 비로그인만 접근. |
| csrf | ValidateCsrfToken (기본 적용) | POST CSRF 토큰 검증. |
| json | 없음 (헤더 수동 설정) | JSON 응답 헤더 자동 설정. |
2. 컨트롤러
controllers/ 폴더에 파일을 생성합니다. Artisan은 없으므로 직접 생성합니다.
2.1 컨트롤러 기본 구조
Laravel (app/Http/Controllers/)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MemberController extends Controller
{
public function index(Request $request)
{
$user = auth()->user();
return view('mypage', compact('user'));
}
}
DXCMS (controllers/)
<?php
if (!defined('DX_CMS')) exit;
// namespace 없음
class MemberController
{
public function index()
{
$user = Auth::getInstance()->user();
// 뷰는 직접 include
include DX_THEMES . '/default/mypage.php';
}
}
DXCMS는 namespace와 타입힌트 없이 PHP 5.6 방식으로 작성합니다. 그 외 구조는 동일합니다.3. QueryBuilder — DB 쿼리
Laravel의 DB 파사드와 거의 동일한 체이닝 방식입니다. $db = Database::getInstance() 로 인스턴스를 가져옵니다.
3.1 기본 SELECT
Laravel
// 전체 조회
DB::table('posts')->get();
// 조건 + 정렬
DB::table('posts')
->where('board_id', 1)
->where('status', 1)
->orderBy('id', 'desc')
->get();
// 단건 조회
DB::table('posts')->find($id);
DB::table('posts')->first();
DXCMS
// 전체 조회
$db->table('posts')->get();
// 조건 + 정렬
$db->table('posts')
->where('board_id', 1)
->where('status', 1)
->orderBy('id', 'desc')
->get();
// 단건 조회
$db->find('posts', array('id' => $id));
$db->table('posts')->first();
3.2 WHERE 변형
Laravel
->where('level', '>=', 5)
->orWhere('role', 'admin')
->whereIn('id', [1, 2, 3])
->whereNotIn('status', [0, 2])
->whereNull('deleted_at')
->whereNotNull('email')
->whereBetween('point', [100, 500])
->whereRaw('YEAR(created_at) = ?', [2025])
DXCMS
->where('level', '>=', 5)
->orWhere('role', 'admin')
->whereIn('id', array(1, 2, 3))
->whereNotIn('status', array(0, 2))
->whereNull('deleted_at')
->whereNotNull('email')
->whereBetween('point', 100, 500)
->whereRaw('YEAR(created_at) = ?', array(2025))
3.3 JOIN / SELECT / 집계Laravel
DB::table('posts')
->select('posts.*', 'members.name')
->join('members',
'posts.member_id', '=', 'members.id')
->get();
DB::table('posts')->count();
DB::table('posts')->sum('view_count');
DB::table('posts')->paginate(20);
DXCMS
$db->table('posts')
->select(array('posts.*', 'members.name'))
->join('members',
'posts.member_id', '=', 'members.id')
->get();
$db->table('posts')->count();
$db->table('posts')->sum('view_count');
$db->table('posts')->paginate(20);
3.4 INSERT / UPDATE / DELETE
Laravel
// INSERT
DB::table('posts')->insert([
'title' => '제목',
'content' => '내용',
]);
// UPDATE
DB::table('posts')
->where('id', $id)
->update(['title' => '수정']);
// DELETE
DB::table('posts')->where('id', $id)->delete();
DXCMS
// INSERT
$db->insert('posts', array(
'title' => '제목',
'content' => '내용',
));
// UPDATE
$db->update('posts',
array('title' => '수정'),
array('id' => $id)
);
// DELETE
$db->delete('posts', array('id' => $id));
4. 인증 (Auth)
4.1 현재 사용자 조회
Laravel
auth()->check();
// 현재 사용자
auth()->user();
auth()->id();
// 게스트 여부
auth()->guest();
// 역할 확인
auth()->user()->hasRole('admin');
DXCMS
Auth::getInstance()->check();
// 현재 사용자 (배열 반환)
Auth::getInstance()->user();
Auth::getInstance()->id();
// 게스트 여부
Auth::getInstance()->guest();
// 역할 확인
$user = Auth::getInstance()->user();
$user['role'] === 'admin';
Laravel은 객체 반환, DXCMS는 배열 반환입니다. $user->name 대신 $user['name'] 으로 접근합니다.4.2 권한 레벨
| 레벨 값 | 의미 | Laravel 대응 |
|---|---|---|
| 0 | 전체 공개 (비회원 포함) | 없음 / public |
| 1 | 회원만 (member 이상) | auth 미들웨어 |
| 2 | 매니저 이상 | role('manager') |
| 9 | 관리자만 (admin) | role('admin') / admin 미들웨어 |
5. 환경 설정 및 헬퍼 함수
5.1 설정값 읽기
Laravel
// .env 값
env('APP_NAME', 'MyApp');
// config/ 값
config('app.name');
config('app.locale', 'ko');
DXCMS
// data/config.php 값
dx_config('db_host', 'localhost');
// dx_settings 테이블 값
dx_setting('site_name');
dx_setting('language', 'ko');
5.2 요청 헬퍼
Laravel
$request->get('name', '');
$request->post('email');
$request->input('key');
$request->isMethod('POST');
$request->ajax();
$request->ip();
DXCMS
dx_get('name', '');
dx_post('email');
dx_request('key');
dx_method('POST'); // bool 반환
dx_is_ajax();
dx_ip();
5.3 응답 헬퍼
Laravel
// JSON 응답
return response()->json(['ok' => true]);
// 리다이렉트
return redirect('/home');
return redirect()->back();
// 에러
abort(403, 'Forbidden');
// 플래시 메시지
session()->flash('success', '저장됨');
session('success');
DXCMS
// JSON 응답
dx_json(array('ok' => true)); exit;
// 리다이렉트
dx_redirect(dx_base_url('/home'));
dx_redirect_back();
// 에러
dx_error('Forbidden', 403);
// 플래시 메시지
dx_flash('저장됨', 'success');
dx_get_flash();
5.4 보안 헬퍼
Laravel
// XSS 이스케이프
e($string);
{{ $var }} // Blade 자동 이스케이프
// CSRF 필드
@csrf
csrf_field()
// CSRF 토큰
csrf_token()
DXCMS
// XSS 이스케이프
dx_esc($string);
<?= dx_esc($var) ?> // PHP 직접
// CSRF 필드 (hidden input 출력)
dx_csrf_field();
// CSRF 토큰만
dx_csrf_token()
6. 템플릿 (뷰)
DXCMS는 Blade 없이 PHP 파일을 직접 사용합니다. 오히려 더 단순합니다.
6.1 레이아웃 상속
Laravel (Blade)
{{-- 레이아웃 파일 --}}
<html>
<body>
@yield('content')
</body>
</html>
{{-- 자식 뷰 --}}
@extends('layouts.main')
@section('content')
<h1>페이지 내용</h1>
@endsection
DXCMS (PHP)
<!-- layout/main.php -->
<html>
<body>
<?php include $content_file; ?>
</body>
</html>
<!-- themes/default/page/mypage.php -->
// include는 main.php가 처리
// 이 파일 = 순수 컨텐츠만
<h1>페이지 내용</h1>
6.2 Blade 문법 → PHP 변환
Laravel (Blade)
{{ $var }}
{!! $html !!}
@if($cond) ... @endif
@foreach($items as $item)
{{ $item->name }}
@endforeach
@csrf
@auth ... @endauth
@guest ... @endguest
{{ url('/path') }}
{{ asset('css/app.css') }}
DXCMS (PHP)
<?= dx_esc($var) ?>
<?= $html ?>
<?php if($cond): ?> ... <?php endif; ?>
<?php foreach($items as $item): ?>
<?= dx_esc($item['name']) ?>
<?php endforeach; ?>
<?= dx_csrf_field() ?>
<?php if(Auth::getInstance()->check()): ?>
<?php if(Auth::getInstance()->guest()): ?>
<?= dx_base_url('/path') ?>
<?= dx_static_url('css/app.css') ?>
DXCMS는 Blade처럼 자동 이스케이프가 없으므로 반드시 dx_esc()를 사용하세요7. 이벤트 / 훅 시스템
Laravel의 Event::dispatch() ↔ do_action() 방식입니다. WordPress에 익숙하다면 완전히 동일한 패턴입니다.
7.1 Action 훅 (이벤트)
Laravel
// 이벤트 발생
event(new PostSaved($post));
// 리스너 등록
Event::listen(PostSaved::class,
function($event) {
Log::info($event->post->title);
}
);
DXCMS
// 훅 실행
dx_run_hook('after_post_save',
array('post' => $post)
);
// 훅 등록 (plugin.php에서)
dx_add_hook('after_post_save',
function($data) {
dx_log($data['post']['title']);
}
);
7.2 Filter 훅 (값 변환)Laravel
// 필터 적용
$content = pipeline($content)
->through([ContentFilter::class])
->thenReturn();
// 필터 클래스
class ContentFilter {
public function handle($content, $next) {
return $next($content . '<p>광고</p>');
}
}
DXCMS
// 필터 적용
$content = dx_apply_filter(
'post_content', $content
);
// 필터 등록 (plugin.php에서)
dx_add_hook('post_content',
function($content) {
return $content . '<p>광고</p>';
}
);
7.3 주요 훅 포인트
| 훅 이름 | 실행 시점 | Laravel 대응 개념 |
|---|---|---|
| dx_top | 모든 페이지 최상단 (body 직후) | layout 상단 |
| dx_bottom | 모든 페이지 최하단 (body 닫기 전) | layout 하단 |
| dx_board_top | 게시판 페이지 상단 | BoardController 진입 전 |
| after_post_save | 게시글 저장 완료 후 | PostSaved 이벤트 |
| before_post_save | 게시글 저장 직전 | saving 이벤트 |
| after_comment_save | 댓글 저장 완료 후 | CommentSaved 이벤트 |
| member_login | 로그인 성공 후 | Login 이벤트 |
| member_register | 회원가입 완료 후 | Registered 이벤트 |
| post_content | 게시글 본문 출력 필터 | - |
| board_list_query | 게시글 목록 쿼리 필터 | - |
8. 의존성 컨테이너 (DI Container)
Laravel
// 바인딩
app()->bind('mailer', function($app) {
return new MyMailer(config('smtp'));
});
// 싱글턴
app()->singleton('sms', function($app) {
return new AlimtalkSMS(config('key'));
});
// 꺼내 쓰기
$mailer = app('mailer');
$mailer = app()->make('mailer');
DXCMS
// 바인딩
dx_app()->bind('mailer', function() {
return new MyMailer(dx_config('smtp'));
});
// 싱글턴
dx_app()->singleton('sms', function() {
return new AlimtalkSMS(dx_config('key'));
});
// 꺼내 쓰기
$mailer = dx_make('mailer');
$mailer = dx_app()->make('mailer');
9. 플러그인 = Laravel Service ProviderLaravel의 Service Provider와 거의 동일한 역할입니다. manifest.php = composer.json, plugin.php = ServiceProvider::boot()
9.1 구조 비교
| Laravel | DXCMS | 역할 |
|---|---|---|
| composer.json | manifest.php | 패키지/플러그인 메타 정보 |
| ServiceProvider::register() | plugin.php 상단 초기화 코드 | 서비스 등록 |
| ServiceProvider::boot() | dx_add_hook() 등록 코드 | 훅/이벤트 등록 |
| config/*.php | manifest.php config 배열 | 기본 설정값 |
| resources/views/ | 플러그인 내 PHP 뷰 파일 | 뷰 템플릿 |
| public/vendor/ | assets/ 폴더 | 공개 정적 파일 |
9.2 manifest.php 예시
<?php
// plugins/my-plugin/manifest.php
return array(
'name' => 'My Plugin',
'version' => '1.0.0',
'author' => '홍길동',
'description' => '플러그인 설명',
'config' => array(
'api_key' => '',
'enabled' => true,
),
);
9.3 plugin.php 예시
<?php
// plugins/my-plugin/plugin.php
if (!defined('DX_CMS')) exit;
// 서비스 등록 (register 역할)
dx_app()->singleton('my_service', function() {
return new MyService(dx_config('api_key'));
});
// 훅 등록 (boot 역할)
dx_add_hook('after_post_save', function($data) {
$svc = dx_make('my_service');
$svc->notify($data['post']);
}, 10);
// 레이아웃 하단에 JS 삽입
dx_add_hook('dx_bottom', function() {
echo '<script src="..."></script>';
});
10. 핵심 차이점 — 주의사항
| 주제 | Laravel | DXCMS | 주의 포인트 |
|---|---|---|---|
| 배열 문법 | [] 단축 문법 | array() 사용 | PHP 5.6 호환을 위해 [] 대신 array() |
| Eloquent | User::find($id) | 없음. $db->find('members', ...) | 모델 클래스 없음. QueryBuilder 직접 |
| 사용자 반환 | auth()->user() → 객체 | Auth::getInstance()->user() → 배열 | $user->name 대신 $user['name'] |
| 자동 이스케이프 | Blade {{ }} 자동 | 없음 → dx_esc() 직접 | XSS 방지 위해 반드시 dx_esc() 필수 |
| CSRF | Web 라우트 자동 적용 | ->middleware('csrf') 명시 필요 | POST 라우트에 반드시 명시 |
| Artisan | php artisan make:* | 없음. 파일 직접 생성 | boilerplate 직접 작성 |
| 네임스페이스 | 사용 | 없음 (PHP 5.6 호환) | class 이름 중복 주의 |
| 테이블 접근 | DB::table('users') | $db->table('members') → dx_members | 프리픽스 dx_ 자동 추가 |
| 뷰 반환 | return view('name', $data) | include $file; 또는 renderWithLayout() | 컨트롤러에서 직접 include |
11. Laravel 개발자 적응 체크리스트
| 단계 | 할 일 | 예상 시간 |
|---|---|---|
| 1 | index.php → core/router/ → core/DxRouter.php 흐름 추적 | 30분 |
| 2 | boards/handler.php 읽기 — 게시판 처리 전체 흐름 파악 | 1시간 |
| 3 | themes/default/layout/main.php 읽기 — 레이아웃 구조 파악 | 30분 |
| 4 | core/functions.php 함수 목록 스캔 — dx_*() 헬퍼 파악 | 30분 |
| 5 | plugins/example-plugin/ 코드 읽기 — 플러그인 작성법 파악 | 30분 |
| 6 | routes/ 폴더에 커스텀 라우트 작성 테스트 | 30분 |
| 7 | controllers/ 에 간단한 컨트롤러 작성 테스트 | 30분 |
| 8 | extend/middle/ 에 PHP 파일 추가하여 훅 없이 코드 삽입 테스트 | 15분 |
| 전체 | 약 4~5시간 |
💡 Artisan이 없어 불편할 수 있지만, 코드 구조 자체는 Laravel보다 단순합니다. '마법'이 없어서 파일을 따라가면 전체 흐름이 다 보입니다