俺の報告

RoomClipを運営するエンジニアの日報(多分)です。

Codeigniterで複数アプリケーション - 日報 #154

今日はサクッと。

PHPフレームワークベンチマークを久々調べてみましたら、
http://blog.a-way-out.net/blog/2015/03/26/php-framework-benchmark/
こんな素晴らしいサイトが。

CodeIgniterは非常に優秀な成績を納めておりまして、
嬉しい限りです。
Laravelのような新しいフレームワークも触ってみたいですが、
あくまで軽さ重視でいきたい今日此の頃です。

さて、
CodeIgniterのコア周りで僕らが加えた大きな変更について今日は少し触れたいと思います。
CIで真っ先に困ったのは、以下2点です。

  1. 複数アプリケーションを作り、ライブラリなどは共有したい
  2. ユニットテストに対応したい

2番に関しては、言わずと知れたkenjiさん(http://d.hatena.ne.jp/Kenji_s/20110822/1314003400)の記事が有名ですが、
1番に関してはモジュールを使うとか、なんかあまり歯切れのいいものになっていない感じがします。
例えばAPIとWEBでCodeIgniterのコアやライブラリは共有したいけど、
コントローラーとビューは別にしたい、なんてことがあると思います。
その場合、どうすりゃいいのか?

結論から言うと、
applicationのlibray,model,helper,config,coreのロードの先に、 commonのようなパスを追加していけばいいという感じです。
CI_Loaderを直接いじると面倒なので、extendして使用します。
public/index.phpに対して

define('COMMONPATH', (dirname(__FILE__) . '/../../hoge/common/'));
  

のように例えばCOMMONPATHを2階層上につくっておき、
その配下にcommon/application/libraryのようなものを作成しておく。
さらに、Codeigniter.phpもcommon/application/system/coreとかに置いておき、
ど頭あたりで、

    if (defined('COMMONPATH')) {
        $base_paths[] = COMMONPATH. 'application/';
    }

のよーにcommon配下のアプリケーションをbase_pathとして追加しておく。
こうすることで、Codeigniter.phpがcommon配下のcoreディレクトリなどを参照してくれるようになる。

この時点でCodeigniter.phpをいじるという大罪を覚悟せねばならないわけですが、
まぁしゃぁなし。

ほんで、このおかげでcommon/application/coreの配下に例えばRC_Loader.phpなるクラスファイルを作成し、
CI_Loaderをextendしておけば、とりあえずCI_Loaderを拡張することができるわけだ。

最後の仕上げに、RC_Loaderにて、

    public function __construct() {
        parent::__construct ();
        $this->_ci_library_paths [] = COMMONPATH . 'application/';
        $this->_ci_helper_paths [] = COMMONPATH . 'application/';
        $this->_ci_model_paths [] = COMMONPATH . 'application/';
        $CI =& get_instance();
        $CI->config->_config_paths[] = COMMONPATH . 'application/';
    }

こんな感じでCOMMONPATH配下のapplicationを参照するように追加しておく。
(ちなみに各loadメソッド、例えばlibraryなどのロードクラスにおいてsubclass_prefixがついている状態でcommonからロードするように一部書き換えは必要。なのでRC_Loaderでhelperメソッドやらlibraryメソッドをオーバーライドする必要が厳密にはあります。)

    public function helper($helpers = array())
    {
            // ...
            // Try to load the helper
            foreach ($this->_ci_helper_paths as $path)
            {
                $helper_file_path_list = array(
                    $path.'helpers/'.$helper.'.php',
                    $path.'helpers/'.config_item('subclass_prefix'). $helper.'.php'
                );
                foreach($helper_file_path_list as $helper_file_path){
                    if (file_exists($helper_file_path))
                    {
                        include_once($helper_file_path);

                        $this->_ci_helpers[$helper] = TRUE;
                        log_message('debug', 'Helper loaded: '.$helper);
                        break;
                    }
                }
            }
    }

例えばこんな上記の様な感じ。
こうしておくと、load先がcommon配下をみてくれるようになるので、
あとはどっからでもcodeigniterっぽくフレームワークを開始するけど、library,helper,model,coreなどを共有してコントローラーとビューだけかけばよい、というハッピーな状況にもっていけます。

まぁ色んなやり方があると思いますが、取り急ぎこうすれば複数アプリいけまっせという、
小ネタの話でした。

RoomClipはPHP(欲を言えばとくにCodeigniterを使える)エンジニアを募集しております!
PHPフレームワークにつかれた方、本気で魔改造してみませんか? www.wantedly.com
www.wantedly.com