ランサーズ(Lancers)エンジニアブログ > PHP > CakePHP > CakePHP2→3バージョンアップの開始

CakePHP2→3バージョンアップの開始

kanazawa|2019年09月02日
CakePHP

SREチームの金澤です。

ランサーズのCakePHP2→3へのバージョンアップを開始しました。

これから何回かに分けてお話したいと思います。

第1回目は、バージョンアップ方針と
CakePHP新旧バージョンの共存方法についてお話したいと思います。

プロダクト規模

ランサーズのプロダクト規模は概ね以下のようになります。
この規模のソースを、普段の開発を止めずにバージョンアップする必要があります。

ディレクトリ ファイル数 ステップ数
Config 約190 約60000
Console 約170 約30000
Controller 約350 約110000
Lib 約1100 約153000
Model 約420 約105000
View 約2800 約240000
合計 約5030 約698000

CakePHP1.3→2.8の段階的バージョンアップ

そのため、CakePHP1.3→2.8移行は段階的に、controller単位で、1年以上かけて行いました。

その内容について、2018年のPHPカンファレンスでも発表させていただきました。

移行中のディレクトリ構成は以下のようになっていました。

+ app(※CakePHP1.3のコード)
 + config
 + controller
 + lib
 + model
+ cake
 + ※CakePHP1.3本体
+ cake28(※CakePHP2.8のコード)
 + Config
 + Controller
 + Lib
 + Model
+ vendor
 + cakephp
  + ※CakePHP2.8本体

この方法の欠点は、
Controllerに焦点を当て、初めにModel、Libをコピーする形をとったため、
普段の開発で両バージョンのModel、Libを修正しなければならなくなったことです。

CakePHP3ではModelが大幅に変更されていることもあり、同じアプローチでは取れません。
そもそも、両バージョンに修正行う構成は避けたいところです。

CakePHPの処理の流れの概要は以下のようになります。

普段の開発で、両バージョンの修正が必要な状態にならないようにするためには、
原則、矢印の終端のコードから移行していく必要があります。

CakePHP2とCakePHP3の共存

まず、CakePHP本体の共存から開始します。

CakePHP1.3→2.8移行のときは、CakePHP1.3をcakeディレクトリに配置し、
CakePHP2.8はvendorディレクトリでcomposer管理していました。

CakePHP2とCakePHP3を共存させるために、CakePHP3をcomposer管理します。

CakePHP2をcake28/Vendor/cakephp に移動します。
CakePHP2本体そのものに手をいれることを想定し、git管理します。

+ cake28(※CakePHP2のコード)
 + Config
 + Controller
 + Lib
 + Model
 + Vendor
  + cakephp
   + ※CakePHP2本体
+ vendor
 + cakephp
  + ※CakePHP3本体

加えて、config、srcディレクトリを作成し、ここにCakePHP3のコードを書いていきます。

+ config(※CakePHP3のコード)
 + .env
 + App.php
+ src(※CakePHP3のコード)
 + Controller
 + Lib
 + Model
+ cake28(※CakePHP2のコード)
 + Config
 + Controller
 + Lib
 + Model
 + Vendor
  + cakephp
   + ※CakePHP2本体
+ vendor
 + cakephp
  + ※CakePHP3本体

旧バージョンでの開発抑止

CakePHP1.3→2.8のバージョンアップが長引いた要因の一つに、
普段の開発がCakePHP1.3で進められていたことがあります。

バージョンアップの進捗状況を壁にも書いていたのですが、途中で棚卸をした段階で、
多くの新規コントローラーがCakePHP1.3に追加されていたことが判明しました。

フレームワークのバージョンアップは長丁場になります。
その間にも普段の新規開発は行われるため、
なるべくこれらを新バージョンで開発してもらう工夫が必要になります。

CIで旧バージョンの新規開発をチェックする

バージョンアップを行うにあたり、CIで文法チェックを行っていましたが、これは非常に効果がありました。

※詳細は以前のブログに詳しく書いています。

ランサーズの開発は、CIのチェックを通らないとマージできないように設定しています。

新規開発を新バージョンで進めてもらうために、CIのチェックに
CakePHP旧バージョンでの開発を抑止するチェックを入れる予定です。

CakePHP2→4バージョンアップについて

この単位で段階的にバージョンアップするのであれば、
CakePHP2→4へのバージョンアップもできるかも知れないと思い、検討しました。

しかし、CakePHP4では、要求するPHPUnitの最低バージョンが8.3.3以上になります。
CakePHP2では、PHPUnit6以上になるとUTが正しく動作しなくなります。

$ ./cake28/Console/cake l_test cake28/Test/Case/Model/CityTest.php
Warning Error: include(PHPUnit/Autoload.php): failed to open stream: No such file or directory in [/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php, line 178]

Warning Error: include(): Failed opening 'PHPUnit/Autoload.php' for inclusion (include_path='/var/www/lancers/vendor/phpunit/phpunit:/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib:/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib:.:/usr/share/pear:/usr/share/php') in [/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php, line 178]

Error: Please install PHPUnit framework v3.7 (http://www.phpunit.de)
#0 /var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/Console/ShellDispatcher.php(221): TestShell->initialize()
#1 /var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/Console/ShellDispatcher.php(66): ShellDispatcher->dispatch()
#2 /var/www/lancers/cake28/Console/cake.php(56): ShellDispatcher::run(Array)
#3 {main}
$

CakePHP2のUTを利用しながらバージョンアップを行いたいので、現状はCakePHP3に留めました。
CakePHP4へのバージョンアップは、UTをCakePHP3ベースに切り替え、
PHPUnitを8.3.3以上にバージョンアップできたタイミングで検討したいと思います。

※2019/10/18追記 CakePHP3でも以下のエラーとなりました。
CakePHP3本体をPHPUnit8.3.3に対応させる必要がありますが、戻り値の型宣言が必要なのでPHP7が必須になりそう。

$ ./bin/phpunit --bootstrap config/bootstrap.php tests/TestCase/Model/Table/CitiesTableTest.php
PHP Fatal error:  Declaration of Cake\TestSuite\TestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp(): void in /var/www/lancers/vendor/cakephp/cakephp/src/TestSuite/TestCase.php on line 35
PHP Stack trace:
PHP   1. {main}() /var/www/lancers/vendor/phpunit/phpunit/phpunit:0
PHP   2. PHPUnit\TextUI\Command::main() /var/www/lancers/vendor/phpunit/phpunit/phpunit:61
PHP   3. PHPUnit\TextUI\Command->run() /var/www/lancers/vendor/phpunit/phpunit/src/TextUI/Command.php:159
PHP   4. PHPUnit\TextUI\TestRunner->getTest() /var/www/lancers/vendor/phpunit/phpunit/src/TextUI/Command.php:177
PHP   5. PHPUnit\TextUI\TestRunner->loadSuiteClass() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php:101
PHP   6. PHPUnit\Runner\StandardTestSuiteLoader->load() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php:141
PHP   7. PHPUnit\Util\FileLoader::checkAndLoad() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php:36
PHP   8. PHPUnit\Util\FileLoader::load() /var/www/lancers/vendor/phpunit/phpunit/src/Util/FileLoader.php:47
PHP   9. include_once() /var/www/lancers/vendor/phpunit/phpunit/src/Util/FileLoader.php:59
PHP  10. spl_autoload_call() /var/www/lancers/tests/TestCase/Model/Table/CitiesTableTest.php:11
PHP  11. Composer\Autoload\ClassLoader->loadClass() /var/www/lancers/tests/TestCase/Model/Table/CitiesTableTest.php:11
PHP  12. Composer\Autoload\includeFile() /var/www/lancers/vendor/composer/ClassLoader.php:322
PHP  13. include() /var/www/lancers/vendor/composer/ClassLoader.php:444
$

今後の予定

次回は、最大の難関であるModelのバージョンアップについて書きたいと思います。

CakeFest2019に登壇します

2019/11/7 – 2019/11/10にCakeFestが東京で開催されます。

CakeFestはCakePHPの世界的なイベントで、2019年は日本で開催されることになりました。
※ランサーズは前回の2017年に続き、2019年もスポンサーになっています。

「CakePHP3への滑らかな移行を考える」というテーマが採択されました。
本記事の内容も踏まえて発表する予定です。