EC-CUBEのバージョンアップを見据えたカスタマイズ方法2020年度版

この記事は[Git を使って EC-CUBE を簡単アップデート](https://qiita.com/nanasess/items/fe2a93ff64833d87eb19)の2020年度版です。

EC-CUBE はバージョンアップが大変なことで有名?でしたが、 4系になって **[EC-CUBEアップデートプラグイン](https://www.ec-cube.net/products/detail.php?product_id=2125)** が用意されるなど、徐々に改善されてきています。

しかし、本体のコードをカスタマイズしてしまうと、バージョンアップ時に上書きすることもできず、アップデートプラグインでもエラーが表示され、バージョンアップの難易度が格段に上ってしまいます。
「プラグインや Customize ディレクトリでカスタマイズしろよ」 ってことでしょうが、何でもかんでもプラグインや Customize ディレクトリで頑張ろうとすると、開発・保守コストも上がってしまいます。
高度なプログラミングスキルも求められるため、なかなか簡単にはいきません。

EC-CUBE4系の場合、カスタマイズ方法は大きく分けて3種類あります。

1. Customize ディレクトリでカスタマイズ
2. プラグインでカスタマイズ
3. 本体のファイルを上書き

この中で、1 の Customize ディレクトリは EC-CUBE4系から用意された方法です。
2系や3系では 2 or 3 の2択となります。

ここで、本当にプラグインにする必要があるのか？ Customize ディレクトリを使う必要があるのか？ 今一度考えてみましょう。

- 別の案件などで再利用したい。オーナーズストアで販売したい
- アンインストール機能が必要
- Git でソースコードのバージョン管理ができない
- ec-cube.co を使っている

クラウド版である [ec-cube.co](https://www.ec-cube.net/product/co/) は、カスタマイズ可能な箇所が限られているため、必然的にプラグインでカスタマイズすることになります。

バージョンアップ楽になるからプラグインで... と、よく言われるのですが **それは大きな間違いです。**

プラグインを使ってカスタマイズしても、本体がバージョンアップした時に、処理が干渉すれば影響を受けます。
干渉しているかどうかは、テストで動かすまでわかりません。
干渉しているかどうか、差分を取るのも苦労します。

プラグインや Customize ディレクトリは実装が複雑化しやすく、脆弱性を生みやすい懸念もあります。
実装上の依存関係がわかりづらいため、引き継ぎをした場合に後任者が大変な思いをすることも。。。

また、すべてのカスタマイズを Customize ディレクトリやプラグインでできるわけではありません。
規模が大きくなると必然的に本体のカスタマイズも必要になってきます。

**Git でしっかりバージョン管理しつつ、本体ファイルを上書きするのがカスタマイズの開発効率も、バージョンアップも楽で開発効率のバランスが取れています。(当社比)**

開発工数自体は本体をカスタマイズした方が圧倒的に少ないです。
また、バージョンアップも Git を使用した方が安全・確実です。

影響のあるところはコンフリクトするので、バージョンアップ時のテストも楽です。 git diff で差分の一発でわかります。
[hub](https://dev.classmethod.jp/articles/hub/) コマンドを使えば、脆弱性パッチもコマンド一つで当てられます。

```shell
# Pull Request #4575 を取り込む
hub merge https://github.com/EC-CUBE/ec-cube/pull/4575
```

*3系、4系でデザイン管理画面からテンプレートを編集すると app/template 以下にファイルがコピーされます。アップデートプラグインを使用していても、手動で差分を確認する必要が出てきます。このため、テンプレートを Git で管理することが難しくなりますので注意しましょう*

それでも本体はさわりたくないという人は否定しませんが、 Git でバージョンアップする手順を見ていきましょう。

この方法は 2系、3系でも利用可能です。
ただし、すべての状況において万能なアップデート方法ではありませんので、自己責任でお願い致します。

また、汎用的にするため、すべてコマンドラインで記載していますが、 [SourceTree](https://ja.atlassian.com/software/sourcetree/overview) などの GUI ツールを使っても大丈夫です。



### 1. github から EC-CUBE のソースコードを clone します

- `<eccube version>` には、使用したい EC-CUBE のバージョン(例: 4.0.4)
- `<folder name>` には、宛先のフォルダ名を入力してください


```EC-CUBE4.x
git clone https://github.com/EC-CUBE/ec-cube.git -b <eccube version> <folder name>
```

```EC-CUBE3.x
git clone https://github.com/EC-CUBE/ec-cube3.git -b <eccube version> <folder name>
```

```EC-CUBE2.x
git clone https://github.com/EC-CUBE/eccube2.git -b <eccube version> <folder name>
# 2系の場合はバージョンの前に eccube- を付与してください
# 例) eccube-2.4.4
```

### 2. 管理用のブランチを作成

`<new-branch-name>` には、ソースコードを管理するためのブランチ名(例: production) を入力します

```sh
cd <folder name>
git checkout -b <new-branch-name>
```

これで、カスタマイズしたソースコードを管理するための準備が整いました。
本番環境などからソースコードを取得し、 `<folder name>` に上書きしてください。


### 3. 差分の確認

カスタマイズしたソースコードと、 EC-CUBE 本体のソースコードに差分が発生しているかを `git status` コマンドで確認します。

```sh
git status

On branch production
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   src/Eccube/Repository/OrderRepository.php

no changes added to commit (use "git add" and/or "git commit -a")
```

`src/Eccube/Repository/OrderRepository.php` に修正が入っていることがわかります。

どのような内容の修正か、 `git diff` コマンドで見てみましょう。


```diff

git diff

diff --git a/src/Eccube/Repository/OrderRepository.php b/src/Eccube/Repository/OrderRepository.php
index f80ee50e8d..d41217427c 100644
--- a/src/Eccube/Repository/OrderRepository.php
+++ b/src/Eccube/Repository/OrderRepository.php
@@ -113,7 +113,7 @@ class OrderRepository extends AbstractRepository
             $qb
                 ->andWhere('o.id = :multi OR o.name01 LIKE :likemulti OR o.name02 LIKE :likemulti OR '.
                             'o.kana01 LIKE :likemulti OR o.kana02 LIKE :likemulti OR o.company_name LIKE :likemulti OR '.
-                            'o.order_no LIKE :likemulti OR o.email LIKE :likemulti OR o.phone_number LIKE :likemulti')
+                            'o.order_no LIKE :likemulti OR o.email LIKE :likemulti OR o.phone_number LIKE :likemulti OR o.message LIKE :likemulti')
                 ->setParameter('multi', $multi)
                 ->setParameter('likemulti', '%'.$searchData['multi'].'%');
         }
```

受注管理画面の検索条件に、お問い合わせ内容が追加されています。

### 4. 修正内容の保存

この修正内容を、 `git add` と `git commit` コマンドで保存しておきましょう。

```sh
git add .
```

```sh
git commit -m 'save production'

[production 37fb0e7] save production
 1 file changed, 1 insertion(+), 1 deletion(-)
```

`git add .` では、最後に「.(ドット)」を入れるのを忘れないようにしてください。
`git commit` の `-m` には、任意のコミットログを記録できます。どんな修正なのか書いておくと、後々役立ちます。

こうして日々の修正をコミットしておくと、差分の確認ができたり、万が一修正ミスが発生した時でも、安心して元に戻すことができます。

### 5. バージョンアップ

EC-CUBE の新バージョンがリリースされましたので、バージョンアップしましょう。

`git fetch origin <eccube version>` コマンドで、最新のソースを取得できます。
ここでは 4.0.5 のソースを取得します。バージョン番号は適宜読み替えてください。

```sh
git fetch origin 4.0.5

From https://github.com/EC-CUBE/ec-cube
 * tag               4.0.5      -> FETCH_HEAD
```

この時、 `git pull` は使用しないのがコツです。 `git pull` を使用すると、予期せぬ更新が反映されてしまう場合があります。

取得した差分を適用(merge)しましょう。

```sh
git merge 4.0.5

Updating 8710496..2d2b958
Fast-forward
 .gitignore                                         |    2 +-
 .gitmodules                                        |    2 +-
 .travis.yml                                        |    9 +-
 README.md                                          |   19 +-
 app/console                                        |    1 -
 appveyor.yml                                       |   11 +-
 composer.json                                      |    7 +-
 composer.lock                                      |  912 +++++++++++-------
 docs
...snip
```

大量にログが出力されますが、落ち着きましょう。
もう一度、 `git status` で正常に適用されたか確認しましょう。
改修した本体のソースコードが上書きされていないことも確認しましょう。

```sh
git status

On branch production
nothing to commit, working directory clean
```

*nothing to commit, working directory clean* と出ていれば、大丈夫です。

`composer.json` や `composer.lock` が変更されていた場合は、 以下のコマンドで vender を更新しましょう。

```sh
curl -sS https://getcomposer.org/installer | php
php ./composer.phar selfupdate --1
php ./composer.phar install --dev --no-interaction
```

この後、ソースコードをサーバーへアップロードすればアップグレード完了です。

データベースに変更が入っていた場合は、以下のコマンドでマイグレーションを実行しましょう

```sh
## データベースの更新を確認
bin/console doctrine:schema:update --dump-sql

## 更新がある場合はマイグレーションを実行
bin/console doctrine:schema:update --dump-sql --force
```

### 使用しないファイルの削除

git clone を使用すると、運用では使用しないファイルも取り込まれます。
そのままにしておくと、セキュリティ的によろしくないものも含まれますので削除しておきましょう。

```EC-CUBE4.x
rm .editorconfig
rm .buildpath
rm .php_cs.dist
rm phpunit.xml.dist
rm phpstan.neon.dist
rm app.json
rm Procfile
rm LICENSE.txt
rm README.md
rm codeception.sh
rm codeception.yml
rm -rf codeception
rm -rf tests
rm -rf .github
rm -rf zap
rm docker-compose-owaspzap.yml
```

```EC-CUBE2.x
rm -rf .github
rm .php_cs.dist
rm phpunit.xml.dist
rm phpstan.neon.dist
rm app.json
rm Procfile
rm build.xml
rm README.md
rm codeception.yml
rm php.ini
rm phpinicopy.sh
rm phpinidel.sh
rm *.phar
rm setup.sh
rm setup_heroku.php
rm svn_propset.sh
rm -rf ctests
rm -rf tests
rm -rf templates
rm -rf patches
rm -rf docs
rm -rf html/test
rm -rf dockerbuild
rm -rf Dockerfile
rm -rf docker-compose*.yml
rm -rf zap
find . -name "dummy" -print0 | xargs -0 rm -rf
```

### 番外) 競合(コンフリクト)してしまった時は？

`git merge` の時に、ソースコードの修正が被ってしまい、バージョンアップの適用に失敗する場合があります。

```sh
git merge 4.0.5

Auto-merging src/Eccube/Repository/OrderRepository.php
CONFLICT (content): Merge conflict in src/Eccube/Repository/OrderRepository.php
Removing src/Eccube/Form/Type/ShoppingType.php
Removing src/Eccube/DependencyInjection/Compiler/TemplateListenerPass.php
Removing repos/.gitkeep
Removing html/user_data/.gitkeep
Removing html/template/default/assets/css/maps/style.css.map
Removing html/template/admin/assets/css/maps/bootstrap.css.map
Removing html/template/admin/assets/css/maps/app.css.map
Removing .github/workflows/action.yml
Removing .github/actions/setup-chromedriver/tsconfig.json
Removing .github/actions/setup-chromedriver/src/setup-codeception.ts
Removing .github/actions/setup-chromedriver/package.json
Removing .github/actions/setup-chromedriver/package-lock.json
Removing .github/actions/setup-chromedriver/lib/setup-codeception.sh
Removing .github/actions/setup-chromedriver/lib/setup-codeception.js
Removing .github/actions/setup-chromedriver/jest.config.js
Removing .github/actions/setup-chromedriver/docs/contributors.md
Removing .github/actions/setup-chromedriver/action.yml
Removing .github/actions/setup-chromedriver/__tests__/run.test.ts
Removing .github/actions/setup-chromedriver/README.md
Automatic merge failed; fix conflicts and then commit the result.
```

最後に *Automatic merge failed; fix conflicts and then commit the result.* という行が出たら修正が競合しています。

上記の例では、 `src/Eccube/Repository/OrderRepository.php` が CONFILICT となっています。

`git status` コマンドでも確認できます。

```sh
git status

On branch production
You have unmerged paths.
  (fix conflicts and run "git commit")

Changes to be committed:

	new file:   .devcontainer/devcontainer.json
	modified:   .dockerignore
	new file:   .editorconfig
	modified:   .env.dist
	modified:   .env.install
	new file:   .github/.htaccess

...snip

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:   src/Eccube/Repository/OrderRepository.php
```

最後に `Unmerged paths:` と出ているのが、競合してしまったファイル一覧です。

`src/Eccube/Repository/OrderRepository.php` を開くと、競合した箇所を確認できます。
`<<<<<<<` で検索するとすぐに見つかります。

```php
            $qb
<<<<<<< HEAD
                ->andWhere('o.id = :multi OR o.name01 LIKE :likemulti OR o.name02 LIKE :likemulti OR '.
                            'o.kana01 LIKE :likemulti OR o.kana02 LIKE :likemulti OR o.company_name LIKE :likemulti OR '.
                            'o.order_no LIKE :likemulti OR o.email LIKE :likemulti OR o.phone_number LIKE :likemulti OR o.message LIKE :likemulti')
=======
                ->andWhere('o.id = :multi OR CONCAT(o.name01, o.name02) LIKE :likemulti OR '.
                            'CONCAT(o.kana01, o.kana02) LIKE :likemulti OR o.company_name LIKE :company_name OR '.
                            'o.order_no LIKE :likemulti OR o.email LIKE :likemulti OR o.phone_number LIKE :likemulti')
>>>>>>> 4.0.5
                ->setParameter('multi', $multi)
                ->setParameter('likemulti', '%'.$clean_key_multi.'%')
```

`=======` より上が、アップグレード前のソースコード、下がアップグレード後のソースコードです。
この場合は、上の方を残したいので、下の方を削除して正しいソースコードに修正します。

```php
                ->andWhere('o.id = :multi OR o.name01 LIKE :likemulti OR o.name02 LIKE :likemulti OR '.
                            'o.kana01 LIKE :likemulti OR o.kana02 LIKE :likemulti OR o.company_name LIKE :likemulti OR '.
                            'o.order_no LIKE :likemulti OR o.email LIKE :likemulti OR o.phone_number LIKE :likemulti OR o.message LIKE :likemulti')
```

修正ができたら、コミットしておきましょう。

```sh
git add .
```

```sh
git commit -m 'save production'
[production b6da7e2] save production
```

小々長くなってしまいましたが、こうすることで、本体のソースコードに手を入れても、比較的簡単にアップデートすることができます。
プラグインを使っていても、本体の修正と競合する問題を完全に防ぐことは難しいです。
Git をうまく活用して、開発効率と安定性を両立させましょう。