EC-CUBE4 独自プラグイン開発　①Dockerで環境構築 + xdebug導入

# 概要
EC-CUBE4で独自プラグインを開発することになった。
プロジェクトの最初から最後まで関わるのは初めてなので、あとで自分が振り返るために考えたことや試したことをどこかに記録しておこうと思った。

本記事では、Dockerで開発環境を構築する手順を書く。内容は、他のメンバーに共有するために仕事中に調べてまとめたものを加筆・修正しただけ。
環境構築は、[EC-CUBE 4.0 開発者向けドキュメント](https://doc4.ec-cube.net/)の通り進めれば簡単に終わる。

# 目次
EC-CUBE4 独自プラグイン開発　①環境構築手順　(本記事)
[EC-CUBE4 独自プラグイン開発　②独自プラグイン開発Tips](https://qiita.com/haruna-nagayoshi/items/27108c75eaf9511f3524)
[EC-CUBE4 独自プラグイン開発　③今後も使えそうなTips](https://qiita.com/haruna-nagayoshi/items/3527ee12c552a339bc6b)

~~3本立てで書く予定。~~
書きました。

# 動作確認環境
```
Windows10 Pro
PHPStorm 2019.3.3
Docker Desktop 2.1.0.5
Docker 19.03.5
EC-CUBE 4.0.3
Symfony 3.4
PHP 7.3
MySQL 5.7
```
Postgresを使用する場合はMySQLと置き換えてください。



# 環境構築手順

## Docker Desktop for Windows/Mac をインストール
既にDockerが使える状態にある場合は次のステップへ。
[Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows)

## git configがglobalで `core.autocrlf=input` になっていることを確認する
既に設定されている場合は次のステップへ。
※他のプロジェクトに影響させたくない場合は、次のステップ「EC-CUBE本体をgit clone」でcloneするときだけglobalの設定を変更し、cloneが終わったら元に戻す。
[gitconfig の基本を理解する](https://qiita.com/shionit/items/fb4a1a30538f8d335b35)



**理由：**

- `core.autocrlf=true`の状態でEC-CUBE本体をcloneすると、LF -> CRLF に変換されることによって次のエラーが発生するため。
     [EC-CUBE4のコマンド叩いたら謎のエラーが出てきた（/usr/bin/env: 'php\r': No such file or directory ）](https://qiita.com/yusukeito58/items/7c4e28021ee8b0326a81)

- ファイルの改行コードをLFで統一するため。混在していると、文字化けなどバグの原因になることがある。
  1年目か2年目にこの記事を読んで以来、globalの設定はずっと`core.autocrlf=input`にしている。
  [気をつけて！Git for Windowsにおける改行コード](https://qiita.com/uggds/items/00a1974ec4f115616580)



## EC-CUBE本体をgit clone
```
// 任意のディレクトリにcloneする
cd xxx
git clone https://github.com/EC-CUBE/ec-cube.git
```

## .envをコピー

```
cd ec-cube
cp .env.dist .env
```

## .envの内容を書き換える
Mysql、メールデバッグ用サーバを使うため。

```
# DATABASE_URL=sqlite:///var/eccube.db
DATABASE_URL=mysql://dbuser:secret@mysql/eccubedb
# MAILER_URL=null://localhost
MAILER_URL=smtp://mailcatcher:1025

# 開発者間で暗号処理を統一したい場合は、この値を統一する。テストデータに含まれる暗号化したパスワードなどを共用できる。
ECCUBE_AUTH_MAGIC=xxxxx
```

## docker-compose.ymlを書き換える
①PhpStormのコード補完機能を有効にするため、vender配下をホスト・コンテナ間で同期させる。
(ちなみにvar配下を同期させるとlocalでlogファイルが閲覧できる。しかし、logに吐かれる内容が非常にわかりづらく、ほぼ活用しなかった。また、ホスト・コンテナ間の同期が増えればその分動作が重くなると考え、最終的には同期するのをやめた。)

下記に示す通り、計3行をコメントアウト、または削除する。
docker-compose.yml 15行目～39行目付近 Before

```
  ### ignore folder volume #####
  var:
    driver: local
  vender:    ★この行を消す★
    driver: local　　★この行を消す★

services:
  ### ECCube4 ##################################
  ec-cube:
    build: 
      context: .
      args:
        # ビルド時のECCubeインストールスクリプトをスキップする場合にtrueを指定する。
        # ビルド時点でDBサーバの起動や接続が出来ない、という場合等にエラーとなるため。
        SKIP_INSTALL_SCRIPT_ON_DOCKER_BUILD: "true"
    ports:
      - 8080:80
      - 4430:443
    volumes:
      - ".:/var/www/html:cached"
      ### 同期対象からコストの重いフォルダを除外 #####################
      - "var:/var/www/html/var"
      - "vender:/var/www/html/vendor"　★この行を消す★
    networks: 
      - backend
```

docker-compose.yml 15行目～39行目付近 After

```
  ### ignore folder volume #####
  var:
    driver: local
　　　　★消した！★
services:
  ### ECCube4 ##################################
  ec-cube:
    build: 
      context: .
      args:
        # ビルド時のECCubeインストールスクリプトをスキップする場合にtrueを指定する。
        # ビルド時点でDBサーバの起動や接続が出来ない、という場合等にエラーとなるため。
        SKIP_INSTALL_SCRIPT_ON_DOCKER_BUILD: "true"
    ports:
      - 8080:80
      - 4430:443
    volumes:
      - ".:/var/www/html:cached"
      ### 同期対象からコストの重いフォルダを除外 #####################
      - "var:/var/www/html/var"
      　　　★消した！★
    networks: 
      - backend
```



②Postgresコンテナは利用しないので、次のコードをコメントアウトまたは削除する

```
  ### Postgres ################################
  postgres:
    image: postgres:10
    environment:
      - POSTGRES_DB=eccubedb
      - POSTGRES_USER=dbuser
      - POSTGRES_PASSWORD=secret
    ports:
      - 15432:5432
    volumes:
      - pg-database:/var/lib/postgresql/data
    networks: 
      - backend
```



## Dockerコンテナを起動

```
// docker-compose.ymlが存在するディレクトリに移動
cd xxx/ec-cube

docker-compose up -d --build
```



## composer install

```
docker-compose exec ec-cube composer install
```



## インストールスクリプトを実行する

**注意**：このスクリプトを実行すると、データやプラグインがすべて初期化される。初回は気にしなくてOKだが、誤って実行して初期化しないように。

```
docker-compose exec ec-cube bin/console eccube:install
```



Installer Wizard が立ち上がるので、画面に従ってインストールを実行する。
既に.envを書き換えてあるので、Enter連打して全部OKするだけ。
↓こんな感じのログが出る

```
$ docker-compose exec ec-cube bin/console eccube:install

EC-CUBE Installer Interactive Wizard
====================================

 If you prefer to not use this interactive wizard, define the environment valiables as follows:

  $ export APP_ENV=dev
  $ export APP_DEBUG=1
  $ export DATABASE_URL=database_url
  $ export DATABASE_SERVER_VERSION=server_version
  $ export MAILER_URL=mailer_url
  $ export ECCUBE_AUTH_MAGIC=auth_magic
  ... and more
  $ php bin/console eccube:install --no-interaction


 Database Url [mysql://dbuser:secret@mysql/eccubedb]:
 >

 Mailer Url [smtp://mailcatcher:1025]:
 >

 Auth Magic [xxxxxx]:
 >

 !                                                                                                                      
 ! [CAUTION] Execute the installation process. All data is initialized.                                                 
 !                                                                                                                      

 Is it OK? (yes/no) [yes]:
 >

 Run doctrine:database:create --if-not-exists...
 Database `eccubedb` for connection named default already exists. Skipped.

 Run doctrine:schema:drop --force...

 Dropping database schema...

 [OK] Database schema dropped successfully!


 Run doctrine:schema:create...

 ! [CAUTION] This operation should not be executed in a production environment!

 Creating database schema...

 [OK] Database schema created successfully!


 Run eccube:fixtures:load...
   > Finished Successful!

 Run cache:clear --no-warmup...

 // Clearing the cache for the dev environment with debug
 // true

 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.


                                                                                                                        
 [OK] EC-CUBE installation successful.   
```



これでlocal環境でEC-CUBE標準サイトが見れる状態になったことを確認する。
フロント側  http://localhost:8080/
管理画面  http://localhost:8080/admin

```
デフォルトのID/PW　公式サイトのデモサイトと同じ。
ID: admin
PW: password
```

メールデバッグ用SMTPサーバ  http://localhost:1080/


次回以降は、次のコマンドでDockerコンテナを起動/終了する。
※EC-CUBEに限らず、PCシャットダウン時にコンテナを終了しておかないと時々Dockerがバグるので注意。毎日終了する。

```
docker-compose up -d
docker-compose down
```


ここまでは、localにEC-CUBE標準サイトが動作する環境を作る手順。
ここから先は、開発するプラグインをEC-CUBEに反映する手順。


## 開発するプラグイン用のリポジトリをcloneする
予め、開発する開発するプラグイン用のリポジトリを作っておく。

```
cd xxx/ec-cube/app/Plugin

// 任意のディレクトリ名を指定する。 app/Plugin/SamplePluginというディレクトリ構成になる
git clone https://github.com/xxx/sample_plugin.git ./SamplePlugin
```

## プラグインジェネレータでプラグインの骨組みを自動生成

```
docker-compose exec ec-cube bin/console eccube:plugin:generate
```

Consoleに答えてEnterで進む。
プラグインには、nameとcodeを設定できる。
nameは、プラグイン一覧ページで表示されるプラグインの名称。日本語も可らしい。

codeは、コマンドを叩くとき、またはプラグインストアで利用される一意の文字列。命名規則は[a-zA-z_]で、数字は使えない。
(市場に出回っているプラグインのなかで一意だと思われる。自分たちでしか使わないような独自プラグインの場合は、導入したい市場のプラグインと重複しなければなんでもOK)
このcodeは、コマンドを叩くときに使用するため、短く覚えやすい文字列のほうがよい。

```
$ docker-compose exec ec-cube bin/console eccube:plugin:generate

EC-CUBE Plugin Generator Interactive Wizard
===========================================

 name [EC-CUBE Sample Plugin]:
 > SamplePluginName

 code [Sample]:
 > SamplePluginCode

 ver [1.0.0]:
 >                                            
 
 [OK] Plugin was successfully created: SamplePluginName SamplePluginCode 1.0.0
```


これで準備が整った。
骨組みを作った時点でgit pushすれば、他の開発者にも共有できる。
他の開発者がこのプラグインをlocalのEC-CUBEにインストールするには、app/Plugin配下にgit cloneして次の項 `開発の流れ(大まかに)` の `プラグインをインストール` をすればOK


## 開発の流れ(大まかに)
- コードを書く。
- プラグインをインストール

```
docker-compose exec ec-cube bin/console eccube:plugin:install --code=Sample
```

すると、こういう感じのログが出てインストールが完了する。(デバッグモード)
コードにタイポがあったりすると、途中で止まってエラーを吐き出してくれる。

```
$ docker-compose exec ec-cube bin/console eccube:plugin:install --code=Sample
gen -> /tmp/proxy_VLW2B0Y0vtbO/src/Eccube/Entity/Product.php

 // Clearing the cache for the dev environment with debug true
                      
 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.
 
 [OK] Installed. 
```

- プラグインを有効化する。

```
docker-compose exec ec-cube bin/console eccube:plugin:enable --code=Sample
```

こういうログが出て、正常に有効化すればOK。

```
$ docker-compose exec ec-cube bin/console eccube:plugin:enable --code=Sample
gen -> /var/www/html/app/proxy/entity/src/Eccube/Entity/Product.php

 // Clearing the cache for the dev environment with debug true
                                           
 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.           
 
 [OK] Plugin Enabled.
```

- 管理画面/フロント画面で動作確認する。エラーが出ていれば修正する。
- 適宜commit,pushする。


## (必要なら)外部プラグインを開発環境で有効にする

**初回のみ**

[プラグインを探す](http://localhost:8080/admin/store/plugin/api/search)より、外部プラグインを導入する。
ソースコードを落とす必要があるため、初回は認証コードを発行して画面上でプラグインをインストールする。また、ソースを落としてこないとプラグインのコードが分からず、コマンドを叩けない。(プラグインのコードはcomposer.jsonに記述してある)

※codeが判明しているなら、eccube:plugin:installコマンドでも初回ソースDLは可能かもしれない。
e:p:iコマンドを叩いてかなり待ったが処理が進まない、ということがあったため画面上からインストールするようにしているが、e:p:iコマンドが完了するまで待てば正常にソースDLできたのかも・・・。


**初回以降**
ソースを落とすことができたら、以降は下記コマンドでインストール、有効化を行う。

```
// プラグインをインストール
docker-compose exec ec-cube bin/console eccube:plugin:install --code={code}

// インストール後、プラグインを有効化
docker-compose exec ec-cube bin/console eccube:plugin:enable --code={code}
```

または、ec-cubeコンテナに入ってから

```
// プラグインをインストール
./bin/console eccube:plugin:install --code={code}

// インストール後、プラグインを有効化
./bin/console eccube:plugin:enable --code={code}
```

# xdebugでデバックする
[PhpStormとXdebugでステップ実行 ①ステップ実行するための設定](https://qiita.com/haruna-nagayoshi/items/99fa041e884c2c3975d2)
以前にLaravel + Dockerの環境でxdebugを導入したときと同じ手順で、EC-CUBE4(symfony) + Dockerの環境でxdebugを有効化できた。

xdebugはソースを深追いしたいときにとても便利で楽しいけど、EC-CUBEではレンタルサーバなど環境によっては利用できないことがあるらしい。

- [ロリポップでEC-CUBE4のプラグインをインストールできない問題](https://tab-log.com/eccube-plugin#xdebug)  

- [プラグインのインストール時、システムエラーが発生するがログに何も表示されない](https://github.com/EC-CUBE/ec-cube/issues/3990)  
>レンタルサーバなど、制限が強いサーバで発生しやすく、これまで経験したケースとしては、以下のいずれか(または複数)の要因で発生していました。
・xdebugが有効になっている -> xdebugを無効にして解消
・memory_limitが128M -> memory_limitを512Mにして解消
・max_execution_timeが30 -> max_execution_timeを180にして解消
・composer.json/composer.lockに書き込み権限がない -> 書き込み権限を与える

localで使う分には問題ない・・・と思う。
~~開発していて「xdebug使いたい」という場面があまりなく、自分のlocal環境でxdebug有効時にプラグインインストールができなくなるかどうかは未検証。~~
~~判明したら更新する。~~

[2020/04/14 追記]
xdebug有効時にプラグインインストールができなくなる事象を確認しました。インストールするときだけ無効化すればよいでしょう。
[EC-CUBE4 独自プラグイン開発　②独自プラグイン開発Tips](https://qiita.com/haruna-nagayoshi/items/27108c75eaf9511f3524#xdebugを有効にしていると市場のプラグインをインストールできない)にも記述しました。

# リンク集

EC-CUBE4で開発するなら一度は目を通したほうがよいサイト集。実装に慣れるまではしょっちゅう閲覧していたのでブックマークしている。

* [EC-CUBE 4.0 開発者向けドキュメント](https://doc4.ec-cube.net/)
* [EC-CUBE 4 Style Guide](https://eccube4-styleguide.herokuapp.com/#/) 開発者向けドキュメントからアクセスできる。フロントのCSSで匙を投げる前に読んでみてください。
* [EC-CUBE 4の決済プラグインサンプル](https://github.com/EC-CUBE/sample-payment-plugin)
* [4.0(旧3.n)ドキュメント化に向けた情報や実装の参考にしたい情報](https://github.com/EC-CUBE/ec-cube/issues/3380)
* [EC-CUBE4 デモサイト](https://site4.ec-cube.net/admin/)　プラグインで拡張しまくると標準の状態を忘れるので確認用に使った。

以下は、問題を抱えて困ったときにときどき検索に引っかかって、問題解決につながることがあった。

- [あずみ.net](https://a-zumi.net/)
- [U-Mebius ECCUBE制作 EC-CUBE4](https://umebius.com/eccube/category/ec-cube4/)

# 次
[EC-CUBE4 独自プラグイン開発　②独自プラグイン開発Tips](https://qiita.com/haruna-nagayoshi/items/27108c75eaf9511f3524)