Rectorを使って地獄のLaravelアップグレード作業をEASYにしよう[Laravel7→11]
はじめに
あるプロジェクトで、PHP・Laravelのアップグレードを行うことになりました。
バージョンを確認したところ、Laravel7でした。がんばって11まで上げていかなくてはなりません。
アップグレード作業は未経験であり、ましてやLaravel7→11と八艘飛びな変更であるため、「間違いなくやらかすぞ!?」と戦々恐々でした。
はてさて、どっから手を付けたらいいものか。ミスを減らしながら、楽にできる方法は無いかと探していたところ、Rectorに出会いました。
Rectorがなければ、私は爆発していました。
Rectoreへの感謝を込めて、Rector推し記事を書いた次第です。
この記事を読んで欲しい人
- PHP・Laravelのアップグレードしたい人!
 - アップグレード作業が不慣れ・未経験の人
 
Rector、Rector-laravelとは
公式がこちら
RectorはPHPコードを即座にアップグレード、リファクタリングします。PHP、Laravelだけでなく、Symfony、PHPUnit、Doctrineなどをサポートしています。
更に、Rectorの拡張機能として、Laravelコミュニティが開発した"Rector-laravel"が提供されています。本記事ではRector&Rector-laravelにより、PHPとLaravelのバージョンアップのやりかたを記述します。
Rectorをインストールし、rector.phpを以下のように書き換え、実行するだけで、非推奨になった記述法などを検出し、アップグレードに対応したコードに一気に書き換えてくれます!素敵!
↓これでLaravel11の記法に変更してくれる。素敵!
<?php declare(strict_types=1);
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelLevelSetList;
return RectorConfig::configure()
    ->withSets([
        LaravelLevelSetList::UP_TO_LARAVEL_110,
    ]);
Rector、Rector-laravelの導入方法
composer require rector/rector --dev
composer require driftingly/rector-laravel --dev
を実行します。
rector.phpの書き換え
rector.phpのconfigを書き換え、アップグレードしたいPHPやLaravelのバージョンに調整します。
<?php declare(strict_types=1);
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelLevelSetList;
return RectorConfig::configure()
    ->withSets([
        LevelSetList::UP_TO_PHP_84,  // PHP 8.4の機能を有効化
        LaravelLevelSetList::UP_TO_LARAVEL_110,
    ]);
LevelSetList::UP_TO_PHP_80にすると、PHP8.0に対応したコード修正ができます
Laravelは7→8→9→10→11と段階的に上げていく必要がありますが、LaravelLevelSetList::UP_TO_LARAVEL_80と記述すればLaravel8に対応したコード修正ができるので、段階的に上げていくのも簡単です。
実行!
いよいよ、Rectorを実行してコードを修正しましょう。
ドライランを行うと、変更点をターミナルで明記してくれます。
vendor/bin/rector process --dry-run
実際にコードを書き換える際はドライランオプションを消して実行すればOKです!
vendor/bin/rector process
これでコード修正ができました!!
おわりに
折角なので、実際に使用したrector.phpファイルの中身をお見せします。
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetList;
use Rector\Set\ValueObject\LevelSetList;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector;
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\PHPUnit\Set\PHPUnitSetList;
return static function (RectorConfig $rectorConfig): void {
    $rectorConfig->paths([
        __DIR__ . '/app',
        __DIR__ . '/config',
        __DIR__ . '/database',
        __DIR__ . '/routes',
        __DIR__ . '/routes/web.php',
        __DIR__ . '/tests',
    ]);
    // Laravel 11への移行に必要なルールセット
    $rectorConfig->sets([
        LaravelSetList::LARAVEL_110,  // Laravel 11.0への移行ルール
        LaravelSetList::LARAVEL_CODE_QUALITY,
        LevelSetList::UP_TO_PHP_84,  // PHP 8.4の機能を有効化
        PHPUnitSetList::PHPUNIT_100,
    ]);
    // PHP 8.4の機能を活用するためのルール
    $rectorConfig->rule(TypedPropertyFromStrictConstructorRector::class);
    $rectorConfig->rule(ClassPropertyAssignToConstructorPromotionRector::class);
    $rectorConfig->rule(RemoveUselessParamTagRector::class);
    $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
    // インポート設定
    $rectorConfig->importNames();
    $rectorConfig->importShortClasses(false);
    // スキップ設定
    $rectorConfig->skip([
        __DIR__ . '/vendor',
        __DIR__ . '/bootstrap/cache',
        __DIR__ . '/storage',
        __DIR__ . '/.phpunit.cache',
        __DIR__ . '/node_modules',
    ]);
};
Discussion