CakePHP3のmigrationsシェルに一括オプション追加

CakePHP3のmigrationsシェルに一括オプションを追加

CakePHP3のCake Shell migrations を拡張した話です。
それは、migrationsbulkオプションを追加して
複数のDatasourceに対するスキマを操作する内容です。

普通にDatasourceに一括操作の対象になるデータベースを全て設定し、
--connectionのオプションでmigrationsのSHELLコマンドをただいても
良いですが、私が管理しているアーキテクチャーは👇の通りでしたので
既にDatasourceの項目を設定して置くのは出来ませんでした。
f:id:ldhdba:20171012171047p:plain

分かりにくいかも知れないので、端的に説明させて頂きますと
実際のアプリのソースコードは一つで、ctrl_appというアプリ管理システムで
顧客向けのアプリケーションを発行・削除・管理をしたりしています。
もちろん以下の物も裏側で自動に生成されたりします。
- 各アプリケーションのDB
- 各アプリケーションのシンボリックリンク
- 各アプリケーションのcronファイル
- などなど

こんな構成にした理由は、もちろんすべてのアプリケーションのコード一貫性を守るためです。 Cacheなどを上手く管理するとCakePHP Frameworkのプロジェクトも普通に実装できました。
※ 少し記事のテマの話とずれてしまいますので、詳しい環境説明は省略します。

また、上端の画嬢で紹介している通り、このプロジェクトには
デプロイツール、Capistrano を利用しています。
で、やりたかったのが、Capistranoで共通のアプリソースコードをデプロイして
それぞれのデータベースのスキマも一括で操作したかったことです。

もちろんMgrationsShellを拡張する選択肢以外にも色々ありますが、
とにかく!やっちゃいました。

まず、普通のMigrationsShellの動きは以下のようになりますね。
Datasourcedefault設定に対するDBスキマを操作しています。
--connection オプションを利用するとdefault以外のキーむ可能です。
f:id:ldhdba:20171012171345p:plain

そして、改修してからはー
f:id:ldhdba:20171012171401p:plain

その後、オプションではなく、別途のSHELLコマンドとしてあった方が良さそうだったので−
f:id:ldhdba:20171012171430p:plain

これでCapistranoで共通のコードをデプロイした後、 各DBスキマ更新も楽になりました。

以下はMigrationsShellを拡張したクラスでございます。

<?php

namespace App\Shell;

use Migrations\Shell\MigrationsShell as CakeMigrationsShell;
use Migrations\MigrationsDispatcher;
use Symfony\Component\Console\Input\ArgvInput;
use Cake\Datasource\ConnectionManager;

class AppDeployMigrationsShell extends CakeMigrationsShell
{
    /**
     * main
     * \Migrations\Shell\MigrationsShell override method
     * デフォルトでctrl_appに登録されている全てのアカウント(db)を一括操作する.
     *
     * @author lee
     *
     * @return bool Success of the call
     */
    public function main()
    {
        if ($this->argv[1] == 'dump') {
            $exitCode = parent::main();
        } else {
            // ⭐最初こちらに来て、migrations SHELLコマンドに dump -cオプションを付ける⭐
            $connectedDbs = $this->connectAccountsDatasource();
            foreach ($connectedDbs as $name) {
                $argv = ['migrations', $this->argv[1], '-c', $name];
                $app = new MigrationsDispatcher(PHINX_VERSION);
                $input = new ArgvInput($argv);
                $app->setAutoExit(false);
                $exitCode = $app->run($input);
                $dispatchCommand = 'migrations dump';
                $dispatchCommand .= ' -c '.$name;
                $dumpExitCode = $this->dispatchShell($dispatchCommand);
            }
        }
        if (isset($dumpExitCode) && $exitCode === 0 && $dumpExitCode !== 0) {
            $exitCode = 1;
        }

        return $exitCode === 0;
    }

    /**
     * connectAccountsDatasource
     * ctrl_appのapiで登録アカウント(db)を受け取り、全てconfigする.
     *
     * @author lee
     *
     * @return array
     */
    private function connectAccountsDatasource()
    {
        $defaultConnectInfo = ConnectionManager::get('default');
        $defaultResourceInfo = $defaultConnectInfo->config();
        $accounts = \App\Statics\Api::getAttachCode();
        $connectedDbs = [];
        foreach ($accounts as $name) {
            $migrateResourceInfo = $defaultResourceInfo;
            $migrateResourceInfo['database'] = $name;
            // config infoをgetしたやつをsetする場合、以下の情報が抜けているので追加する
            $migrateResourceInfo['className'] = 'Cake\Database\Connection';
            $connectedDbs[] = $name;
            if (!empty(ConnectionManager::config($name))) {
                continue;
            }
            ConnectionManager::config($name, $migrateResourceInfo);
        }

        return $connectedDbs;
    }
}

以上、CakePHP3のCake Shell migrations を拡張した話でした。