明日から使えるLaravel テクニック

InnoCafe vol.18

@localdisk

自己紹介

 

松尾 大(まつお まさる)

 

  • http://twitter.com/localdisk
  • Laravelエンジニア養成読本
  • Laravelリファレンス

 

 

前置き

本スライドははLaravel 5.2を対象にしてます

 

http://slides.com/masarumatsuo/innocafe-18#/

JSON を返す

配列を返す

Route::get('/', function() {
    return ['foo', 'bar'];
});

Content-Type がちゃんと

 

application/json になる

Model を返す

Route::get('users', function() {
    // モデルファクトリー便利
    $user = factory(\App\User::class)->make();
    return $user;
});

解説

returnしてJSONでレスポンスさせるには以下の条件のいずれかに該当させる必要があります。

  • Jsonableを実装する
  • ArrayObjectを継承する
  • JsonSerializableを実装する
  • is_arrayがtrue

補足

  • 他のクラスもJSONで返したい
    • Response::jsonメソッドを使おう
    • ゴニョゴニョしたいならJsonableを実装してtoJsonメソッド実装しよう
  • XMLで返したい​
    • Responseマクロを使おう
  •  

イベントあれこれ

イベントの基本

  • イベントを発生(fire)させるところと実行(listen)させるところが分かれてる

  • 前者を 'Event' 、後者を 'Listner' と呼ぶ
  • 双方用意されて初めて効果を発揮する
  • この特性を利用して、LaravelにはModelやAuthとかに仕込まれている。便利。

既存のイベントを使う

# ロールバックされた時のリスナを作る
$ php artisan make:listener RollbackListner
 --event=Illuminate\Database\Events\TransactionRolledBack
<?php
namespace App\Listeners;
use Illuminate\Database\Events\TransactionRolledBack;
class RollbackListner
{
    public function handle(TransactionRolledBack $event)
    {
       // ロールバックされたクエリを参照できる
        dd($event->connection->getQueryLog());
    }
}

イベント + キュー

非同期イベント

  • イベントを非同期に処理する
    • メール配信諸々(ユーザー登録、エラー通知)
    • 画像がアップロードされたらリサイズしてクラウドストレージに保存
  • 重くて急がない処理に使う
  • 最近流行のマイクロサービス(サービス間の連携)とか
  • ドライバはSQSとかRedisとかが手軽だと思う

非同期イベント

php artisan make:event AsyncEvent
php artisan make:listener AsyncLister
 --event=App\\Events\\AsyncEvent
// ShouldQueue を implements するのがポイント
class AsyncLister implements ShouldQueue
{
}

認証と認可

Laravelの認証と認可

  • Laravel 5.0 までは色々機能が足らなかった
  • 5.1/5.2 でほとんど作りこまなくていいレベルまで来た
    • 5.1.11 で認可
    • 5.2 で MultiAuth、TokenGuard
      • TokenGuardは簡易的すぎるのでJWTのほうがよさげ

認証のセットアップ

php artisan make:auth

Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/auth/login.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/auth/register.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/auth/passwords/email.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/auth/passwords/reset.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/auth/emails/password.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/layouts/app.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/home.blade.php
Created View: /Users/localdisk/NetBeansProjects/five-point-two/resources/views/welcome.blade.php
Installed HomeController.
Updated Routes File.

MultiAuth

  • サービスを運用するにあたりテーブルは分けたい
    • 一般ユーザーと管理者では持つ情報がぜんぜん違う
  • 認証するテーブルを別にできる
    • 一般ユーザーは `users` 管理者は `admins` とか

MultiAuthやってみる

# -m つけるとマイグレーションファイルも作ってくれる
php artisan make:model Admin -m
class CreateAdminsTable extends Migration
{
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            // CreateUsersTable からコピペ
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password', 60);
            $table->rememberToken();
            $table->timestamps();
        });
    }
}

MultiAuthやってみる

<?php

return [
    'guards' => [
        // 追加
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    ],
    'providers' => [
        // 追加
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
    ],

MultiAuthやってみる

// モデルファクトリを追加
// database/factories/ModelFactory.php
$factory->define(App\Admin::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'password' => bcrypt(str_random(10)),
        'remember_token' => str_random(10),
    ];
});
➜  five-point-two php artisan tinker
Psy Shell v0.7.2 (PHP 7.0.4 — cli) by Justin Hileman
>>> factory(App\Admin::class)->create(['password' => bcrypt('secret')]);
=> App\Admin {#719
     name: "Mr. Sage McDermott",
     email: "kFeest@yahoo.com",
     updated_at: "2016-03-29 06:45:52",
     created_at: "2016-03-29 06:45:52",
     id: 2,
   }

MultiAuthやってみる

// http://localhost:8000/admin
Route::group(['prefix' => 'admin'], function() {
    Route::get('login', function() {
        // ビューはコピる
        return view('admin.login');
    });
    Route::post('login', function(\Illuminate\Http\Request $request) {
        $credentials = $request->only(['email', 'password']);
        // guard メソッドの引数に `admin` を入れるのがポイント
        $result = Auth::guard('admin')->attempt($credentials);
        dd($result);
    });
});

認証と認可

認証…ネットワークやサーバへ接続する際に本人性をチェックし、正規の利用者であることを確認する方法。

 

認可…認証によって確認された利用者を識別して、アクセス権限の制御を行い、利用者ごとに固有のサービスを提供すること。

  • http://www.atmarkit.co.jp/ait/articles/0401/01/news067.html
  • http://www.atmarkit.co.jp/ait/articles/0401/01/news068.html

Laravelの認可

Gateファサードを使ってみよう

➜  five-point-two php artisan make:model Profile -m
Model created successfully.
Created Migration: 2016_03_29_083825_create_profiles_table
➜  five-point-two php artisan migrate
Migrated: 2016_03_29_083825_create_profiles_table
$factory->define(App\Profile::class, function (Faker\Generator $faker) {
    return [
        'nickname' => $faker->name,
        'user_id'  => factory(\App\User::class)->create()->id,
    ];
});

Laravelの認可

➜  five-point-two php artisan tinker
>>> factory(App\Profile::class)->create();
=> App\Profile {#708
     nickname: "Delbert Rau",
     user_id: 2,
     updated_at: "2016-03-29 08:44:30",
     created_at: "2016-03-29 08:44:30",
     id: 1,
   }

Laravelの認可

Gateファサードを使ってみよう

<?php
class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);
        // ユーザーIDとプロフィールIDが一致すればOK
        \Gate::define('update-profile', function($user, $profile){
            return $user->id === $profile->user_id;
        });
       
    }
}

Laravelの認可

Gateファサードを使ってみよう

<?php
class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);
        // ユーザーIDとプロフィールIDが一致すればOK
        \Gate::define('update-profile', function($user, $profile){
            return $user->id === $profile->user_id;
        });
       
    }
}

Demo

明日から使えるLaravelテクニック

By Masaru MATSUO

明日から使えるLaravelテクニック

明日から使えるLaravelテクニック

  • 3,495