CakePHP1.3→2.6のアップグレード時に発生した作業や注意点について

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存

こんにちは。リスペクトの木村です。

CakePHPで運用しているサイトがいくつかあるのですが、その一部について1.3から2.6へアップグレードする機会がありました。
フレームワークのコア部分のアップグレードというと何かしらのトラブルが発生する印象があります(メジャーバージョンアップなら尚更)が、例に漏れずすんなりと終わる事はありませんでした・・・。

そこで、今回はアップグレードの中で行った作業やすんなり行かなかったポイントについて、解決策と合わせてご紹介したいと思います。

アップグレードに踏み切った理由

そもそも、何故アップグレードに踏み切ったか、という所を簡単にご紹介します。
諸事情ありますが・・・

  • オンプレミスから、クラウド(AWS)へ移行する事になった
  • ApacheやPHPといったミドルウェアのバージョンが上がったり、サーバ構成が変更されるため、プログラムをある程度整理したい
  • リファクタリングもしなければならない
  • そもそも1.3系は3.x系のリリースに伴いサポート終了なので、今後の事を考えると2.x系もしくは3.x系へ上げなければならない

大体はこんな理由です。

ちなみに、1.3系のままでも一応動きます。
しかし、コア部分の改修が必要になってくるのではないかという点や、上記のリファクタリングの作業を行う上で、フレームワーク側やPHP側の新機能に合わせてリファクタリングを行った方が良いのではないかなど、色々検討した結果、リファクタリング前にまずはアップグレードを行う事になりました。

3.xではなく2.xにした理由

ちなみに、CakePHPは今回アップグレード対象の2.6ではなく、3.0が最新版です。
「せっかくなので最新の3.0へアップグレードするのが良いのではないか?」とは思いましたが、主に次のような理由で断念しています。

  • 2.xであればある程度慣れているが、3.xはリリースされたばかりのためある程度調査が必要
  • 1.3→2.xに比べて、変更されている部分がかなり多く、工数が大幅ににかかることが予想された
  • 1.3→2.xであればアップグレードシェル(ここに参照リンク)があるため、ある程度自動化されているが、1.3→3.xへ上げる手段は用意されていない
    そのため、全て手動もしくは、一旦2.xを経由してアップグレードする必要がある
  • さらに、構造が特殊(後述)なため、想定しているよりも工数が掛かる可能性も

結局2.xを経由する必要がありそうだったり、使い慣れてない3.xへ移行して何かあるよりは、安定していて使い慣れている2.xへの移行が最適だろう、という事で今回は2.6への移行となりました。

ちょっと特殊なアプリケーション構成

上で「特殊な構造」と書きましたが、アップグレード前のアプリケーション構造はこんな感じでした。

DocumentRoot/
├ app/
│ ├ controllers/
│ ├ models/
│ ├ views/
│ ├ ...
│ └ webroot/
├ app1/
│ └app/
│  ├ controllers/
│  ├ models/
│  ├ views/
│  ├ ...
│  └ webroot/
├ app2/
│ └app/
│  └ ...
├ app3/
│ └app/
│  └ ...
├ app4/
│ └app/
│  └ ...
├ cake/
├ plugins/
├ vendors/
└ ...

どれぐらい特殊かお分かり頂けますでしょうか。

本来、1.3系は2.x系のようにマルチアプリケーションに対応していないのですが、index.phpを書き換えて、アプリケーションの読み込み先を動的に変更させていました。
それを実現するため、 app/ 以外の app1〜4/ 下には更にappディレクトリがあり、その下に app/ と同じ構造のフォルダ(controllersやmodels)が広がっている、という構造になっていました。

アップグレードの主な作業+ポイント

前提条件を説明した所で、早速作業とそのポイントについて説明します。
今回は、2.0への移行ガイドを参考にしながら、次の作業順でアップグレードの作業を進めていました。

  1. 不要なファイルの整理
  2. プラグインの確認
  3. index.phpの更新
  4. UpgradeShellの実行
  5. 微調整
  6. 設定のアップグレード
  7. plugin/vendor の Composerへの移行

大体はこの手順で良いはずなのですが、参考にされる際は手元の環境に合わせて調整して下さい。

お次は、各作業の中で躓いたり調整が必要だった部分についてご紹介します。

不要なファイルの整理

基本ではありますが、まずは不要なファイル/フォルダが無いかどうかを確認し、不要であれば削除しておきます。
アップグレードやその後の作業に掛かる手間が少なくなるのはもちろんですが、後ほど使用するUpgradeShellは全てのファイルを探索してリネームや調整を行うため、時間の短縮に繋がります。
また、整理する流れでシステム構造を改めて確認できるため、構造も整理する事で作業の効率化にも繋がります。

Controller/Model/Viewや、利用しているComponent/Helperなんかは本当に全て使用しているかどうかを予め確認しておくと安心です。

今回は、改めて確認すると利用していないもの、Git化前のバックアップ用ファイルや実験用の別名ファイルなんかが見つかったので、そこそこ整理しています。
前から整理しておけばこうはならなかったはずですが・・・いい機会だと思って削除しました。

1.3系プラグインはそのままでは2.xに対応していないプラグインも注意が必要です。

プラグインの構造はapp下と同じのためか、1.3系向けのプラグインはそのままでは2.x系では使用できません。
簡単な物であれば自分で調整する、というのも手ですが・・・やはりアップグレードが提供されていればそれを利用しましょう。

ただし、cake_ktai_libraryのように2.x系の動作確認は古いバージョンまで、という場合があるのでこれも注意が必要です。
可能であればプラグイン回りのコードは無効化しておき、アップグレード後に対応版を導入して再度動作を確認するという手段が理想的です。

今回は利用していたプラグインのほとんどが2.x向け(対応?)ではありませんでした。
ただ、そのプラグインの中でも使用している部分は一部だけでしたので、その部分と同じ動きをするようなプラグインを自作して対応しています。

app/index.phpやapp/webroot/index.phpを2.xのものに上書きする

アップグレード手順のサイトには記載されていませんが、app/index.phpやapp/webroot/index.phpの中身も若干変化しています。
触らずとも大丈夫なのですが、念のため行っておいた方が良さそうです。

今回のようにindex.phpの改変によるマルチサイト化が行われている場合は、そのままではUpgradeShellが動作しないため上書きが必須です。

UpgradeShellによるファイル移動は万全ではない

ここまででUpgradeShellを実行する準備は整っているはずです。
前の状態に戻せるようにしておくため、バックアップを取っておきます。
変換後に、以前どんな構造だったかが速やかに確認できるという点でも有用なので、忘れずに取っておきます。

また、実行前には–dry-runオプションを付与してどんなリネームや移動が行われるかを予めチェックしておきます。
大体はこの通りの結果になるので、どんなリネームや移動が行われるかを確認しておきます。

で、いよいよ準備が整った段階でいざ実行しますが、この段階でエラーが発生し、変換が中途半端な所で止まってしまう場合があります。
コンソールの結果から正常に終わっているかどうかを確認し、エラーで失敗していた場合はGitの管理で戻したり、バックアップから復元するようにします。

今回遭遇したのは「ファイルやフォルダのリネームが正常に行われない場合がある」というものでした。
Windows環境下で実行したせいかもしれませんが、先頭の文字を大文字に変換するだけのリネームに失敗している事が多めでした。
例えば、view→Viewsでは成功しますが、view→Viewでは失敗する、という感じです。

これは、Windowsが大文字小文字を区別しない仕様でため、同じフォルダ名と認識されてリネームに失敗しているためです。
Mac/Linux環境下で発生する事は少ないのですが、対象ディレクトリをVagrantの仮想マシンでマウントしていて、そこに対してUpgradeShellを実行する場合も発生していました。
回避方法としては、Gitによるバージョン管理が行われていれば–gitオプションを付与する事でgitを利用したリネームや移動が行われるため、付与する事で正常に実行できます。
万が一失敗しても、Git上からアップグレード前の状態に戻せるため、安心です。

ちなみに、今回のようにアップグレードするサイトがマルチサイト化している場合は、app下のディレクトリを一階層上げてから実行しましょう。

ファイル内部のリネームも万全ではない

UpgradeShellの実行時はファイルやフォルダのリネームに加えて、ファイル内部の調整も行われます。
例えば、ViewでHelperを利用する際の記述が $Paginator->hogehoge() となっていましたが、2.xからは $this->Paginator->hogehoge() となるため、この書式に調整されます。

UpgradeShellによるリネームのタイミングでは、その変数がModelかどうかの確認をしていないため、各種Helperのオーバーライドなどをしていて同じ命名規則の変数が存在する場合、その部分も上記の規則に従ってリネームされます。
予め変更しておくか、Upgradeshellの実行後に$this->が付けられた部分を一通り確認し、余計な所まで変換されていないか確認しておきます。

設定のアップグレードは行われない

これも当然ですが、設定回り(Config以下)の内容についてはアップグレードされません。
特にcore.phpやbootstrap.php、database.phpでは記述が変わっていたり、そもそも使用できなくなっているオプションが存在します。
そのため、2.x用の設定を確認しながら、同じような設定になるよう調整を行います。

手動で調整が必要な部分もある

設定の他にも手動で調整する部分が多々存在するため、深いカスタマイズや変わった使い方をしている所は特に注意が必要です。
今回アップグレードするにあたって、手動で調整した所を表にしてみました。

変更対象 変更内容
GETパラメータを $this->request->params で取得している部分 $this->request->query に置換
$this->headerを使用している部分 $this->request->header に置換
find関数で、第一引数に検索パラメータ(conditionsとか)を指定している部分 第二引数に検索パラメータを指定するようにし、第一引数はallやfirstにする
Modelを呼び出す際に、App::import()で読み込んでからnewしている部分 ClassRegistry::init(Model名) で読み込むようにする
$this->logの第二引数でファイル名を指定している部分 CakeLog::configで定義した設定名を記述するようになったので、bootstrap.phpなどで予め定義しておき、設定名を記述する
$this->cakeErrorによるエラー表示 適切なExceptionを呼び出すようにする
$this->cakeErrorなどの、エラー表示時の動作をカスタムしている部分 独自のExceptionRendererを作成し、予めそれを呼び出すようにする必要がある

特に、エラー表示回りやModelを呼び出す際の動作は使用している部分が多いので特に注意する必要があります。
このあたりは、2.0への移行ガイドに書いてあったり、書いてなかったりします。

Composerを使う場合は要注意

必要なライブラリはComposer経由でインストールする、という場合が最近は多いと思います。
ただ、app/Vendorやapp/Pluginに導入する場合はそのままで良いのですが、appと同ディレクトリにあるvendorsやpluginsに導入するという場合は注意が必要です。

デフォルトですと、CakePHPのPluginはplugin、それ以外はvendorと、 s の付かないディレクトリにインストールされるため、そのままではCake側で自動でロードされません。
そのため、自動でロードされるよう調整を行う必要があります。

Pluginの場合

composer.jsonに次の記述を追加します。

"extra": {
    "installer-paths": {
      "plugins/{$name}": ["type:cakephp-plugin"]
    }
},

(参考: http://qiita.com/matsuoshi/items/fc105ce011a4a868879c

こうする事で、CakePHPのPlugin(とPackagistに登録されているもの)はpluginsにインストールされるようになります。

Vendorの場合

この場合は公式ドキュメントにも書いてありますが、次の記述を追加します。

require_once APP.'../vendor/autoload.php';
spl_autoload_unregister(array('App', 'load'));
spl_autoload_register(array('App', 'load'), true, true);

1行目でautoload.phpを読み込んでいますが、これだけですと問題が発生します。
そのため、2行目でCakePHPのオートローダーを一旦削除し、3行目で再度登録する事でComposerよりも先に評価されるようになります。

おわりに

CakePHPアップグレードの際の作業やハマったポイント、ちょっとした調整点をご紹介しました。
実際に作業を進めてみると、何か問題があった際に解決しようとして調べてみるのですが、アップグレードしてみたという事例がそんなに多くないせいか、トラブル解決に若干手間取ってしまった感じがあります。
基本的な事項はドキュメント2.0への移行ガイドに書いてありますが、そこから発展した作業が必要な場合があるのでそこには注意が必要です。
CakePHPのお作法に則ってマジメに作っていればこんなに困る事は無かったとは思いますが・・・大抵のサイトはどこかで引っかかってしまうのではないでしょうか。

この記事が、アップグレードに困っている方のお役に少しでも立てれば幸いです。
現場からは以上です。

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存