
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、前回の記事「Laravel 5.7 のEmail Verification(本登録メール)の使い方」では、リリースされたばかりのLaravel 5.7
から新機能のひとつをお届けしました。
ということで、今回はLaravel 5.7 で追加されたその他の新しい機能をまとめてみたいと思います。
ぜひ効率的なサイト構築に役立ててください。
目次 [非表示]
フォルダ構造が変更になった
小さな変更ですが、Laravel 5.7
では、resources
内フォルダ構造が平坦化されました。
バージョン 5.6 の場合は以下のようにassets
が存在していました。
それが今回のアップデートで、以下のように平坦な構造になっています。
Eloquentモデルのエラーメッセージが改善された
例えば以下のような存在しないメソッドを実行する場合です。
\App\User::nothing(); // nothing()は存在しない
これを実行するとLaravel 5.6
の場合は以下のようなエラーを表示していました。
エラー内容を見てみると、Builder::nothing()
となっています。「does not exist」と書かれているので、何かが存在しないことは分かるものの肝心の「どこの?」が抜けてしまっていました。
これがLaravel 5.7
では以下のように改善されています。
「App\User::nothing()
というまだ定義されていないメソッドが呼ばれました。」
と、どこの何でエラーが発生しているかを教えてくれるようになりました。
Pagination(ページリンク)で両サイドの件数が指定できるようになった
例えば、以下のようなコードを実行すると、通常のページ送りリンクが表示されます。(見た目はCSSで装飾しています)
echo \App\User::paginate(10)->links();
そして、今回追加されたonEachSide($count)
を使うと、この中央の両サイドにあるリンク数を指定することができます。
実際の例で見てみましょう。
echo \App\User::paginate(10)->onEachSide(1)->links();
なお、デフォルト値は3
です。
独自Artisanコマンドのテストができるようになった
テスト用の独自コマンドを作る
まず、TestCommand
という独自コマンドを作ってみましょう。
php artisan make:command TestCommand
すると、app/Console/Commands
にTestCommand.php
が作成されるので、この中に、
- 好きな食べ物を答えてもらう
- 好きな音楽ジャンルを選んでもらう
という2つの質問と、その結果を表示するというコードを追加します。
コードは以下のようになります。(太字の部分が追加/変更した場所です)
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TestCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'テストコマンドです。';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$food = $this->ask('好きな食べ物は?');
$music = $this->choice('どの音楽が好きですか?', [
'ポップ',
'ロック',
'クラシック',
]);
$this->line('好きな食べ物は「'. $food .'」、音楽は「'. $music .'」です。');
}
}
では、php artisan command:test
を実行してみましょう。
まず好きな食べ物を答え、
音楽のジャンルを選ぶと、
結果がこのように表示されます。
コマンドをテストする
では、ここからがメインの「Artisanコマンドのテスト」です。実行環境として、PHPUnit
を使います。
では、すでに存在しているtests/Unit/ExampleTest.php
を使ってテストを作成してみましょう。
コードは以下になります。
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->artisan('command:test')
->expectsQuestion('好きな食べ物は?', 'カレー')
->expectsQuestion('どの音楽が好きですか?', 'ロック')
->expectsOutput('好きな食べ物は「カレー」、音楽は「ロック」です。');
}
}
まず、テスト実行部分1行目の
$this->artisan('command:test')
で、先ほど作成した独自コマンドcommand:test
を実行し、
->expectsQuestion('好きな食べ物は?', 'カレー')
->expectsQuestion('どの音楽が好きですか?', 'ロック')
2つの期待する答えがあっているかチェックします。
->expectsOutput('好きな食べ物は「カレー」、音楽は「ロック」です。')
そして、最後に表示が正しいかチェックします。
では、以下のコマンドでPHPUnit
で実行してみましょう。
php vendor/phpunit/phpunit/phpunit
うまくテストを通過したようです。
では、わざと「ロック」を「ポップ」に変更して実行してみます。
->expectsQuestion('どの音楽が好きですか?', 'ポップ')
この場合、以下のようなエラーが表示されることになります。
アウトプットは、
好きな食べ物は「カレー」、音楽は「ロック」です。
が表示されていませんよ!と言っています。
変数の中身を確認するDump-Serverが追加された
dump-server
を使うために、まず以下の起動コマンドを実行します。
php artisan dump-server
すると以下のような内容が表示されます。(終了したい場合はCtr+C
です。)
ではこの状態で以下コードをブラウザから実行してみましょう。
$test = 'xxxxx';
dump($test);
すると、起動中のDump-Serverが以下のような情報を表示してくれます。
GET http://l57.test/dump_server
-------------------------------
------------ -----------------------------------------
date Thu, 06 Sep 2018 19:12:43 +0000
controller "HomeController"
source HomeController.php on line 12
file app/Http/Controllers/HomeController.php
------------ -----------------------------------------
"xxxxx"
このように、コードを実行している途中に変数の中身をチェックすることができるわけですね。
つまり、以下のようにループごとに変数の中身が変わってしまっても、Dump-Serverを起動していれば変数の中身がどのように変化しているか、その都度表示してくれるので、バグ修正などに役立つことでしょう。
for($i = 0 ; $i < 12 ; $i++) {
dump($i);
}
action()にクラスを指定してURLを取得できるようになった
まず、web.php
に以下のようなRouteがあるとします。
Route::get('/posts', 'PostsController@index');
Route::get('/posts/{id}', 'PostsController@show');
そして、Laravel 5.6
までは、action()
を使って次のようにURLを取得するこができていました。
$url = action('PostsController@index');
$url = action('PostsController@show', ['id' => 1]);
これが 5.7
からは::class
を使って直接指定することができるようになりました。
$url = action([PostsController::class, 'index']);
$url = action([PostsController::class, 'show'], ['id' => 1]);
Email Verificationで本登録メールを送信する
これは前回記事、Laravel 5.7 のEmail Verification(本登録メール)の使い方で、詳しく紹介しているのでそちらをご覧ください。
Filesystemにストリーム用のメソッドが追加された
テストとして、storage/app/public
にtest_1.zip
というファイルを用意し、これをtest_2.zip
という名前でローカル(つまり、storage/app
フォルダ)に保存してみます。
$stream = \Storage::disk('public')->readStream('test_1.zip');
\Storage::disk('local')->writeStream('test_2.zip', $stream);
※ 実際の運用ではS3
やSFTP
などを使うことになるでしょう。
Notificationの言語を指定できるようになった
サンプルとして、日本語環境でフランス語のメッセージを送信してみましょう。config/app.php
のlocale
をja
に設定しておいてください。
翻訳データをつくる
まず、resources/lang
内に翻訳データを作成します。
では、以下2つのフォルダにそれぞれの翻訳データを作成しましょう。
(resources/lang/ja)
<?php
return [
'subject' => '注文を受け付けました',
'details' => '注文内容:'
];
(resources/lang/fr)
<?php
return [
'subject' => 'Nous avons accepté votre commande',
'details' => 'Détails de la commande: '
];
ファイル構造はこのようになります。
Notificationを実装する
Ordered
という名前のNotification
を作成します。
php artisan make:notification Ordered
コマンドを実行したら、app/Notifications/Order.php
を開いてtoMail()の中身を以下のように変更してください。
public function toMail($notifiable)
{
return (new MailMessage)
->subject(trans('ordered.subject')) // ここがさっきの翻訳データ
->line(trans('ordered.details'));// ここがさっきの翻訳データ
}
Notificationを実行する
では、まずは通常どおりメッセージを送信してみましょう。
<?php
namespace App\Http\Controllers;
use App\Notifications\Ordered;
class HomeController extends Controller
{
public function notification_localization() {
$user = \App\User::first();
$user->notify(new Ordered()); // 日本語メッセージ
}
すると、以下のようなメッセージが送信されました。
※ ちなみにHello!などの部分は、Notification
の方で日本語化する必要があります。詳しくは、【Laravel5.6】インストール直後にやること3点をご覧ください。
では、次にフランス語を指定してメッセージ送信してみましょう。
$user->notify(
(new Ordered())->locale('fr')
);
うまくフランス語に切り替わってメッセージ送信することができました。
この方法を使えば動的にNotification
の言語を切り替えることができますね。
(2018年10月9日追記)
さらに、Laravel 5.7.7
からはUser
モデル内でデフォルトの言語を指定できるようになりました。
この機能を利用するには、まずusers
テーブルに言語情報を登録するlocale
フィールドを追加してマイグレーションします。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('locale');
$table->rememberToken();
$table->timestamps();
});
}
テーブル構成は以下のようになります。
そして、app/User.php
にHasLocalePreference
を追加します。
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Authenticatable implements MustVerifyEmail, HasLocalePreference
{
use Notifiable;
public function preferredLocale()
{
return $this->locale; // localeフィールドの言語
}
// 省略
}
以上で設定は終わりです。
後は、言語をわざわざ指定しなくてもusers
テーブルから自動的に対象となる言語に切り替えられて通知(メール送信)されることになります。
$user->notify(new Ordered()); // ユーザーごとの言語で送信
※適用されるのは以下の赤枠のデータです。
もちろん以下のように言語を指定した場合はそちらが優先されます。
$user->notify(
(new Ordered())->locale('en') // 英語で送信される
);
おわりに
今回追加された新しい機能の中で地味に効果を発揮しそうなのが、「エラーメッセージの改善」ですね。
ひとつのエラーだけならそれほど時間の短縮にはならないかもしれませんが、これが何十、何百と重ねていくとショートカットできる時間も積もり積もって山となりそうだからです。
あとは、やっぱりDump-Serverですかね。
変数内の状況を全て確認できるので、「どのデータのときにエラーが発生しているか」をチェックしやすくなるのではないでしょうか。
さすがLaravel。
これからもすばらしい作品を楽しみにしています!
ではでは〜。