Laravel6.2 → Laravel 7.xへのアップグレード手順

公式ドキュメント: Upgrade Guide

Update your laravel/framework dependency to ^7.0 in your composer.json file. In addition, update your nunomaduro/collision dependency to ^4.1, phpunit/phpunit dependency to ^8.5, laravel/tinker dependency to ^2.0, and facade/ignition to ^2.0.

composer.json

//省略

"laravel/framework": "^7.0",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
"laravel/tinker": "^2.0",
"facade/ignition": "^2.0",
"laravel/ui": "^2.0",

// 省略

App/Exceptions/Handler
-> composer.updateする前に変更しないとエラーになる

use Throwable;

// public function report(Exception $exception)
public function report(Throwable $exception)

// public function render($request, Exception $exception)
public function render($request, Throwable $exception) 

$ php composer.phar update
$ php artisan –version
Laravel Framework 7.2.1

## 主要変更点
– Symfony 5 関連のアップグレード
— App\Exceptions\Handlerクラスのreportとrender
— コンフィグファイルのsessionのoptionのデフォルト値の変更
– Authenticationー認証
— laravel/uiを~2.0にする必要
– Date Serializationー日付のシリアライズ化
— 2019-12-02 20:01:00は7系から2019-12-02T20:01:00.283041Zに更新
– $model->getOriginal()メソードはキャストされたモデルを使用

## その他変更点
– PHPのバージョン 7.2.5以上
– Blade::componentメソードをBlade::aliasComponentに変更
– Blade Components & “Blade X”
– “factory types”機能を削除
– addHiddenとaddVisible削除
– bootingとbootedをEloquentに追加
– resolveRouteBindingメソードは$fieldパラメータ使用
– Illuminate\Auth\Passwords\TokenRepositoryInterfaceにrecentlyCreatedTokenを使用
– queue:workコマンドのフラグ–daemonが削除
– Illuminate\Http\Resources\Json\Resourceは削除
– array セッションドライバのデータはカレントリクエストに持続的にアクセス
– TestResponseクラスのassertSee アサーションは自動的にエスケープ
– differentルールはリクエストに特定のパラメータが足りない場合に通らない

## 各変更点の確認
– Authentication
laravel/ui 2.0で異常なし

– コンフィグファイルのsessionのoptionのデフォルト値の変更
config/session.php

// 'secure' => env('SESSION_SECURE_COOKIE', false),
'secure' => env('SESSION_SECURE_COOKIE', null),

// 'same_site' => null,
'same_site' => 'lax',

– Date Serialization
一部データをJasonで送って、blade側でdateのデータ(created_at)をmomentでMM/DD HH:mmに変換しているが、挙動確認したところ影響はない。

– $model->getOriginal()
画像の保存処理で、$file->getClientOriginalName();としており、似ているため念の為確認したが、やはり問題なし

– Mail Configuration File Changes
laravel7.2をcreateして一応違いを確認しておく。
6系だとconfig/service.phpに書かれていたsmtp周りがconfig/mail.phpに纏められています。確かに、なんでservice.phpに?って思っていたので、これは良い改良です。

'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
            'port' => env('MAIL_PORT', 587),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
        ],

        'ses' => [
            'transport' => 'ses',
        ],

        'sendmail' => [
            'transport' => 'sendmail',
            'path' => '/usr/sbin/sendmail -bs',
        ],

        'log' => [
            'transport' => 'log',
            'channel' => env('MAIL_LOG_CHANNEL'),
        ],

        'array' => [
            'transport' => 'array',
        ],
    ],

しかし、まさかもうLaravel6.x系が古くなるとは思わなかった。。

vagrant awslinuxとLarave update6.0

– php7.1は2019/12より積極的にメンテナンスされなくなる
– その為、php7.2以上が要求

$ php -v
PHP 7.1.7 (cli) (built: Sep 14 2017 15:47:38) ( NTS )
$ cat /etc/issue
Amazon Linux AMI release 2017.03

### PHP7.4へのアップデート
// repositoryのインストール
$ sudo yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
$ sudo yum install -y –enablerepo=remi-php74 php which
Loaded plugins: priorities, update-motd, upgrade-helper
Error getting repository data for remi-php74, repository not found

あれ、vagrantboxesのawslinuxだと、php7.1以上は入れられない?
ってことは、vagrant init は、mvbcoding/awslinuxではなく、centos/7でやらないと駄目ってこと??
今のタイミングでlaravel6.0以外で開発するってのは絶対ありえんからなー

$ exit
logout
Connection to 127.0.0.1 closed.
> vagrant halt

Laravel update 5.7&5.8

### laravel 5.7
upgradeページを確認
https://readouble.com/laravel/5.7/ja/upgrade.html

composer.json

"require": {
        "php": ">=7.1.3",
        "laravel/framework": "5.7.*",
        "laravelcollective/html": "5.7.*",
        "cviebrock/eloquent-sluggable": "^4.3",
        "unisharp/laravel-filemanager": "^1.9",
        "intervention/image": "^2.5"
    },

$ php composer.phar update
$ php artisan –version
->エラー
-> Unresolvable dependency resolving [Parameter #0 [ $app ]] in class Illuminate\Support\Manager

config/app.php

Illuminate\Notifications\NotificationServiceProvider::class,

$ php artisan –version

### laravel 5.8
https://readouble.com/laravel/5.8/ja/upgrade.html

composer.json

"require": {
        "php": ">=7.1.3",
        "laravel/framework": "5.8.*",
        "laravelcollective/html": "5.8.*",
        "cviebrock/eloquent-sluggable": "^4.3",
        "unisharp/laravel-filemanager": "^1.9",
        "intervention/image": "^2.5"
    },

$ php artisan –version

criticalな変更はそこまでありませんが、公式のupgrade guideを読むと、セキュリティパッチが多く、やはり最新版に保った方が良さそうだ。

Laravel upgrade to 5.6

### laravel 5.5
$ npm install

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.5.*",
        "laravelcollective/html": "5.5.*",
        "cviebrock/eloquent-sluggable": "^4.3",
        "unisharp/laravel-filemanager": "^1.9",
        "intervention/image": "^2.5"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~6.0",
        "symfony/css-selector": "2.8.*|3.0.*",
        "symfony/dom-crawler": "2.8.*|3.0.*"
    },

### laravel 5.6
composer.json

"scripts": {
        "post-root-package-install": [
            "php -r \"copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall",
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
        ]
    },

$ php composer.phar update
$ php artisan –version

Pythonでも何だかんだ言われながらpytho2.7から3に変わっていきましたし、常に最新バージョンで開発する癖をつけた方が良さそうです。

larave 5.3 -> 5.4 & Webpack

– 5.3 -> 6.0など一気に上げず、一つ一つバージョンを上げていく
– 5.4からcompileはgulpではなくwebpackになっており、基本的にwebpackを使う

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.4.*",
        "laravelcollective/html": "5.4.*",
        "cviebrock/eloquent-sluggable": "^4.0",
        "unisharp/laravel-filemanager": "^1.9",
        "intervention/image": "^2.5"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.7",
        "symfony/css-selector": "2.8.*|3.0.*",
        "symfony/dom-crawler": "2.8.*|3.0.*"
    },

webpack.mix.js

const { mix } = require('laravel-mix');

mix.js('resources/assets/js/app.js', 'public/js')
    .sass('resources/assets/sass/app.scss', 'public/css');

mix.styles([
    'resources/assets/css/libs/blog-post.css',
    'resources/assets/css/libs/bootstrap.css',
    'resources/assets/css/libs/font-awesome.css',
    'resources/assets/css/libs/metisMenu.css',
    'resources/assets/css/libs/sb-admin-2.css'

], 'public/css/libs.css');

mix.scripts([
    'resources/assets/js/libs/jquery.js',
    'resources/assets/js/libs/bootstrap.js',
    'resources/assets/js/libs/metisMenu.js',
    'resources/assets/js/sb-admin-2.js',
    'resources/assets/js/libs/jquery.js',
    'resources/assets/js/libs/scripts.js'

], 'public/js/libs.js');

package.json

{
  "private": true,
  "scripts": {
    "dev": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch-poll": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "hot": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "production": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },
  "devDependencies": {
    "axios": "^0.15.3",
    "bootstrap-sass": "^3.3.7",
    "jquery": "^3.1.1",
    "laravel-mix": "^0.8.1",
    "lodash": "^4.17.4",
    "vue": "^2.2.2"
  }
}

$ npm install
$ npm run dev
$ npm run watch

webpackはちょっと取っつきにくいイメージがありましたが、build inもありますし、そんなことありませんね。

Laravel upgradeの基本的な進め方

– まずlogin, authから確認
– upgrade後に基本動作から試していく
– packageもlaravelのヴァージョンに依存関係がある為、composer.jsonも必ず確認する(laravel collective)

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

$ php artisan route:list;

https://github.com/laravel-shift/laravel-5.3/blob/master/app/Http/Controllers/Auth/LoginController.php
Authフォルダの下にcontroller fileを追加
LoginController.php
ResetPasswordController.php
RegisterController.php
ForgotPasswordController.php

web.php

Route::auth();
Route::get('/logout', 'Auth\LoginController@logout');

LoginController.php

protected $redirectTo = '/';

web.php

Route::group(['middleware'=>'admin'], function(){

	Route::get('/admin', function(){
		return view('admin.index');
	});

	Route::resource('admin/users', 'AdminUsersController',['names'=>[
		'index'=>'admin.users.index',
		'create'=>'admin.users.create',
		'store'=>'admin.users.store',
		'edit'=>'admin.users.edit',
	]]);
	Route::resource('admin/posts', 'AdminPostsController', ['names'=>[
		'index'=>'admin.posts.index',
		'create'=>'admin.posts.create',
		'store'=>'admin.posts.store',
		'edit'=>'admin.posts.edit',
	]]);	
	Route::resource('admin/categories', 'AdminCategoriesController', ['names'=>[
		'index'=>'admin.categories.index',
		'create'=>'admin.categories.create',
		'store'=>'admin.categories.store',
		'edit'=>'admin.categories.edit',
	]]);	
	Route::resource('admin/media', 'AdminMediasController', ['names'=>[
		'index'=>'admin.media.index',
		'create'=>'admin.media.create',
		'store'=>'admin.media.store',
		'edit'=>'admin.media.edit',
	]]);

	Route::resource('admin/comments', 'PostCommentsController', ['names'=>[
		'index'=>'admin.comments.index',
		'create'=>'admin.comments.create',
		'store'=>'admin.comments.store',
		'edit'=>'admin.comments.edit',
	]]);
	Route::resource('admin/comments/replies', 'CommentRepliesController', ['names'=>[
		'index'=>'admin.replies.index',
		'create'=>'admin.replies.create',
		'store'=>'admin.replies.store',
		'edit'=>'admin.replies.edit',
	]]);
});

AdminUsersController
lists->pluckに変更

public function create()
    {
        //
        $roles = Role::pluck('name','id')->all();
        return view('admin.users.create', compact('roles'));
    }
$categories = Category::pluck('name', 'id')->all();

composer.json

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.3.*",
        "laravelcollective/html": "5.3.*"
    },

Middleware: kernel.php

protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'admin' => \App\Http\Middleware\Admin::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ];

$ php composer.phar require cviebrock/eloquent-sluggable:^4.0

$ php artisan vendor:publish –provider=”Cviebrock\EloquentSluggable\ServiceProvider”

フレームワークのアップデートは、アップデートに伴う変更点を一つ一つ潰していくのかと思っていましたが、そうではなく、まずupgradeして、挙動を一つ一つ確認しながらエラーを潰していく。発想が真逆でした。道理で、凄い大変そうにみえたわけだ。。

ただし、マイクロアプリケーションなら比較的すぐ終わりそうですが、大規模アプリケーションだと、テスト工数が結構かかりそうです。

Laravel Upgrade

– upgrade時には公式のドキュメントを読むと同時に、参考記事を探し、主な変更点を確認する
– 新しいversionをインストールして、folder構成の違いを確認する
– composer updateでエラーが出た場合は、コードを修正する

$ php artisan –version

### composer.jsonでupdate

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.3.*",
        "laravelcollective/html": "^5.2.0"
    },

### composer update
$ php composer.phar update

app/Providers/EventServiceProvider.php

public function boot()
    {
        parent::boot();

        //
    }

app/Providers/RouteServiceProvider.php

use Illuminate\Support\Facades\Route;
public function boot()
    {
        //

        parent::boot();
    }
public function map()
    {
        $this->mapWebRoutes();

        //
    }
protected function mapWebRoutes()
    {
        Route::group([
            'namespace' => $this->namespace, 'middleware' => 'web',
        ], function ($router) {
            require base_path('routes/web.php');
        });
    }

routes/web.php

Route::get('/', function () {
    return view('welcome');
});

routes/console.php

Artisan::command('inspire', function () {
    $this->comment(Inspiring::quote());
})->describe('Display an inspiring quote');

routes/api.php

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:api');

$ php composer.phar update
$ php artisan –version
$ php artisan route:list;

技術負債は後々問題になりやすいので、「じゃー新しいの作る?」となってしまわないよう、設計時によく考えておかないといけない。