[Laravel] 5.8がリリースされました

laravel/frameworkのバージョン5.8がリリースされました。追加された機能について確認します。

Release

EloquentクラスにHasOneThrough()メソッドが追加されました

関連するリレーションを経由したリレーションを操作できます。

たとえば、SupplierモデルにAccountモデルが1つあり、AccountモデルにAccountHistoryモデルが1つあるとします。

Accountモデルを通じてSupplierAccountHistoryを1件するには、hasOneThroughリレーションを使用します。

Schema:

// suppliers table
Schema::create('suppliers', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('name');
    $table->timestamps();
});

// accounts table
Schema::create('accounts', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->bigInteger('supplier_id');
    $table->string('email');
    $table->timestamps();
});

// account_histories table
Schema::create('account_histories', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->bigInteger('account_id');
    $table->string('sentence');
    $table->timestamps();
});

hasOneThrough Model:

// App\Supplier class
/**
 * Get the account history for the supplier.
 */
public function accountHistory()
{
    return $this->hasOneThrough(AccountHistory::class, Account::class);
}

$supplier->accountHistory;

Result:

{
    "id": 1,
    "account_id": 1,
    "content": "Officia quas velit minus explicabo quibusdam a.",
    "created_at": "2019-02-27 01:52:21",
    "updated_at": "2019-02-27 01:52:21",
    "laravel_through_key": 1
}

// select * from `suppliers` where `suppliers`.`id` = 1 limit 1
// select `account_histories`.*, `accounts`.`supplier_id` as `laravel_through_key` from `account_histories` inner join `accounts` on `accounts`.`id` = `account_histories`.`account_id` where `accounts`.`supplier_id` = 1 limit 1

また、Supplierの全てのAccountHistoryを取得する場合にはhasManyThrough()リレーションを使用します。

hasManyThrough Model:

// App\Supplier class
/**
 * Get the account histories for the supplier.
 */
public function accountHistories()
{
    return $this->hasManyThrough(AccountHistory::class, Account::class);
}

$supplier->accountHistories;

Result:

[
    {
        "id": 1,
        "account_id": 1,
        "content": "Officia quas velit minus explicabo quibusdam a.",
        "created_at": "2019-02-27 01:52:21",
        "updated_at": "2019-02-27 01:52:21",
        "laravel_through_key": 1
    },
    {
        "id": 2,
        "account_id": 2,
        "content": "Qui ut optio est voluptatem dolores voluptatem tempore.",
        "created_at": "2019-02-27 01:52:21",
        "updated_at": "2019-02-27 01:52:21",
        "laravel_through_key": 1
    },

    ...

    {
        "id": 201,
        "account_id": 1,
        "content": "Qui odio excepturi magni est quisquam.",
        "created_at": "2019-02-27 01:52:22",
        "updated_at": "2019-02-27 01:52:22",
        "laravel_through_key": 1
    },
    {
        "id": 202,
        "account_id": 2,
        "content": "Sed nesciunt architecto est voluptas officiis esse voluptatem.",
        "created_at": "2019-02-27 01:52:22",
        "updated_at": "2019-02-27 01:52:22",
        "laravel_through_key": 1
    }
]

// select * from `suppliers` where `suppliers`.`id` = 1 limit 1
// select `account_histories`.*, `accounts`.`supplier_id` as `laravel_through_key` from `account_histories` inner join `accounts` on `accounts`.`id` = `account_histories`.`account_id` where `accounts`.`supplier_id` = 1

モデルのPolicyが自動検出されるようになりました

v5.7までのPolicyの利用にはAuthServiceProviderへの手動登録が必要でしたが、v5.8からは自動で登録されるようになります。

自動登録を行うには、クラス名をモデル名 + Policyとし、app/policiesディレクトリへ配置するという命名規則に従う必要があります。

また、独自の命名規則を使用する場合にはGateクラスのguessPolicyNameUsing()メソッドを利用して拡張することができます。

// app/Providers/AuthServiceProvider.php

public function boot()
{
    $this->registerPolicies();

    Gate::guessPolicyNameUsing(function ($modelClass) {
        $policyClass = class_basename($modelClass) . 'Authorizer';

        return "App\\Policies\\{$name}";
    });
}

Cacheの仕様がPSR-16に準拠されました

以下のキャッシュメソッドに渡していた整数の引数の値が分数から秒数へ変更されました。

  • put
  • putMany
  • add
  • remember
  • setDefaultCacheTime

引数としてDateTimeクラス(Carbonクラス等の拡張クラス含む)を渡している場合には変更はありません。

// Laravel 5.7 - Store item for 30 minutes...
Cache::put('foo', 'bar', 30);

// Laravel 5.8 - Store item for 30 seconds...
Cache::put('foo', 'bar', 30);

// Laravel 5.7 / 5.8 - Store item for 30 seconds...
Cache::put('foo', 'bar', now()->addSeconds(30));

Broadcastに複数の認証が指定可能になりました

以前のリリースでは、BroadcastChannelはアプリケーションのデフォルト認証を介してユーザを認証していました。

Laravel 5.8以降では、通知要求を認証するための複数の認証を割り当てることができます。

Broadcast::channel('channel', function() {
    // ...
}, ['guards' => ['web', 'admin']])

API Tokenの認証にSHA256ハッシュのサポートが追加されました

プレーンテキストTokenを格納するよりもセキュリティが向上します。

利用するにはconfig/auth.phphashの利用を許可します。

'api' => [
    'driver' => 'token',
    'provider' => 'users',
    'hash' => true,
],

また、API Tokenの作成はユーザー登録時には行わず、アプリケーション内に独自のAPIトークン管理ページを実装する必要があります。

このページでは、ユーザーが自分のAPI Tokenを初期化して更新できるようにする必要があります。

ユーザーのTokenの初期化または更新が必要な場合は、Tokenのハッシュコピーをデータベースに格納し、Tokenのプレーンテキストコピーを一度表示するためにクライアントに返す必要があります。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Str;
use Illuminate\Http\Request;

class ApiTokenController extends Controller
{
    /**
     * Update the authenticated user's API token.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function update(Request $request)
    {
        $token = Str::random(60);

        $request->user()->forceFill([
            'api_token' => hash('sha256', $token),
        ])->save();

        return ['token' => $token];
    }
}

メールアドレスに対するバリデーションが改善されました

Scheduleを実行するタイムゾーンの指定が可能になりました

timezone()メソッドを使ってスケジュールされたタスクのタイムゾーンを指定できます。

$schedule->command('inspire')
         ->hourly()
         ->timezone('America/Chicago');

また、すべてのスケジュールされたタスクに対して同じタイムゾーンを指定する場合には、\App\Console\KernelクラスのscheduleTimezone()メソッドを利用して一律に設定が可能です。

/**
 * Get the timezone that should be used by default for scheduled events.
 *
 * @return \DateTimeZone|string|null
 */
protected function scheduleTimezone()
{
    return 'America/Chicago';
}

Pivotモデルの更新時にEloquentモデルイベントが発行されうようになりました

Artisanクラスのcall()メソッドの引数問題が改善されました

Laravelの以前のリリースでは、コマンドのオプションはメソッドの2番目の引数として配列を介して渡されていました。

use Illuminate\Support\Facades\Artisan;

Artisan::call('migrate:install', ['database' => 'foo']);

しかし、Laravel 5.8では、オプションを含むコマンド全体をメソッドの最初の文字列引数として渡すことができます。

Artisan::call('migrate:install --database=foo');

テスト時のMockSpyに関するヘルパーメソッドが追加されました

モックオブジェクトをより便利にするために、新しいモックメソッドとスパイメソッドが基本のLaravelテストケースクラスに追加されました。

これらのメソッドは、モッククラスを自動的にコンテナにバインドします。

// Laravel 5.7
$this->instance(Service::class, Mockery::mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
}));

// Laravel 5.8
$this->mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
});

Resourcesクラスを利用してDatabaseCollectionのレスポンスを行う際にkeyをカスタマイズできるようになりました

コレクションのキーを保存するかどうかを示すpreserveKeysプロパティをリソースクラスに追加できるようになりました。

デフォルトでは、そして以前のLaravelリリースとの一貫性を保つために、キーはデフォルトでリセットされます。

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class User extends JsonResource
{
    /**
     * Indicates if the resource's collection keys should be preserved.
     *
     * @var bool
     */
    public $preserveKeys = true;
}

preserveKeysプロパティが未設定の場合には、コレクションキーは保持されます。

use App\User;
use App\Http\Resources\User as UserResource;

Route::get('/user', function () {
    return UserResource::collection(User::all()->keyBy->id);
});

EloquentモデルのorWhere()メソッドがHigherOrderに対応しました

Laravelの以前のリリースでは、論理和演算子を介して複数のEloquentモデルスコープを組み合わせるには、Closureコールバックを使用する必要がありました。

// scopePopular and scopeActive methods defined on the User model...
$users = App\User::popular()->orWhere(function (Builder $query) {
    $query->active();
})->get();

Laravel 5.8では、クロージャを使用せずにこれらのスコープをスムーズに連鎖させることができるHigherOrderorWhereメソッドが導入されました。

$users = App\User::popular()->orWhere->active()->get();

Artisan Serveコマンドでのビルドインサーバーを複数起動可能になりました

Laravelの以前のリリースでは、Artisanのserveコマンドはポート8000でビルドインサーバーを提供していました。

別のアプリケーションでserveコマンドを実行した場合には、既にポートがlistenされているため、コマンドはエラーを投げていました。

Laravel 5.8以降、serveはポート8009までの使用可能なポートをスキャンするようになりました。これにより、一度に複数のアプリケーションに対応できます。

Bladeファイルへの追跡が可能になりました

Bladeテンプレートをコンパイルするとき、Laravelはコンパイル済みファイルの先頭に元のBladeテンプレートへのパスを含むコメントを追加するようになりました。

CacheSessionのドライバにDynamoDBが利用可能になりました

DynamoDBをドライバとして利用する場合にはconfig/cache.phpを設定します。

'dynamodb' => [
    'driver' => 'dynamodb',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_REGION', 'us-east-1'),
    'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
],

Carbon 2.0がサポートされました

Pheanstalk 4.0がサポートされました

Upgrade

MySQLでJson型のカラムの結果を受け取る場合に引用符が付与されなくなりました

MySQLとMariaDBを使用している場合、クエリービルダーは引用符で囲まれていないJSON値を返すようになりました。

この動作は、サポートされている他のデータベースと一貫性があります。

その結果、 ->>`演算子はサポートされなくなり、必要なくなりました。

$value = DB::table('users')->value('options->language');

dump($value);

// Laravel 5.7...
'"en"'

// Laravel 5.8...
'en'

Illuminate/Events/Dispatcherクラスのfire()メソッドが削除されました

代わりにdispatch()メソッドを使用してください。

SoftDeleteを利用したモデルのdeleted_atカラムがキャストされるようになりました

EloquentモデルがSoftDeletesトレイトを使用するとき、deleted_atプロパティは自動的にCarbonインスタンスにキャストされます。

この動作を無効にするには、そのプロパティのカスタムアクセサを作成するか、手動でcasts属性に追加します。

protected $casts = ['deleted_at' => 'string'];

MarkDownメールのファイルディレクトリが変更されました

/resources/views/vendor/mail/markdownへ変更されました。

以前にvendor:publishを実行してファイルをコピーしている場合には手動で変更する必要があります。

str_*およびarray_*に関するヘルパーが非推奨になりました

これらのヘルパーは削除される予定なので、代わりにIlluminate\Support\ArrおよびIlluminate\Support\Strクラスを使用してください。

ヘルパーが必要な場合は、laravel/helpersパッケージを追加でインストールしてください。

NexmoおよびSlack への通知クラスが外部パッケージへと変更されました

アプリケーションでこれらのチャンネルを使用するには、以下のパッケージが必要です。

composer require laravel/nexmo-notification-channel
composer require laravel/slack-notification-channel

詳しい変更については以下を確認してください。

Release Notes - Laravel - The PHP Framework For Web Artisans

© Xzxzyzyz