EC-CUBE3のプラグインについて

# EC-CUBE プラグイン

_本資料はEC-CUBE3のプラグイン制作者に向けた記事となります。_
_2015/07/30現在下書き状態で、随時アップデートをかけていきます。_

## 目次

* プラグインでできること
    + 新規ページの作成
    + 既存機能の拡張・変更
        - フックポイント：Middleware
        - 入力フォームの拡張：FormEvent
        - ビューの書き換え：FilterResponse
* プラグインの作り方
    + 最低限必要なファイル構成
    + 新規ページの作成方法
    + 既存機能の拡張・変更方法
        - フックポイント：Middleware
        - 入力フォームの拡張：FormEvent
        - ビューの書き換え：FilterResponse
* プラグインのライセンス
* 参考文献
    + Qiita
    + etc



* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 



## プラグインでできること

#### 新規ページの作成

プラグインから独自のページを定義することができます。

#### フィルター

アプリケーション全体の処理の前後や、特定の処理の前後に処理を介入させることができます。

* フックポイント：Middleware
    + アプリケーション全体の処理の前後・特定のページの処理の前後に処理を介入させることができます。
    + 全てのControllerに対して介入が可能です。
    + 決済処理のタイミングで、決済情報に介入が可能です。
* 入力フォームの拡張：FormEvent
    + フォームを送信する前や後の任意のタイミングで、入力フォームを拡張することができます。
    + 定義されているすべてのフォームに対して拡張が可能です。
* ビューの書き換え：FilterResponse
    + Responseが返却される描画される直前のHTTP HeaderやBodyを書き換えることができます。
    + 管理画面のナビゲーションを拡張することができます。
    + HTMLだけでなく、JSONで返却したいなどの変更も可能です。



* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 



## プラグインの作り方

#### ファイル構成

* {PluginName}
    + config.yml
    + event.yml
    + Migration
        - Version{YYYYmmddHHiiss}.php
    + {EventName}.php
    + PluginManager.php

* config.yml
    プラグイン全体の設定ファイルを記述します。
    設定できる項目は以下です。
    + name
        インストール後に表示されるプラグイン名です。
        任意の文字指定が可能です。
    + version
        インストール後に表示されるバージョンです。
        任意の文字指定が可能です。
        バージョンアップ管理を行う際にご活用ください。
    + code
        オーナーズストアがプラグインを識別するコードです。
        英数字でオーナーズストア内で一意となるように命名する必要があります。
    + event
        イベントの業務処理ファイル名を記述してください。
        後述の `{EventName}.php` が読み込まれます。
    + service
        イベント以外の任意のロジックを読み込ませるファイルを指定できます。
        こちらに記述したファイルが `ServiceProvider` ディレクトリ以下から読み込まれます。
        複数指定が可能です。
        Yaml配列となるようにしてください。
    + orm.path
        DoctrineORMの定義ファイルの配置ディレクトリを記述してください。

* event.yml
    利用するイベントを定義するファイルです。
    以下の形式で複数定義可能です。

```
    {HookPointName}:
    - [{MethodName}, {Priority}]
```

* Migration/Version{YYYYmmddHHiiss}.php
    データ移行用ファイルです。
    `PluginManager.php` からプラグインインストール/アンインストール時に呼ばれます。
    テーブル作成・削除、データの挿入に利用できます。

* {EventName}.php
    フックポイントや入力フォーム拡張時に呼ばれるファイルです。
    フックポイントや入力フォームの拡張をする際の、業務処理を記述します。

* PluginManager.php
    EC-CUBEがプラグインを管理するファイルです。
    プラグインインストール/アンインストール時に呼ばれます。
    `Migration` はこのファイルから呼び出します。


### プラグイン基本設定

新規のページを追加する場合も、既存機能や画面の拡張を行う場合も、
まずはプラグイン情報を基本設定ファイルに記述する必要があります。

* config.ymlの作成

まず `config.yml` を作成し、プラグイン情報を入力します。
`name` , `code` , `version` を記載してください。

```yml:config.yml
name: カテゴリーコンテンツ
code: CategoryContent
version: 1.0.0
```

必要に応じて、 [ファイル構成]() に沿って記載してください。


#### 新規ページの作成方法

`config.yml` に `service` を記載します。

```yml:config.yml
name: カテゴリーコンテンツ
code: CategoryContent
version: 1.0.0
service:
    - PluginServiceProvider
```

`/{PluginName}/ServiceProvider/PluginServiceProvider.php` が
呼び出されるようになります。

ファイルは以下のように記述します。

```php:PluginServiceProvider.php
<?php

namespace Plugin\{PluginName}\ServiceProvider;

use Eccube\Application;
use Silex\Application as BaseApplication;
use Silex\ServiceProviderInterface;

class PluginServiceProvider implements ServiceProviderInterface
{
    public function register(BaseApplication $app)
    {
    }

    public function boot(BaseApplication $app)
    {
    }
}
```

`register()` に以下のように記載することで、新しくルーティングが定義されます。
`src/Eccube/ControllerProvider/FrontControllerProvider.php` と同様に、
コントローラーとメソッドを記述する方式と、クロージャを使う方式が利用できます。

```php
    public function register(BaseApplication $app)
    {
        // コントローラーとメソッドを記述する方式
        $app->match('/sample', '\\Plugin\\{PluginName}\\PluginController::sample')->bind('sample');

        // クロージャを使う方式
        $app->get('/sample/{id}', function (Application $app, $id) {
            return 'sample id:' . $id;
        })
        ->assert('id', '\d+')
        ->bind('get_sample');
    }
```

コントローラーとメソッドを記述する方式では、記述したコントローラーの内部で、
自由に業務ロジックを記載することができます。

#### 既存機能の拡張・変更方法

###### フックポイント：Middleware
	特定の処理の前後に処理を介入させられる仕組みです。
	「特定の処理」とは、以下を指します。
	+ アプリケーションの開始時・終了時
	+ コントローラーの呼び出し時・終了時
	+ 決済処理時
	フックポイント一覧は、 [別ファイル]() を参照してください。

フックポイントを使って処理を介入させるには、 `event.yml` を作成・定義します。
`event.yml` には、

+ 利用するフックポイント
+ メソッド名
+ 優先順位 (NORMAL / FIRST / LAST)

を記述します。

```yaml:event.yaml
# 利用するフックポイント:
# 	- [メソッド名, 優先順位]
eccube.event.controller.admin_product_category_edit.after:
    - [onAdminProductCategoryEditAfter, NORMAL]
```

ここに記載したメソッドは、 `config.yml` 内の `event` に記載したファイルから呼ばれます。
`config.yml` に `event` 項を追加してください。

```yaml:config.yaml
name: カテゴリーコンテンツ
code: CategoryContent
version: 1.0.0
event: event
```

以上のように記載することで、
`/Plugin/{PluginName}event::onAdminProductCategoryEditAfter` 
が呼ばれるようになります。
このメソッド内で介入させたい処理を記述してください。

###### 入力フォームの拡張：FormEvent
    フォームを送信する前や後の任意のタイミングで、入力フォームを拡張することができます。
    `/src/Eccube/Form/Type` に定義されているすべてのフォームに対して拡張が可能です。
    以下のタイミングを自由に使うことができます。
	+ PRE_SET_DATA
	+ POST_SET_DATA
	+ PRE_SUBMIT
	+ SUBMIT
	+ POST_SUBMIT

FormEventを利用する際は、 `config.yml` に `form` 項を追加してください。
`form` 項には、ファイル名とイベント名を記載します。順番に気をつけてください。

```yaml:config.yml
form:
    # - イベント名
    #     ファイル名
    - onPreSetData:
        SampleForm
```

以上のように記載することで、 `SampleForm::onPreSetData` が呼ばれます。

フォームを拡張するイベントは、全てのフォームに対して呼び出されるので、適用するフォームを限定したいときは、
以下のように、 `$event->getForm()` にて、フォーム名を取得してください。

```php:SampleForm.php
<?php

namespace Plugin\SampleForm;

use Symfony\Component\Form\FormEvent;

class SampleForm
{
    public function onPreSetData(FormEvent $event)
    {
        $form = $event->getForm();
        if ('contact' === $form->getName()) {
            $form->add('sample_form', 'text');
        }
    }
}
```

###### ビューの書き換え：FilterResponse
描画されるコンテンツや、ヘッダを書き換えることができます。
また、管理画面のナビゲーションを拡張することができます。
EC-CUBE内部では、フックポイントと同様の仕組みを利用しています。
`config.yml` , `event.yml` に必要な情報を記載してください。
このフックポイントでは、 `FilterResponseEvent` が渡されます。

```php:event.php
    public function onRenderBefore(FilterResponseEvent $event)
    {
        $request = $event->getRequest();
        $response = $event->getResponse();

        $html = $response->getContent();
        
        /*
         * ここで$htmlを書き換える
         */

        $response->setContent($html);
        $event->setResponse($response);
    }
```

###### 管理画面：メニューの追加

管理画面の左メニューを簡単に追加することができます。
EC-CUBE本体でYamlを解析しており、そこに介入が可能です。

新規ページの作成時と同じく、 `ServiceProvider` の `register()` に記述します。
受注管理の一番後ろに追加する場合は以下のように記述してください。

```
public function register(BaseApplication $app)
{
    $app['config'] = $app->share($app->extend('config', function ($config) {
        $config['nav']['order']['child'][] = array(
        	'id' => 'order_sample',
        	'name' => 'サンプル',
        	'url' => 'sample',
        );
        
        return $config;
    }));
}
```



* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 



## プラグインのライセンス

* プラグインのライセンスは基本的に自由です。
* プラグインの作成方法によって、EC-CUBE本体のライセンスに抵触する場合、基本ルールにのっとり作成してください。
    + 該当する場合、強制的にGPLライセンスになります。
* EC-CUBEの商用ライセンスに矛盾するライセンス形態をとった場合、商用ライセンスご購入サイトにプラグインが導入できなくなります。
* 以下の点をご参照いただき、作成者の判断にてプラグインのライセンスを選択してください。
    + 推奨：プラグインを無料で配布する場合（EC-CUBEオフィシャルサイトで配布する場合）
        プラグインのライセンスは商用ライセンスに矛盾しないLGPLライセンス もしくは、LGPLライセンスに矛盾しないライセンス（BSDライセンス、MITライセンス等）を推奨します。
        [LGPLについて](http://ja.wikipedia.org/wiki/GNU_Lesser_General_Public_License)
        ※ 本マニュアルでは例として、LGPLライセンスでの作成方法を記載します。（参照：3-5 ライセンスの指定方法）
    + プラグインを有料配布する等、再配布不可なプラグインにしたい場合
        プラグインのライセンスは自由に決定することが可能です。
        ただし、商用ライセンスに矛盾するライセンス形態にした場合、商用ライセンスご購入サイトにて使用することができませんので、ご注意いただき、作成者の判断にて作成してください。
    + プラグインのライセンスを指定しない場合
        ライセンスを指定しない場合、プラグインのライセンスはEC-CUBE本体のライセンスを継承し自動的にGPLライセンスになります。
        プラグインのライセンスがGPLライセンスの場合、商用ライセンスと矛盾してしまうため、商用ライセンスご購入サイトにプラグインを導入することができなくなります。
        - EC-CUBEをGPLライセンスのまま使用される場合はプラグインがGPLライセンスでも問題なく導入できます。