michimani.net

Laravel5.1からLaravel5.5にアップグレードしたときに修正した部分まとめ

2018-01-30

以前にも少し書きましたが、それ以外にも色々と修正した部分があったので、以前に書いた内容も含めてあらためて書きます。

※環境によっては下記内容以外にも修正が必要な場合があります。詳しくはLaravel公式のアップグレードガイドを参照してください。

コア部分、設定関係

composer.json の書き換え

@@ -5,15 +5,23 @@
     "license": "MIT",
     "type": "project",
     "require": {
-        "php": ">=5.5.9",
-        "laravel/framework": "5.1.*",
+        "php": ">=7.0.0",
+        "fideloper/proxy": "~3.3",
+        "laravel/framework": "5.5.*",
+        "laravel/tinker": "~1.0",
         "doctrine/dbal": "^2.5"
     },
     "require-dev": {
+        "filp/whoops": "~2.0",
         "fzaninotto/faker": "~1.4",
         "mockery/mockery": "0.9.*",
-        "phpunit/phpunit": "~4.0",
-        "phpspec/phpspec": "~2.1"
+        "phpunit/phpunit": "~6.0"
+    },
+    "extra": {
+        "laravel": {
+            "dont-discover": [
+            ]
+        }
     },
     "autoload": {
         "classmap": [
@@ -31,18 +39,14 @@
     },
     "scripts": {
         "post-root-package-install": [
-            "php -r \"copy('.env.example', '.env');\""
+            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
         ],
         "post-create-project-cmd": [
-            "php artisan key:generate"
-        ],
-        "post-install-cmd": [
-            "Illuminate\\Foundation\\ComposerScripts::postInstall",
-            "php artisan optimize"
+            "@php artisan key:generate"
         ],
-        "post-update-cmd": [
-            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
-            "php artisan optimize"
+        "post-autoload-dump": [
+            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
+            "@php artisan package:discover"
         ]
     },
     "config": {

フィルタ を ミドルウェアに書き換え

Controllerのコンストラクタなどで $this->beforeFilter() といった形でフィルタを使用している場合は、ミドルウェアへの書き換えが必要です。

before

<?php
public function __construct()
{
	parent::__construct();

	$this->beforeFilter("@hogehoge");
}

public function hogehoge()
{
    // 処理
}

after

<?php
public function __construct()
{
	parent::__construct();

	$this->middleware(function ($request, $next) {
        // 処理

        return $next($request);
    });
}

Kernel.php の書き換えと、ミドルウェアの追加

app/Http/Kernel.phpでミドルウェアを設定していましたが、書き方が変更になったのと、新たにミドルウェアが追加されているのでその対応です。

@@ -9,16 +9,38 @@ class Kernel extends HttpKernel
     /**
      * The application's global HTTP middleware stack.
      *
+     * These middleware are run during every request to your application.
+     *
      * @var array
      */
     protected $middleware = [
         \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
-        \App\Http\Middleware\EncryptCookies::class,
-        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
-        \Illuminate\Session\Middleware\StartSession::class,
-        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
-        \App\Http\Middleware\VerifyCsrfToken::class,
+        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
+        \App\Http\Middleware\TrimStrings::class,
+        // \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
+        \App\Http\Middleware\TrustProxies::class,
+    ];
+
+    /**
+     * The application's route middleware groups.
+     *
+     * @var array
+     */
+    protected $middlewareGroups = [
+        'web' => [
+            \App\Http\Middleware\EncryptCookies::class,
+            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+            \Illuminate\Session\Middleware\StartSession::class,
+            // \Illuminate\Session\Middleware\AuthenticateSession::class,
+            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
+            \App\Http\Middleware\VerifyCsrfToken::class,
+            \Illuminate\Routing\Middleware\SubstituteBindings::class,
+        ],
+        'api' => [
+            'throttle:60,1',
+            'bindings',
+        ],
     ];

     /**
@@ -27,8 +49,11 @@ class Kernel extends HttpKernel
      * @var array
      */
     protected $routeMiddleware = [
-        'auth' => \App\Http\Middleware\Authenticate::class,
+        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
         'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
+        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
+        'can' => \Illuminate\Auth\Middleware\Authorize::class,
         'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
+        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
     ];
 }

ここで、新たに追加されている ConvertEmptyStringsToNull ですが、これが少し曲者です。
このミドルウェアの処理は、formで送信される値が空白("")のものは、null として扱う というものです。この結果、今まで空白でpostされてDBの nullableでない カラムに空白が保存されていたようなところで、dbエラーが発生してしまいます。

対処方法としては、この ConvertEmptyStringsToNull をコメントアウトするか、対象のカラムを nullable にするか、です。

更に、新たに下記のファイルを追加します。

これらはGithubからそのまま持ってきます。

https://github.com/laravel/laravel

EventServiceProvider.php と RouteServiceProvider.php の書き換え

それぞれ boot() の引数が変更されているので修正します。

app/Providers/EventServiceProvider.php

@@ -24,9 +24,9 @@ class EventServiceProvider extends ServiceProvider
      * @param  \Illuminate\Contracts\Events\Dispatcher  $events
      * @return void
      */
-    public function boot(DispatcherContract $events)
+    public function boot()
     {
-        parent::boot($events);
+        parent::boot();

         //
     }

app/Providers/RouteServiceProvider.php
RouteServiceProvider.phpについてはboot()以外にも変わっている部分があります。こちらも Github のソースを見ながら修正します。

@@ -1,44 +1,63 @@
 <?php
-
 namespace App\Providers;
-
-use Illuminate\Routing\Router;
+use Illuminate\Support\Facades\Route;
 use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
-
 class RouteServiceProvider extends ServiceProvider
 {
     /**
-     * This namespace is applied to the controller routes in your routes file.
+     * This namespace is applied to your controller routes.
      *
      * In addition, it is set as the URL generator's root namespace.
      *
      * @var string
      */
     protected $namespace = 'App\Http\Controllers';
-
     /**
      * Define your route model bindings, pattern filters, etc.
      *
-     * @param  \Illuminate\Routing\Router  $router
      * @return void
      */
-    public function boot(Router $router)
+    public function boot()
     {
         //
-
-        parent::boot($router);
+        parent::boot();
     }
-
     /**
      * Define the routes for the application.
      *
-     * @param  \Illuminate\Routing\Router  $router
      * @return void
      */
-    public function map(Router $router)
+    public function map()
     {
-        $router->group(['namespace' => $this->namespace], function ($router) {
-            require app_path('Http/routes.php');
-        });
+        $this->mapApiRoutes();
+        $this->mapWebRoutes();
+        //
+    }
+    /**
+     * Define the "web" routes for the application.
+     *
+     * These routes all receive session state, CSRF protection, etc.
+     *
+     * @return void
+     */
+    protected function mapWebRoutes()
+    {
+        Route::middleware('web')
+             ->namespace($this->namespace)
+             ->group(base_path('routes/web.php'));
+    }
+    /**
+     * Define the "api" routes for the application.
+     *
+     * These routes are typically stateless.
+     *
+     * @return void
+     */
+    protected function mapApiRoutes()
+    {
+        Route::prefix('api')
+             ->middleware('api')
+             ->namespace($this->namespace)
+             ->group(base_path('routes/api.php'));
     }

ルーティングファイルの変更

Laravel5.1では app/Http/routes.php にルーティングの設定を書いていましたが、5.5では以下の2つのファイルで設定します。

とりあえず今までの app/Http/routes.phproutes/web.php にリネームします。
routes/api.php については Github から取得します。

app/config/app.php の書き換え

@@ -2,6 +2,8 @@

 return [

+    'env' => env('APP_ENV', 'production'),
+
     /*
     |--------------------------------------------------------------------------
     | Application Debug Mode
@@ -120,7 +122,6 @@ return [
         Illuminate\Bus\BusServiceProvider::class,
         Illuminate\Cache\CacheServiceProvider::class,
         Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
-        Illuminate\Routing\ControllerServiceProvider::class,
         Illuminate\Cookie\CookieServiceProvider::class,
         Illuminate\Database\DatabaseServiceProvider::class,
         Illuminate\Encryption\EncryptionServiceProvider::class,

app/config/auth.php の書き換え

デフォルトから特に編集していなければ、 Github の内容をそのままコピペすればOKです。

@@ -1,67 +1,95 @@
-
-    'driver' => 'eloquent',
-
+    'defaults' => [
+        'guard' => 'web',
+        'passwords' => 'users',
+    ],

-
-    'model' => App\User::class,
-
+    'guards' => [
+        'web' => [
+            'driver' => 'session',
+            'provider' => 'users',
+        ],
+        'api' => [
+            'driver' => 'token',
+            'provider' => 'users',
+        ],
+    ],

-
-    'table' => 'users',
-
+    'providers' => [
+        'users' => [
+            'driver' => 'eloquent',
+            'model' => App\User::class,
+        ],
+        // 'users' => [
+        //     'driver' => 'database',
+        //     'table' => 'users',
+        // ],
+    ],

-
-    'password' => [
-        'email'  => 'emails.password',
-        'table'  => 'password_resets',
-        'expire' => 60,
+    'passwords' => [
+        'users' => [
+            'provider' => 'users',
+            'email' => 'auth.emails.password',
+            'table' => 'password_resets',
+            'expire' => 60,
+        ],
     ],

sessionsテーブルにカラム追加

セッションをDBに保持する設定にしている場合、sessionsテーブルにカラムの追加が必要です。

$ php artisan make:migration alter_add_sessions
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AlterAddSession extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('sessions', function($t){
            $t->integer('user_id')->nullable();
            $t->integer('ip_address')->nullable();
            $t->string('user_agent');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('sessions', function($t){
            $t->dropColumn(['user_id', 'ip_address', 'user_agent']);
        });
    }
}

アプリケーションレベルの細かい変更

クエリビルダーの lists()

lists() は廃止されたため、pluck() に変更が必要です。使用方法、返り値は一緒です。

URL生成の url()

ルートパスを得るために url() としていたところは url('') と変更が必要です。

\URL::Schema()

関数名が Schema から Scheme に変更になっています。
強制的にHTTPSにする処理を実装していると使用しているかと思いますが、開発環境が非SSL環境だと本番に反映してからでないと気付けない場合があります。

PHPのバージョンについて

Laravel5.5ではPHP7.0以上が必須となっていますが、これは合っているようで間違っています。
2018年1月時点での最新のLaravelのバージョンは 5.5.31 となっていますが、このバージョンを使用する場合には PHP7.1 が必須となります。
5.5.31で composer install を実行すると、下記のようなエラーとなります。


$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for doctrine/annotations v1.6.0 -> satisfiable by doctrine/annotations[v1.6.0].
    - doctrine/annotations v1.6.0 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 2
    - Installation request for doctrine/cache v1.7.1 -> satisfiable by doctrine/cache[v1.7.1].
    - doctrine/cache v1.7.1 requires php ~7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 3
    - Installation request for doctrine/collections v1.5.0 -> satisfiable by doctrine/collections[v1.5.0].
    - doctrine/collections v1.5.0 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 4
    - Installation request for doctrine/common v2.8.1 -> satisfiable by doctrine/common[v2.8.1].
    - doctrine/common v2.8.1 requires php ~7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 5
    - Installation request for doctrine/dbal v2.6.3 -> satisfiable by doctrine/dbal[v2.6.3].
    - doctrine/dbal v2.6.3 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 6
    - Installation request for doctrine/inflector v1.3.0 -> satisfiable by doctrine/inflector[v1.3.0].
    - doctrine/inflector v1.3.0 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 7
    - Installation request for symfony/css-selector v4.0.3 -> satisfiable by symfony/css-selector[v4.0.3].
    - symfony/css-selector v4.0.3 requires php ^7.1.3 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 8
    - Installation request for symfony/event-dispatcher v4.0.3 -> satisfiable by symfony/event-dispatcher[v4.0.3].
    - symfony/event-dispatcher v4.0.3 requires php ^7.1.3 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 9
    - Installation request for doctrine/instantiator 1.1.0 -> satisfiable by doctrine/instantiator[1.1.0].
    - doctrine/instantiator 1.1.0 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
  Problem 10
    - doctrine/inflector v1.3.0 requires php ^7.1 -> your PHP version (7.0.25) does not satisfy that requirement.
    - laravel/framework v5.5.31 requires doctrine/inflector ~1.1 -> satisfiable by doctrine/inflector[v1.3.0].
    - Installation request for laravel/framework v5.5.31 -> satisfiable by laravel/framework[v5.5.31].

Laravelのコアで使用している doctorine がPHP7.1必須のようです。

http://www.doctrine-project.org/2017/07/25/php-7.1-requirement-and-composer.html

対策としては、PHPのバージョンを7.1に上げるのが一番良い。が、簡単には上げられない環境もあるので、その場合は、composer.jsonでPHPのバージョンを指定すればいい(らしい)。

参考: doctrine/dbal:2.6 でPHP7.1が必要になった時の対策

まとめ

とりあえずこれで2020年までは気持ち的には安心ですが、今後は細かく対応を進めていって、今回みたいな一気にアップグレードをする必要がにないようにしたいです。


comments powered by Disqus