2015年から CakePHP2.xをベースに、あるパッケージソフトウェアを開発しているのだが、実際にお客さんに提供する際、機能やデザインの一部をカスタマイズして提供することが多い。
しかしパッケージ本体のソースコードに手を入れてしまうと、後々パッケージをバージョンアップした際に、マージするのが非常に煩雑になる。WordPress のプラグインように、CakePHP のプラグイン機能を使って拡張する方法も検討してみたが、制約が多く、なかなか思うようにはいかない。そこで CakePHP のクラスパスを利用し、ソースの読み込み順を制御することによって、パッケージ本体とカスタム領域を分離することを試みた。
具体的には、CakePHP の構成設定ファイル、Config/bootstrap.php に以下のような設定を行った。
// カスタマイズ用ディレクトリの登録(このディレクトリに格納されたソースを優先して読み込む)
App::build(
array(
'Model' => array(APP.'Custom'.DS.'Model'.DS),
'Model/Behavior' => array(APP.'Custom'.DS.'Model'.DS.'Behavior'.DS),
'Model/Datasource' => array(APP.'Custom'.DS.'Model'.DS.'Datasource'.DS),
'Model/Datasource/Database' => array(APP.'Custom'.DS.'Model'.DS.'Datasource'.DS.'Database'.DS),
'Model/Datasource/Session' => array(APP.'Custom'.DS.'Model'.DS.'Datasource'.DS.'Session'.DS),
'Controller' => array(APP.'Custom'.DS.'Controller'.DS),
'Controller/Component' => array(APP.'Custom'.DS.'Controller'.DS.'Component'.DS),
'Controller/Component/Auth' => array(APP.'Custom'.DS.'Controller'.DS.'Component'.DS.'Auth'.DS),
'Controller/Component/Acl' => array(APP.'Custom'.DS.'Controller'.DS.'Component'.DS.'Acl'.DS),
'View' => array(APP.'Custom'.DS.'View'.DS),
'View/Helper' => array(APP.'Custom'.DS.'View'.DS.'Helper'.DS),
'Console' => array(APP.'Custom'.DS.'Console'.DS),
'Console/Command' => array(APP.'Custom'.DS.'Console'.DS.'Command'.DS),
'Lib' => array(APP.'Custom'.DS.'Lib'.DS),
'Locale' => array(APP.'Custom'.DS.'Locale'.DS),
'Vendor' => array(APP.'Custom'.DS.'Vendor'.DS),
'Plugin' => array(APP.'Custom'.DS.'Plugin'.DS),
)
);
その結果、Custom ディレクトリにパッケージ本体と同名のソースファイルを配置した場合、 Custom ディレクトリ上のファイルが優先的に読み込めるようになった。例えばパッケージのログイン画面をカスタマイズしたい場合は、パッケージの View/login.ctp を Custom/View/User ディレクトリにコピーし、カスタマイズを行う。パッケージ側のソースファイルには修正が入らないため、ファイルの差し替えだけでパッケージの更新が可能となる。
加えて、同じく Config/bootstrap.php に以下の行を加えることによって、Custom ディレクトリに配置した config.php ファイルによって、パッケージ本体の設定の上書き、または追加ができるようになった。
// カスタマイズ用設定ファイルをロード
Configure::config('default', new PhpReader(APP.'Custom'.DS.'Config'.DS));
Configure::load("config");
また View/Layouts/default.php に以下のコードを追加し、全画面で「custom.css」と「custom.js」を読み込み、カスタマイズ用の CSS とJavaScript を追加できるようにした。
echo $this->Html->css('custom.css'); // カスタマイズ用CSS
echo $this->Html->script('custom.js'); // カスタマイズ用スクリプト
ブラウザで /update を実行すると、パッケージ本体のテーブル定義のアップデートと、カスタマイズ用のテーブル定義のアップデートが同時に行われる。
ディレクトリ構成を図にすると以下の通りとなる。
これでパッケージ本体とカスタム領域を一応は分離することが可能となった。しかしながら、この方法ではソースファイル単位での差分が発生してしまい(例えば UsersContoller.php の特定のメソッドを書き換えたいだけ場合も、ソースを丸ごとコピーする必要がある。 )、まだ改善の余地があるように思う。