1
오승훈
@akasima
• XE 커뮤니티 개발 그룹
• XE3 개발
• Database, Document, DynamicField,
Presenter..
• XE3 게시판 플러그인 개발

2
목차
33
플러그인 제작
플러그인 생성 관리자 사이트맵에서 메뉴 생성 라우트 등록
인터셉션
데이터 베이스
Manual 플러그인
4
Manual 플러그인 요구사항
5
카테고리 도큐먼트
관리자 > 사이트맵에서 메뉴 생성
6
플러그인 생성
7
플러그인 규칙
디렉토리이름은 소문자, 숫자와 언더스코어(언더바)로 작성
plugin.php, composer.json 필수
8
plugin.php - 필수 요소1
9
<?php

namespace Akasima;



use …;



class Plugin extends AbstractPlugin

{

/**

* 이 메소드는 활성화(activate) 된 플러그인이 부트될 때 항상 실행됩니다.

*

* @return void

*/

public function boot()

{

}
AbstractPlugin
10
http://api.xpressengine.io
11
플러그인 코어 패키지
플러그인
플러그인 코어 패키지는 플러그인에게
묻고 싶은게 많습니다.
12
<?php



abstract class AbstractPlugin

{

public static function getId()


public static function getIdWith($postfix =
'', $delimiter = '::')

public function activate($installedVersion =
null)



public function deactivate($installedVersion
= null)



public function install()



public function
checkInstall($installedVersion = null)



public function update($installedVersion =
null)



public function checkUpdate($currentVersion =
null)



public function uninstall()



abstract public function boot();



public function getSettingsURI()



public static function getPath($path = '')



public static function asset($path, $secure =
composer.json - 필수 요소2
13
{

"name": "xpressengine-plugin/
my_plugin",

"description": "플러그인소개",

"keywords": [

"xpressengine",

"plugin"

],

"license": "LGPL-2.0",

"version": "1.0.0",

"type": "xpressengine-plugin",

"support": {

"email": "email@email.com"

},

"authors": [

{

"name": "input your name",

"email": "input@your.email",

"homepage": "http://
mysite.com",

"role": "Developer"

}

],

"extra": {

"xpressengine": {

"title": "my_plugin_title",

"icon": "myicon.png",

"component": []

}

},

"repositories": [

{

"type": "composer",

"url": "http://
packagist.xpressengine.io/"

}

],

"require": {



},

"autoload": {

"psr-4": {

"Akasima": "src/"

}

}

}

app/Console/Commands/stubs/composer.json.stub 복사
플러그인 생성 완료
14
composer.json
pluing.php
플러그인 생성 확인
15
플러그인 켜기
16
플러그인 동작 확인
17
public function boot()

{

$this->route();

}



protected function route()

{

// implement code



Route::fixed($this->getId(), function () {

Route::get('/', [

'as' => 'my_plugin::index',

'uses' => function (Request $request) {

echo "Hello World";

}

]);

});

}
어렵다!!
간단한 command 제공
19
php artisan make:plugin my_plugin Akasima my_plugin_title
20
vendor
view
생성된 디렉토리
assets
src
composer.json
pluing.php
js, css, image
PHP source
템플릿
21
메뉴 추가
22
컴포넌트?
my_plugin
테마 스킨 매뉴얼
위젯 게시판 스킨
플러그인은 설치/실행 등 기능 꾸러미 관리의 목적
플러그인은 여러개의
기능 요소로 이루어짐
(컴포넌트가 있을 수 있음)
23
컴포넌트
Interface XE3
ModuleAbstractModule 모듈
SkinAbstractSkin 스킨
ThemeAbstractTheme 테마
WidgetAbstractWidget 위젯
UIObjectAbstractUIObject UI Object
DynamicFieldAbstractType FieldType
DynamicFieldAbstractSkin FieldSkin
24
ComponentInterface
25
ComponentInterface
26
컴포넌트 ID
플러그인 코어 패키지
my_plu
테마 스킨 매뉴
위젯 게시판
저 등록좀 해주세요~
그리고 저 한테 컴포넌트도 있으니까
이 애들도 등록할께요
27
컴포넌트 ID
플러그인 코어 패키지
my_plu
테마 스킨 매뉴
위젯 게시판
저 등록좀 해주세요~
그리고 저 한테 컴포넌트도 있으니까
이 애들도 등록할께요
플러그인 코어 패키지
컴포넌트
28
컴포넌트 ID
플러그인 코어 패키지
my_plu
테마 스킨 매뉴
위젯 게시판
Register 코어 패키지
에 컴포넌트 등록
29
컴포넌트 ID
등록된 컴포넌트 리스트
컴포넌트 ID란?
module/board@board
module/my_plugin@manual
컴포넌트종류/플러그인@컴포넌트이름
컴포넌트 ID
module/board@board
module/my_plugin@manual
// my_plugin 에서 등록한 게시판 모듈용 redSkin
module/board@board/skin/my_plugin@redSkin
// my_plugin 에서 등록한 매뉴얼 모듈용 redSkin
module/my_plugin@manual@skin/my_plugin@blueSkin
컴포넌트종류/플러그인@컴포넌트이름/컴포넌트종류/플러그인@컴포넌트이름
대상아이디/컴포넌트종류/플러그인@컴포넌트이름
32
src/Manual.php
<?php

namespace Akasima;



use XpressengineModuleAbstractModule;



class Manual extends AbstractModule

{

public static function getInstanceSettingURI($instanceId)

{

}



public function createMenuForm()

{

}



public function storeMenu($instanceId, $menuTypeParams,
$itemParams)

{

}



public function editMenuForm($instanceId)

{

33
MenuTypeInterface
34
Composer.json - 컴포넌트 등록
"extra": {

"xpressengine": {

"title": "my_plugin_title",

"icon": "myicon.png",

"component": {

“module/my_plugin@manual": {

"class": "AkasimaManual",

"name": "Manual",

"description": "akasima 매뉴얼 모듈",

"screenshot" : [

“/plugins/my_plugin/assets/img/screenshots/
akasimaManual.jpg"

]

}

}

}

},
35
메뉴 컴포넌트 추가
36
메뉴를 추가할 수 있습니다.
37
Routing
라우팅 설정이 없음
38
Routing 등록
공식사이트, Laravel 문서 참고
39
Routing 등록
http://xpressengine.io/docs/3.0/Routing
40


class Manual extends AbstractModule

{

public static function boot()

{

Route::instance(self::getId(), function () {

Route::get('', ['as' => 'index', 'uses' =>
'UserController@index']);

Route::get('/edit', ['as' => 'edit', 'uses' =>
'UserController@edit']);

Route::post('/update', ['as' => 'update', 'uses' =>
'UserController@update']);

}, ['namespace' => 'Akasima']);

}
Routing 등록
41
namespace Akasima;



use AppHttpControllersController;



class UserController extends Controller

{

public function index()

{

return Presenter::make('my_plugin::views.manual.index');

}



public function edit()

{

return 'edit';

}



public function update()

{

return 'update';

}

}
Routing 등록
UserController.php
42
<strong>메인페이지 입니다</strong>



<a href="{{instanceRoute('edit')}}">수정페이지</a>

view blade
views/manual/index.blade.php
43
44
하고 싶은 이야기는 많지만..
12월 12일 오픈 세미나가 있습니다.
더 자세한 얘기는 XEHub 에서
45
Interception
46
Interception
Hook Event Trigger
47
AOP
interception(가로채는) 을 구현하기 위해 AOP 를 도입
AOP
관점지향 프로그래밍
Aspect Oriented Programming
[Documentation]
49
Proxy 생성
Service provider 에 정의되어있습니다.
50
Interception 사용
인터셉션 등록은 plugin boot() 메소드에 정의
intercept(

'Comment@add',

'notification.comment.add',

function ($addFunc, CommentEntity $comment,
MemberEntityInterface $user = null) {


/**

* @var $commentNotificator CommentNotificator

*/

$commentNotificator =
app('xe.notification.notificator.comment');

$commentNotificator->notify($comment);



$commentEntity = $addFunc($comment, $user);



return $commentEntity;

}

);
51
Interception 사용
댓글 작성시 알림 발송(알림센터)
intercept(

'Comment@add',

'notification.comment.add',

function ($addFunc, CommentEntity $comment,
MemberEntityInterface $user = null) {


/**

* @var $commentNotificator CommentNotificator

*/

$commentNotificator =
app('xe.notification.notificator.comment');

$commentNotificator->notify($comment);



$commentEntity = $addFunc($comment, $user);



return $commentEntity;

}

);
동작 시점
코드
실제 동작 대상 실행
52
Interception 사용
댓글 작성시 알림 발송 - 댓글
intercept(

'Comment@add',

'notification.comment.add',

function ($addFunc, CommentEntity $comment,
MemberEntityInterface $user = null) {


$commentEntity = $addFunc($comment, $user);



/**

* @var $commentNotificator CommentNotificator

*/

$commentNotificator =
app('xe.notification.notificator.comment');

$commentNotificator->notify($comment);



return $commentEntity;

}

);
데이타 베이스 사용하기
53
데이타 베이스
54
트랜잭션
55
intercept(

'Comment@add',

'notification.comment.add',

function ($addFunc, CommentEntity $comment,
MemberEntityInterface $user = null) {


XeDB::beginTransaction();



$commentNotificator =
app('xe.notification.notificator.comment');

$commentNotificator->notify($comment);



$commentEntity = $addFunc($comment, $user);



XeDB::commit();


return $commentEntity;

}

);
트랜잭션
56
intercept(

'Comment@add',

'notification.comment.add',

function ($addFunc, CommentEntity $comment,
MemberEntityInterface $user = null) {


XeDB::beginTransaction();



$commentNotificator =
app('xe.notification.notificator.comment');

$commentNotificator->notify($comment);



$commentEntity = $addFunc($comment, $user);



XeDB::commit();


return $commentEntity;

}

);
데이터 베이스 테이블
57
if (Schema::hasTable(‘table_name') === false) {

Schema::create('table_name', function (Blueprint $table) {

$table->increments('id');

$table->string('instanceId', 255);

$table->string('title', 255);



$table->index(array('title'));

});

}
디버깅
58
/storage/log/laravel.log 참고
APP_DEBUG=true
/.env
캐시 삭제
59
php artisan xeCache:clear
감사합니다
60

XECon2015 :: [3-2] 오승훈 - XE3 플러그인 제작 소개