2019年5月23日木曜日

EC-CUBE4でプラグインからのマイグレーションでEntityManager・Entityを使う方法

SYSTEM_KDです。


今回のブログから、StackEdit を利用してMarkdownで書いてみています。
(いや、何の宣言?


久々の投稿ですが、内容はEC-CUBE4でのマイグレーションについてです。


ほぼメモです。



EC-CUBE4でのプラグインからマイグレーション


EC-CUBE3では、プラグインでテーブルの拡張・データ追加を行う際はPluginMigrationで行いますが、
4系ではテーブルの拡張は「doctrine:schema:update」での拡張が推奨されてます。

(まぁ、プラグインからのテーブル拡張は、プラグイン機構部分が良しなにしてくれるのであまり気にしなくてOK)


データの追加を行う際も、PluginMigrationから行えます。

AbstractPluginManager を継承して enable() 関数にてinsertするなり、$container(ContainerInterface) からEntityManagerを利用するなりしてデータ追加が行えます。


ただ、この方法だと再度 enable()が操作した際にinsertしないようにチェックする必要があります。

プラグインをバージョンアップして、追加するデータが増えた際・既に追加しているデータを変更する際など、管理が面倒くさい。


振り返らずに、前に進みたいです。


ということで、3系と同様にマイグレーションファイルを用意して、追加するデータを管理したいと思います。


必要なファイル
(プラグイン用ディレクトリの中)
  • PluginManager.php
  • DoctrineMigrations/Version2019XXXXXXXXXX.php


    VersionXXXのファイルは、下記コマンドで生成
    (生成できたらプラグインの中に持ってくる)
bin/console doctrine:migrations:generate

PluginManager.php は、Eccube\Plugin\AbstractPluginManagerを継承する。

AbstractPluginManagerにある、migrationメソッドを呼べば3系の時みたいにバージョン管理しながらデータ追加が行える。


有効にした際にデータ追加したい場合
public function enable(array $meta, ContainerInterface $container)  
{  
    $this->migration($meta['code'], $container);
}

逆にアンインストールで削除する場合
public function uninstall(array $meta, ContainerInterface $container)  
{  
    $this->migration($meta['code'], $container, 0);  
}


あとは、マイグレーションファイル内の up() 関数で、`addSql`すれば良い。
※アンインストール時は、down()

(色々とサンプルが転がっているのでざっくりで m(_ _)m


でも、これだとEntityManager使えない。Entityが使えない。。使いたい。。


で、本題のEntityManagerを使ってのマイグレーションです。

マイグレーションファイルで、ContainerAwareInterfaceをimplementsし、
use ContainerAwareTraitを差し込んであげれば、ContainerInterfaceを使えるようになると見せかけて、ならない。

bin/console doctrine:migrations:migrate

で、app/DoctrineMigrations にあるマイグレーションファイルは良い感じになりますが、プラグインの方はダメっぽい。

やり方が悪いだけだったりして・・・^^;


解決方法
Eccube\Plugin\AbstractPluginManagermigration 関数をベースにちょっと書き換えます。

PluginManager .php
class PluginManager extends AbstractPluginManager  
{
 /**  
  * @param array $meta  
  * @param ContainerInterface $container  
  * @throws MigrationException  
  */
 public function uninstall(array $meta, ContainerInterface $container)  
 {  
     $this->pluginMigration($meta, $container, 0);  
 }  
   
 /**  
  * * @param array $meta  
  * @param ContainerInterface $container  
  * @throws MigrationException  
  */
 public function enable(array $meta, ContainerInterface $container)  
 {  
     $this->pluginMigration($meta, $container);  
 }

 protected function pluginMigration(array $meta, ContainerInterface $container, $version = null)  
 {
     $migrationFilePath = __DIR__ . '/DoctrineMigrations';  
     $connection = $container->get('database_connection');  
   
     $pluginCode = $meta['code'];  
   
     $config = new Configuration($connection);  
     $config->setMigrationsNamespace('\Plugin\\' . $pluginCode . '\DoctrineMigrations');  
     $config->setMigrationsDirectory($migrationFilePath);  
     $config->registerMigrationsFromDirectory($migrationFilePath);  
     $config->setMigrationsTableName(self::MIGRATION_TABLE_PREFIX . $pluginCode);  
   
     /** @var Version $objVersion */  
     foreach ($config->getMigrations() as $objVersion) {  
         $versionMigration = $objVersion->getMigration();  

         if ($versionMigration instanceof ContainerAwareInterface) {  
             $versionMigration->setContainer($container);  
         }  
     }
   
     $migration = new Migration($config);  
     $migration->migrate($version, false);  
 }
}

間違え探しみたいな微妙な違いですが、、
キモとなる部分はこの部分になります。

ContainerInterfaceをVersionXXX側に渡してあげるようにします。
/** @var Version $objVersion */  
foreach ($config->getMigrations() as $objVersion) {  
    $versionMigration = $objVersion->getMigration();  

    if ($versionMigration instanceof ContainerAwareInterface) {  
        $versionMigration->setContainer($container);  
    }  
}


これで無事にマイグレーションをバージョン管理しながら、EntityManager・Entityを使うことができます。


final class VersionXXX extends AbstractMigration implements ContainerAwareInterface  
{
    use ContainerAwareTrait;

    public function up(Schema $schema): void  
    {  
        /** @var EntityManagerInterface $entityManager */  
        $entityManager = $this->container->get('doctrine.orm.entity_manager');  
   
        $ProductRepository = $entityManager->getRepository(Product::class);
    }  
   
    public function down(Schema $schema): void  
    {  
   
    }
}


まとめ


bin/console でマイグレーションする場合は、VersionXXXの方だけで良いけど、
EC-CUBE4のプラグインでマイグレーションする際は、PluginMigrationでContainerInterfaceを渡してあげる必要がある。

2019年2月3日日曜日

Azure (App Service) に EC-CUBE 4 をインストール


SYSTEM_KD です。

自分用のEC-CUBE3 デモ環境を Azure に構築していますが、EC-CUBE4系も欲しいなということで、今更ながらEC-CUBE4 のデモ環境を Azureに構築したいと思います。

ちなみに、なぜAzureかというと、「」で「便利」で「安い」からです。

App Service を利用すれば、マネージドな環境なのでサーバの設定を気にすることもなく楽。
SSL証明書も付いてる(もちろん独自ドメインでな無く、そもそもLet’s Encryptを使えば気にしなくても良いというのはありますが・・まぁ環境作ったら付いてるので便利)
安いのは、そのままです。無料で使えます。


App Service 作成


では、環境作成します。

Azure にアクセスして、左側のメニューから App Service を選択します。


image

App Service のページが表示されるので、「+追加」から「Web Apps」を選択します。

作成をクリックして、「アプリ名」に好きな名称(ドメイン名になるので、他の人とかぶるとダメ)を指定。

リソースグループは「新規作成」を選択。(別に既存があるなら既存でも良い。自由に)

OS は「Windows」を選択(Linuxを選ぶと有料)

公開で、「コード」を選択。(Docker イメージは有料)

App Service プラン/選択で、新規作成から、場所は「Japan」で、プランは、「開発/テスト」の「F1」を選択。

image


(しばらく見ないうちに、UIめちゃめちゃ変わっている。。^^; 


「作成」で環境用意完了!!


App Service で先程作成したものを選択して、概要の「URL」をクリックすると、デフォページが表示されるかと思います。


EC-CUBE4 をインストール


環境が作成できましたので、インストール作業をすすめていきます。


ソースコードをアップしたいのですが、FTP経由でアップすると時間がかかるので、Git でアップしたいと思います。


メニューから、「デプロイセンター」を選択して、「Local Git」を選びます。
※ここらへんも前と変わっている・・・。


ひとまず、git clone します。


clone できたら、そこに EC-CUBE4のソースを配置して、コミットして、push します。


※ディレクトリを作成して、その中にソースを置くと Azure 側の「仮想アプリケーションとディレクトリ」の設定を調整する必要があるので、とくにディレクトリは作成せずそのままソースコードを配置


これで配置は完了。


さくっとインストール。


のはずが、微妙に罠がありました。


まず、web.config でエラーが発生してインストールが表示されない。

<add segment=”bin” />

を削除して対応。


ついでに、 git 管理から、 bin ディレクトリを除外。


app/Plugin ディレクトリが空で、git 管理から外れるため、.gitkeep を追加。

同じく、app/Customize/Controller と app/Customize/Entity にも、.gitkeep を追加


終わりと思いきや、まだあります。。

app/template/admin
app/template/default
app/template/user_data
app/proxyentity
app/PluginData
src/Eccube/Resource/doctrine/migration

にも同様に、.gitkeep 追加


再度 push して、インストールにトライ!


重い。。



image


ようやく、インストール画面。


DBは、MySQL In App を使います。


Azureのコンソールで、

D:\home\data\mysql
に移動すると


MYSQLCONNSTR_localdb.txt があるので、表示すると接続情報が書いてますので、DBへの接続情報はそれを利用します。


image


なんとか、インストール完了。


git 経由でアップしたことによって、色々とハマりましたが、4系用の検証環境ができました。


ただ、Azure 無料プランで無理やり動かすのは厳しいようで、最初の表示はかなり時間を必要とします。
(キャッシュが生成されれば、それなりには動きます)


2019年1月15日火曜日

wsl + Docker for Windows でdocker-compose を動作させる際の Volume設定について


SYSTEM_KDです。
年初はブログ更新を頑張るけど、すぐに力尽きます。。^^;

docker-compose.yml の Volume 設定について

前回、環境をCygwinから wsl へ変更したという記事を書きましたが、docker-compose up してみると、volume部分で問題が発生することが判明しました。
ディレクトリは相対パスで指定していたので、問題ないだろうと思っていたのですが甘かったです。

※wsl + Docker for Windows は、tcp://localhost:2375 経由で動かすようにしてます。

具体的には、docker-compose up 自体は成功するのですが、windows側のマウントが行えていない(ディレクトリ空っぽ)状態になっていました。

調べてみると、wsl 側でホストのドライブは 「/mnt/ドライブ」 という感じで、マウントされているために上手くマウントできていない状態とのことでした。

解決策としては、設定ファイルを追加してマウントの場所を変えるということでした。
設定ファイルの追加場所は、
/etc/
で、ファイル名は
wsl.conf
になります。
中身は、
[automount]
enabled = true
root = /
options = "metadata,umask=22,fmask=11"
mountFsTab = false

こんな感じです。
マウントの場所を/mnt から / に変更している状態となります。

設定ができたら、wsl を一旦終了させます。

これで、/c/ とか /d/ とかでアクセスできるようになり、上手くマウントできるようになるかと思います。

wsl-terminal が起動しない

上記でマウント問題が解決させ、wsl を起動させたところ、起動しないという問題発生。

設定ファイル追加を、wsl-terminal 以外から実施していたので気づきませんでしたが、wsl-terminalから実施してたら、終了させた後に起動できなくなるかと思います。

ちょっと焦りました ^^;

おそらく /mnt/ 配下にドライブがマウントされていること前提で動作しているのだろう(勝手な憶測)ということで、他のターミナルとか、コマンドプロンプト経由でubuntuを起動して、ちょろっと変更します。

変更といっても、/mnt/ドライブ から /ドライブ にシンボリックリンクをはるだけです。

ln -s /c /mnt/c

Cドライブだとこんな感じですね。

これで、wsl-terminal も起動できるようになります。

以上、wsl + Docker for Windows でdocker-compose を動作させる際の Volume設定について でした。

2019年1月13日日曜日

Cygwin から WSL にきりかえ。


SYSTEM_KDです。

久々のブログ更新です。


この年末年始は、始めて大腸検査・胃カメラをするなど、毎週病院に通う謎仕様になっておりました。

今は、右耳が難聴という・・・急激に歳をとったのか ^^;
おみくじ大吉だったのになんという年明けだ!!

(皆様もストレスにはお気をつけください m(__)m


と、まぁ色々ありましたので、気分を変えるということで、環境を少しチェンジしてみました。


Cygwin から WSL に切り替え

今までは、UNIX的な操作をする際に、 Cygwin を利用しておりましたが、そろそろ WSL(Windows Subsystem for Linux)を使ってみようかなと思い切り替えてみました。


インストールは簡単で、コントロールパネルから「プラグラムと機能」を選択し、「Windows の機能有効化まとは無効化」から「Windows Subsystem for Linux」のチェックを入れて再起動。

image

image


再起動が完了したら、「Microsoft Store」(スタートボタンをおして、”Store”と入力すれば出てくる)を立ち上げて、検索部分に「ubuntu」と入力すればOK


image


何種類か出てきますが、好きなのを選択(バージョン番号書いていないのがデフォっぽい)

あとは、右上の「入手」ボタンをクリックすれば完了。


インストール後、「起動する」をクリックするとターミナルが起動して、初期処理と「ID・パス」の設定を行います。


wsl-terminal を導入

そのまま利用しても良いのですが、使いにくかったので、wsl-terminal を導入しました。

[ここからゲットできます]
https://github.com/goreliu/wsl-terminal/releases

zip等を展開すると、「open-wsl.exe」がありますので、そのままダブルクリックで起動できます。


微妙に問題発生

特に問題なく使えるように思えたのですが、sudo apt-get update を実行しようと、パスワードがNGになるという現状が発生しました。

再起動して、元のターミナルから実施してみたのですが、現象は変わらず。。


もう1つターミナルを立ち上げて、実行してみると今度は成功しました。


謎現象かと思っておりましが、よく見ると失敗したターミナルは、「Bash on Ubuntu on Windows」となっており、どうやらベータ版のころに入れた(記憶なしw)ものが邪魔をしておりました。

アンインストール方法をググって、

lxrun /uninstall /full 

をコマンドプロンプトから実行して、万事解決しました。


PhpStormのターミナルも変更

PhpStormのターミナルをCygwinにしていたので、こちらも合わせて変更しました。

「File > Setting」より設定を起動して、「Tools > Terminal」を選択。

「Shell path」に「C:\Windows\System32\wsl.exe」を設定して完了。


PhpStormを再起動するか、Terminalのタブを全て閉じてあげれば、wsl を利用できます。



以上、1年ぶりぐらいのブログ更新。「Cygwin から WSL に切り替え」でした。

2018年2月17日土曜日

Docker For Mac で Kubernetes を試してEC-CUBEを動かしてみる(その4)

SYSTEM_KDです。

その1、その2、その3 とやってきて、ようやくEC-CUBEをインストールするところにたどりつきました。


Kubernetes な環境に EC-CUBE3 をインストール


インストールに利用する EC-CUBEは 3.0.15 になります。


ここからは楽勝ですね。

いままで作ってきたものを全て起動させた状態にします。


WEBサーバー側で、マウントしているホストのディレクトリに、EC-CUBE3 のソースを配置します。

そして、ポート指定して localhostにアクセスすれば、ようこそページが表示されました。




流れにそって進んでいきます。


EC-CUBEをインストールするには、事前にDBを作成しておく必要があるので、GUI等にてアクセスを行って、事前に作成しておきます。


接続情報の設定



データベースの種類で、 MySQLを選択

データベースのホスト名に、mysql-server を設定

データベース名は、事前に作成したもの

ユーザ名は root

パスワードは 「その2」の先に作成したものです。


・・・ インストール中 ・・・





無事インストールできました!!


PODを増やして 複数台っぽくしてみる


EC-CUBE3のインストールに成功しましたので、Kubernetes っぽく PODの数を増やしてみたいと思います。


apiVersion: apps/v1
kind: Deployment
metadata:
  name: mycentos7
  labels:
    app: mycentos7
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mycentos7
  template:
    metadata:
      labels:
        app: mycentos7
    spec:
      containers:
      - name: mycentos7
        image: localhost:5000/web/mycentos7:2
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /var/www
          name: docroot
      volumes:
      - name: docroot
        persistentVolumeClaim:
          claimName: centos7-volume-claims

replicas を 指定してあげることにより、PODを増やすことができます。

デプロイします。

kubectl apply -f centos7.yml

確認してみます。

NAME                            READY     STATUS    RESTARTS   AGE
mycentos7-884464574-m5952       1/1       Running   0          58s
mycentos7-884464574-qb99x       1/1       Running   0          14h
mysql-server-5b9788cc57-2wvmq   1/1       Running   0          18h


増えました。

どっちの POD も Volume が共通で、ホストのものをみているので、複数台状態でも一応動きました。

(※EC-CUBEは複数台構成で動くことが想定されていません)


速度てきな問題への対応


ここまで動かしてみると重大な問題があることがわかりました。


それは、動作が遅いということです。

Docker For Mac でホスト側をマウントして普通に動かした場合も同様に遅いので、ある程度は想定しておりましたが、やはり遅いみたいです。


ぱっと思いつく問題点は、Volume 周りかなと思いますので、確認していみたいと思います。


Docker Image にパックしてみる

ソースコード全体についてホスト側をマウントしているようにしていましたが、イメージ内にパックしてみます


完全に全体をイメージに入れてしまうと、ログとかキャッシュ用にファイルを作成する部分がエラーになるので、app の配下だけはホスト側のディレクトリをマウントするようにしました。

結果は、

ソースコード全体をマウントした場合
TOP画面 ・・・ 平均 5.15秒
商品一覧 ・・・ 平均 4.86秒

一部のみマウントした状態
TOP画面 ・・・ 平均 1.34秒
商品一覧 ・・・ 平均 1.04秒


早くなりました!


ファイルが分かれて個別に作成するのが面倒な問題に対応


設定ファイルを個別に作成してきましたが、個別に create するのが面倒になってきましたので、1ファイルにまとめたいと思います。

と言ってもまとめるのは簡単です。

それぞれの設定ファイルを一箇所に集めて、「---」で区切るだけです。

(ついでに全体、ソースをはる)


# Volume
apiVersion: v1
kind: PersistentVolume
metadata:
  name: centos7-volume
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: centos7-storage
  hostPath:
    path: /ホスト側フルパス

---
# Volume Caims
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: centos7-volume-claims
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: centos7-storage

---
# deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mycentos7
  labels:
    app: mycentos7
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mycentos7
  template:
    metadata:
      labels:
        app: mycentos7
    spec:
      containers:
      - name: mycentos7
        image: localhost:5000/web/mycentos7:3
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /var/www/app
          name: docroot
      volumes:
      - name: docroot
        persistentVolumeClaim:
          claimName: centos7-volume-claims

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: mycentos7
  labels:
    app: mycentos7
spec:
  ports:
    - port: 80
      nodePort: 31000
  selector:
    app: mycentos7
  type: NodePort


毎回アクセスするポートが変わるのも面倒だったので、こっそり固定にしてます。
ついでに、MySQLの方もはっておきます

# Secret
apiVersion: v1
kind: Secret
metadata:
  name: mysql-pass
type: Opaque
data:
  password: XXXXX # echo -n "pass" | base64  # base64した値を設定

---
# Volume
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-volume
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: mysql-storage
  hostPath:
    path: /ホスト側のフルパス

---
# Volume Claims
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-volume-claims
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: mysql-storage

---
# Deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-server
  labels:
    app: mysql-server
spec:
  selector:
    matchLabels:
      app: mysql-server
  template:
    metadata:
      labels:
        app: mysql-server
    spec:
      containers:
      - name: mysql-server
        image: mysql:5.6
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-storage
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-volume-claims

---
# Service 外部用
apiVersion: v1
kind: Service
metadata:
  name: mysql-server-open
  labels:
    app: mysql-server
spec:
  ports:
    - port: 3306
      nodePort: 31001
  selector:
    app: mysql-server 
  type: NodePort

---
#Service 内部用
apiVersion: v1
kind: Service
metadata:
  name: mysql-server
  labels:
    app: mysql-server
spec:
  ports:
    - port: 3306
  selector:
    app: mysql-server
  clusterIP: None


Secret 部分のパスワードは、パスワードをbase64した値を設定します。

ということで、 Docker For Mac で Kubernetesを試しながらEC-CUBEをインストールするところまでできました。


よくわからないまま進んできましたが、Kubernetes の情報がのっているページ(GKEのドキュメントとか)の内容がなんとなく理解できるようになったのは収穫だったかなとおもっています。


その4は切りが悪いので、その5を書こうかなと思いつつ、以上、Docker For Mac で Kubernetes を試してEC-CUBEを動かしてみる(その4)でした。