$30 off During Our Annual Pro Sale. View Details »

Laravel のメール認証の内部実装を掘り下げる - PHPerKaigi 2021

Laravel のメール認証の内部実装を掘り下げる - PHPerKaigi 2021

スライド内で紹介した設計方針で実装したサンプルコードも公開しています。
興味のある方はこちらも是非ご覧ください!

https://github.com/hamakou108/laravel-separate-user-sample

hamakou108

March 27, 2021
Tweet

More Decks by hamakou108

Other Decks in Programming

Transcript

  1. Laravel
    のメール認証の
    内部実装を掘り下げる
    2021.03.27 PHPerKaigi 2021
    株式会社
    M&A
    クラウド 濱⽥晃輔
    @ hamakou108

    View Slide

  2. ⾃⼰紹介
    濱⽥晃輔 ( )
    株式会社M&A
    クラウド
    Web
    エンジニア
    PHP, Laravel
    TypeScript, Vue.js, Nuxt.js
    AWS
    Vim
    @hamakou108

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. このスライドで話すこと
    メール認証の仕組みと構成要素
    Laravel
    を使ったメール認証の実装⽅法
    フレームワークの内部実装を理解して拡張する

    View Slide

  7. このスライドで話さないこと
    メール認証のセキュリティ上の利点や⽋点
    Laravel
    の基本的な機能の説明
    Service Container, Service Provider
    Authentication, Authorization
    Middleware
    Routing
    Eloquent, Query Builder
    Notifications
    etc.
    トークンの⽣成ロジックなどの実装の詳細部分

    View Slide

  8. メール認証の仕組みとその構成要素

    View Slide

  9. メール認証とは
    ⼊⼒・登録されたメールアドレスを使った認証⽅法
    ⼀時的に有効なトークンつき URL
    を記載したメールを送信し、その URL
    の閲
    覧を以って本⼈性を担保する
    他⼈のメールアドレスを⽤いた成りすましのリスクを下げる

    View Slide

  10. シーケンス図で構成要素を洗う

    View Slide

  11. シーケンス図で構成要素を洗う

    View Slide

  12. シーケンス図で構成要素を洗う

    View Slide

  13. シーケンス図で構成要素を洗う

    View Slide

  14. その他の構成要素
    認証 URL
    (トークン)を⽣成する
    ユーザーの認証情報を埋め込む
    トークンの有効期限を埋め込む
    改ざん防⽌のため署名を埋め込む
    認証 URL
    (トークン)へのリクエストを検証する
    認証メールの再送機能を⽤意する

    View Slide

  15. まるっと実装するのは結構⼤変そう🥺

    View Slide

  16. Laravel
    を使ったメール認証の実装⽅法

    View Slide

  17. Laravel
    の利⽤者がやること
    App User (App\Models\User)
    に MustVerifyEmail
    インターフェースを実装させる
    本⼈認証が必要なページの Routing
    を Middleware
    で保護する
    Starter kits
    で Routing
    や Controller
    や view
    などを⽣成する

    View Slide

  18. App User
    App\Models\User
    MustVerifyEmail
    を実装する =
    メール認証の有効化
    ユーザー登録時に認証メールを送信する
    認証 URL
    へのリクエストを検証する
    認証⽇時を保存する
    ユーザー認証済みかどうかを検証する
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable implements MustVerifyEmail
    {
    use Notifiable;
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9

    View Slide

  19. App User
    App\Models\User
    MustVerifyEmail
    を実装する =
    メール認証の有効化
    ユーザー登録時に認証メールを送信する
    認証 URL
    へのリクエストを検証する
    認証⽇時を保存する
    ユーザー認証済みかどうかを検証する
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable implements MustVerifyEmail
    {
    use Notifiable;
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class User extends Authenticatable implements MustVerifyEmail
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    1
    use Illuminate\Foundation\Auth\User as Authenticatable;
    2
    3
    4
    {
    5
    use Notifiable;
    6
    7
    // ...
    8
    }
    9

    View Slide

  20. Routing
    の保護
    Kernel

    $routeMiddleware

    verified
    という名前で登録されている。
    Route::get('profile', function () {
    // Only verified users may enter...
    })->middleware('verified');
    1
    2
    3

    View Slide

  21. Starter kits (Laravel Breeze)
    を使うと
    さらに実装量が減る
    ├── app
    │ ├── Models
    │ ├── Http
    │ │ ├── Controllers
    │ │ └── Middleware
    │ └── Providers
    ├── routes
    ├── resources
    │ ├── css
    │ ├── js
    │ └── views
    ├── database
    │ └── migrations
    └── tests
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    View Slide

  22. Starter kits (Laravel Breeze)
    を使うと
    さらに実装量が減る
    ├── app
    │ ├── Models
    │ ├── Http
    │ │ ├── Controllers
    │ │ └── Middleware
    │ └── Providers
    ├── routes
    ├── resources
    │ ├── css
    │ ├── js
    │ └── views
    ├── database
    │ └── migrations
    └── tests
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ├── app
    │ ├── Models
    │ ├── Http
    │ │ ├── Controllers
    ├── routes
    ├── resources
    │ ├── css
    │ ├── js
    │ └── views
    └── tests
    1
    2
    3
    4
    │ │ └── Middleware
    5
    │ └── Providers
    6
    7
    8
    9
    10
    11
    ├── database
    12
    │ └── migrations
    13
    14

    View Slide

  23. Starter kits (Laravel Breeze)
    を使うと
    さらに実装量が減る
    ├── app
    │ ├── Models
    │ ├── Http
    │ │ ├── Controllers
    │ │ └── Middleware
    │ └── Providers
    ├── routes
    ├── resources
    │ ├── css
    │ ├── js
    │ └── views
    ├── database
    │ └── migrations
    └── tests
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ├── app
    │ ├── Models
    │ ├── Http
    │ │ ├── Controllers
    ├── routes
    ├── resources
    │ ├── css
    │ ├── js
    │ └── views
    └── tests
    1
    2
    3
    4
    │ │ └── Middleware
    5
    │ └── Providers
    6
    7
    8
    9
    10
    11
    ├── database
    12
    │ └── migrations
    13
    14
    ├── app
    │ ├── Models
    ├── routes
    1
    2
    │ ├── Http
    3
    │ │ ├── Controllers
    4
    │ │ └── Middleware
    5
    │ └── Providers
    6
    7
    ├── resources
    8
    │ ├── css
    9
    │ ├── js
    10
    │ └── views
    11
    ├── database
    12
    │ └── migrations
    13
    └── tests
    14

    View Slide

  24. Starter kits (Laravel Breeze)
    を使うと
    さらに実装量が減る
    ├── app
    │ ├── Models <- MustVerifyEmail
    を実装するだけ
    ├── routes <- middleware('verified')
    を追加するだけ
    1
    2
    │ ├── Http
    3
    │ │ ├── Controllers
    4
    │ │ └── Middleware
    5
    │ └── Providers
    6
    7
    ├── resources
    8
    │ ├── css
    9
    │ ├── js
    10
    │ └── views
    11
    ├── database
    12
    │ └── migrations
    13
    └── tests
    14

    View Slide

  25. Laravel
    の機能やツールを活⽤すれば
    少ない⼿数でメール認証を実装できる 😃

    View Slide

  26. フレームワークの内部実装を理解して拡張する

    View Slide

  27. Laravel
    のメール認証は便利だが
    ...
    フレームワーク内部で何をしているかよく分からない
    ドキュメントには必要最低限の拡張⽅法しか書かれていない
    例えば RDB
    を NoSQL
    に差し替えたい場合はどうする?

    View Slide

  28. App User
    (再掲)
    App\Models\User
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable implements MustVerifyEmail
    {
    use Notifiable;
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9

    View Slide

  29. 依存先が⾒えるように書き直してみる
    Auth
    関連の Contract
    とトレイト、 Eloquent Model
    、 Notifiable
    に依存してい

    use Illuminate\Auth\Authenticatable;
    use Illuminate\Auth\MustVerifyEmail;
    use Illuminate\Auth\Passwords\CanResetPassword;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    use Illuminate\Notifications\Notifiable;
    class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Notifiable,
    Authenticatable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  30. 依存先が⾒えるように書き直してみる
    Auth
    関連の Contract
    とトレイト、 Eloquent Model
    、 Notifiable
    に依存してい

    use Illuminate\Auth\Authenticatable;
    use Illuminate\Auth\MustVerifyEmail;
    use Illuminate\Auth\Passwords\CanResetPassword;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    use Illuminate\Notifications\Notifiable;
    class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Notifiable,
    Authenticatable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    Authenticatable,
    Authorizable,
    CanResetPassword,
    MustVerifyEmail;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Database\Eloquent\Model;
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    use Illuminate\Notifications\Notifiable;
    10
    11
    class User extends Model implements
    12
    13
    14
    15
    16
    {
    17
    use Notifiable,
    18
    19
    20
    21
    22
    }
    23

    View Slide

  31. 依存先が⾒えるように書き直してみる
    Auth
    関連の Contract
    とトレイト、 Eloquent Model
    、 Notifiable
    に依存してい

    use Illuminate\Auth\Authenticatable;
    use Illuminate\Auth\MustVerifyEmail;
    use Illuminate\Auth\Passwords\CanResetPassword;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    use Illuminate\Notifications\Notifiable;
    class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Notifiable,
    Authenticatable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    Authenticatable
    use Illuminate\Auth\Authenticatable;
    1
    use Illuminate\Auth\MustVerifyEmail;
    2
    use Illuminate\Auth\Passwords\CanResetPassword;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Database\Eloquent\Model;
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    use Illuminate\Notifications\Notifiable;
    10
    11
    class User extends Model implements
    12
    13
    14
    15
    16
    {
    17
    use Notifiable,
    18
    19
    use Illuminate\Database\Eloquent\Model;
    class User extends Model implements
    use Illuminate\Auth\Authenticatable;
    1
    use Illuminate\Auth\MustVerifyEmail;
    2
    use Illuminate\Auth\Passwords\CanResetPassword;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    use Illuminate\Notifications\Notifiable;
    10
    11
    12
    AuthenticatableContract,
    13
    AuthorizableContract,
    14
    CanResetPasswordContract,
    15
    MustVerifyEmailContract
    16
    {
    17
    use Notifiable,
    18
    Authenticatable,
    19

    View Slide

  32. 依存先が⾒えるように書き直してみる
    Auth
    関連の Contract
    とトレイト、 Eloquent Model
    、 Notifiable
    に依存してい

    use Illuminate\Auth\Authenticatable;
    use Illuminate\Auth\MustVerifyEmail;
    use Illuminate\Auth\Passwords\CanResetPassword;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    use Illuminate\Notifications\Notifiable;
    class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Notifiable,
    Authenticatable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    Authenticatable
    use Illuminate\Auth\Authenticatable;
    1
    use Illuminate\Auth\MustVerifyEmail;
    2
    use Illuminate\Auth\Passwords\CanResetPassword;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Database\Eloquent\Model;
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    use Illuminate\Notifications\Notifiable;
    10
    11
    class User extends Model implements
    12
    13
    14
    15
    16
    {
    17
    use Notifiable,
    18
    19
    use Illuminate\Database\Eloquent\Model;
    class User extends Model implements
    use Illuminate\Auth\Authenticatable;
    1
    use Illuminate\Auth\MustVerifyEmail;
    2
    use Illuminate\Auth\Passwords\CanResetPassword;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    use Illuminate\Notifications\Notifiable;
    10
    11
    12
    AuthenticatableContract,
    13
    AuthorizableContract,
    14
    CanResetPasswordContract,
    15
    MustVerifyEmailContract
    16
    {
    17
    use Notifiable,
    18
    Authenticatable
    19
    use Illuminate\Notifications\Notifiable;
    use Notifiable,
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Database\Eloquent\Model;
    8
    use Illuminate\Foundation\Auth\Access\Authorizable;
    9
    10
    11
    class User extends Model implements
    12
    AuthenticatableContract,
    13
    AuthorizableContract,
    14
    CanResetPasswordContract,
    15
    MustVerifyEmailContract
    16
    {
    17
    18
    Authenticatable,
    19
    Authorizable,
    20
    CanResetPassword,
    21
    MustVerifyEmail;
    22
    }
    23

    View Slide

  33. Auth
    関連のトレイトの依存先
    Illuminate\Auth\MustVerifyEmail
    Auth
    関連の機能は App User
    を通して Eloquent
    と Notifiable
    に複雑に依存して
    いる
    trait MustVerifyEmail
    {
    /**
    * Mark the given user's email as verified.
    *
    * @return bool
    */
    public function markEmailAsVerified()
    {
    return $this->forceFill([
    'email_verified_at' => $this->freshTimestamp(),
    ])->save();
    }
    // ...
    /**
    * Send the email verification notification.
    *
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  34. Auth
    関連のトレイトの依存先
    Illuminate\Auth\MustVerifyEmail
    Auth
    関連の機能は App User
    を通して Eloquent
    と Notifiable
    に複雑に依存して
    いる
    trait MustVerifyEmail
    {
    /**
    * Mark the given user's email as verified.
    *
    * @return bool
    */
    public function markEmailAsVerified()
    {
    return $this->forceFill([
    'email_verified_at' => $this->freshTimestamp(),
    ])->save();
    }
    // ...
    /**
    * Send the email verification notification.
    *
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Mark the given user's email as verified.
    *
    * @return bool
    */
    public function markEmailAsVerified()
    {
    return $this->forceFill([
    'email_verified_at' => $this->freshTimestamp(),
    ])->save();
    }
    trait MustVerifyEmail
    1
    {
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // ...
    15
    16
    /**
    17
    * Send the email verification notification.
    18
    *
    19

    View Slide

  35. Auth
    関連のトレイトの依存先
    Illuminate\Auth\MustVerifyEmail
    Auth
    関連の機能は App User
    を通して Eloquent
    と Notifiable
    に複雑に依存して
    いる
    trait MustVerifyEmail
    {
    /**
    * Mark the given user's email as verified.
    *
    * @return bool
    */
    public function markEmailAsVerified()
    {
    return $this->forceFill([
    'email_verified_at' => $this->freshTimestamp(),
    ])->save();
    }
    // ...
    /**
    * Send the email verification notification.
    *
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Mark the given user's email as verified.
    *
    * @return bool
    */
    public function markEmailAsVerified()
    {
    return $this->forceFill([
    'email_verified_at' => $this->freshTimestamp(),
    ])->save();
    }
    trait MustVerifyEmail
    1
    {
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // ...
    15
    16
    /**
    17
    * Send the email verification notification.
    18
    *
    19
    /**
    * Send the email verification notification.
    *
    * @return void
    */
    public function sendEmailVerificationNotification()
    {
    $this->notify(new VerifyEmail);
    }
    return $this->forceFill([
    10
    'email_verified_at' => $this->freshTimestamp(),
    11
    ])->save();
    12
    }
    13
    14
    // ...
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // ...
    27
    }
    28

    View Slide

  36. App User
    の責務が多すぎる
    Auth
    系の機能を使うための I/F
    を提供する
    DB
    を通して認証情報を取得、保存する (=> Eloquent Model)
    ユーザーにメールを送信する (=> Notifiable)

    View Slide

  37. App User
    の責務が多すぎる
    Auth
    系の機能を使うための I/F
    を提供する
    DB
    を通して認証情報を取得、保存する (=> Eloquent Model)
    ユーザーにメールを送信する (=> Notifiable)

    View Slide

  38. Repository
    パターンを利⽤して
    App User
    の責務を切り離す

    View Slide

  39. クラス図(変更前)

    View Slide

  40. クラス図(変更後)

    View Slide

  41. ⚠ この先、幾つかの
    User
    が出てきます
    呼称 役割
    App User
    認証に⽤いる I/F
    を提供する
    Domain User
    ドメインのコアロジックを提供する
    Eloquent User User
    を永続化するための機能を提供する
    Notifiable User User
    に通知を送るための機能を提供する

    公式の呼称ではありません。

    View Slide

  42. Domain Repository
    Domain\User\UserRepository
    interface UserRepository
    {
    public function markEmailAsVerified(UserId $id): bool;
    // ...
    }
    1
    2
    3
    4
    5
    6

    View Slide

  43. Infra Repository
    Infra\Repository\Eloquent\UserRepository
    use Domain\User\UserRepository as UserRepositoryInterface;
    use Infra\Model\Eloquent\User as UserModel;
    class UserRepository implements UserRepositoryInterface
    {
    public function markEmailAsVerified(UserId $id): bool
    {
    return UserModel::where('id', $id->rawValue())
    ->whereNull('email_verified_at')
    ->update([
    'email_verified_at' => Date::now(),
    ]);
    }
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    View Slide

  44. Infra Repository
    Infra\Repository\Eloquent\UserRepository
    use Domain\User\UserRepository as UserRepositoryInterface;
    use Infra\Model\Eloquent\User as UserModel;
    class UserRepository implements UserRepositoryInterface
    {
    public function markEmailAsVerified(UserId $id): bool
    {
    return UserModel::where('id', $id->rawValue())
    ->whereNull('email_verified_at')
    ->update([
    'email_verified_at' => Date::now(),
    ]);
    }
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class UserRepository implements UserRepositoryInterface
    use Domain\User\UserRepository as UserRepositoryInterface;
    1
    use Infra\Model\Eloquent\User as UserModel;
    2
    3
    4
    {
    5
    public function markEmailAsVerified(UserId $id): bool
    6
    {
    7
    return UserModel::where('id', $id->rawValue())
    8
    ->whereNull('email_verified_at')
    9
    ->update([
    10
    'email_verified_at' => Date::now(),
    11
    ]);
    12
    }
    13
    14
    // ...
    15
    }
    16

    View Slide

  45. Infra Repository
    Infra\Repository\Eloquent\UserRepository
    use Domain\User\UserRepository as UserRepositoryInterface;
    use Infra\Model\Eloquent\User as UserModel;
    class UserRepository implements UserRepositoryInterface
    {
    public function markEmailAsVerified(UserId $id): bool
    {
    return UserModel::where('id', $id->rawValue())
    ->whereNull('email_verified_at')
    ->update([
    'email_verified_at' => Date::now(),
    ]);
    }
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class UserRepository implements UserRepositoryInterface
    use Domain\User\UserRepository as UserRepositoryInterface;
    1
    use Infra\Model\Eloquent\User as UserModel;
    2
    3
    4
    {
    5
    public function markEmailAsVerified(UserId $id): bool
    6
    {
    7
    return UserModel::where('id', $id->rawValue())
    8
    ->whereNull('email_verified_at')
    9
    ->update([
    10
    'email_verified_at' => Date::now(),
    11
    ]);
    12
    }
    13
    14
    // ...
    15
    }
    16
    public function markEmailAsVerified(UserId $id): bool
    {
    return UserModel::where('id', $id->rawValue())
    ->whereNull('email_verified_at')
    ->update([
    'email_verified_at' => Date::now(),
    ]);
    }
    use Domain\User\UserRepository as UserRepositoryInterface;
    1
    use Infra\Model\Eloquent\User as UserModel;
    2
    3
    class UserRepository implements UserRepositoryInterface
    4
    {
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // ...
    15
    }
    16

    View Slide

  46. RepositoryServiceProvider
    App\Providers\RepositoryServiceProvider
    インフラが変わる場合は Infra
    の UserRepository
    を差し替えれば良いだけにな
    った!
    use Domain\User\UserRepository;
    use Infra\Repository\Eloquent\UserRepository as EloquentUserRepository;
    class RepositoryServiceProvider extends ServiceProvider
    {
    public function register()
    {
    $this->app->bind(
    UserRepository::class,
    EloquentUserRepository::class
    );
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    View Slide

  47. RepositoryServiceProvider
    App\Providers\RepositoryServiceProvider
    インフラが変わる場合は Infra
    の UserRepository
    を差し替えれば良いだけにな
    った!
    use Domain\User\UserRepository;
    use Infra\Repository\Eloquent\UserRepository as EloquentUserRepository;
    class RepositoryServiceProvider extends ServiceProvider
    {
    public function register()
    {
    $this->app->bind(
    UserRepository::class,
    EloquentUserRepository::class
    );
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $this->app->bind(
    UserRepository::class,
    EloquentUserRepository::class
    );
    use Domain\User\UserRepository;
    1
    use Infra\Repository\Eloquent\UserRepository as EloquentUserRepository;
    2
    3
    class RepositoryServiceProvider extends ServiceProvider
    4
    {
    5
    public function register()
    6
    {
    7
    8
    9
    10
    11
    }
    12
    }
    13

    View Slide

  48. Domain Notifier
    Domain\User\UserNotifier
    interface UserNotifier
    {
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void;
    }
    1
    2
    3
    4
    5
    6
    7

    View Slide

  49. Infra Notifier
    Infra\Notifier\Illuminate\UserNotifier
    use Domain\User\User;
    use Domain\User\UserNotifier as UserNotifierInterface;
    use Illuminate\Auth\Notifications\VerifyEmail;
    use Infra\Notifiable\User as NotifiableUser;
    use Infra\Notifications\VerifyEmail;
    class UserNotifier implements UserNotifierInterface
    {
    private Dispatcher $dispatcher;
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void {
    $this >dispatcher >send(
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  50. Infra Notifier
    Infra\Notifier\Illuminate\UserNotifier
    use Domain\User\User;
    use Domain\User\UserNotifier as UserNotifierInterface;
    use Illuminate\Auth\Notifications\VerifyEmail;
    use Infra\Notifiable\User as NotifiableUser;
    use Infra\Notifications\VerifyEmail;
    class UserNotifier implements UserNotifierInterface
    {
    private Dispatcher $dispatcher;
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void {
    $this >dispatcher >send(
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class UserNotifier implements UserNotifierInterface
    use Domain\User\User;
    1
    use Domain\User\UserNotifier as UserNotifierInterface;
    2
    use Illuminate\Auth\Notifications\VerifyEmail;
    3
    use Infra\Notifiable\User as NotifiableUser;
    4
    use Infra\Notifications\VerifyEmail;
    5
    6
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    public function __construct(Dispatcher $dispatcher) {
    11
    $this->dispatcher = $dispatcher;
    12
    }
    13
    14
    public function sendEmailVerificationNotification(
    15
    User $user,
    16
    string $url
    17
    ): void {
    18
    $this >dispatcher >send(
    19

    View Slide

  51. Infra Notifier
    Infra\Notifier\Illuminate\UserNotifier
    use Domain\User\User;
    use Domain\User\UserNotifier as UserNotifierInterface;
    use Illuminate\Auth\Notifications\VerifyEmail;
    use Infra\Notifiable\User as NotifiableUser;
    use Infra\Notifications\VerifyEmail;
    class UserNotifier implements UserNotifierInterface
    {
    private Dispatcher $dispatcher;
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void {
    $this >dispatcher >send(
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class UserNotifier implements UserNotifierInterface
    use Domain\User\User;
    1
    use Domain\User\UserNotifier as UserNotifierInterface;
    2
    use Illuminate\Auth\Notifications\VerifyEmail;
    3
    use Infra\Notifiable\User as NotifiableUser;
    4
    use Infra\Notifications\VerifyEmail;
    5
    6
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    public function __construct(Dispatcher $dispatcher) {
    11
    $this->dispatcher = $dispatcher;
    12
    }
    13
    14
    public function sendEmailVerificationNotification(
    15
    User $user,
    16
    string $url
    17
    ): void {
    18
    $this >dispatcher >send(
    19
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    use Illuminate\Auth\Notifications\VerifyEmail;
    3
    use Infra\Notifiable\User as NotifiableUser;
    4
    use Infra\Notifications\VerifyEmail;
    5
    6
    class UserNotifier implements UserNotifierInterface
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    11
    12
    13
    14
    public function sendEmailVerificationNotification(
    15
    User $user,
    16
    string $url
    17
    ): void {
    18
    $this->dispatcher->send(
    19
    new NotifiableUser($user),
    20
    new VerifyEmail($url)
    21

    View Slide

  52. Infra Notifier
    Infra\Notifier\Illuminate\UserNotifier
    use Domain\User\User;
    use Domain\User\UserNotifier as UserNotifierInterface;
    use Illuminate\Auth\Notifications\VerifyEmail;
    use Infra\Notifiable\User as NotifiableUser;
    use Infra\Notifications\VerifyEmail;
    class UserNotifier implements UserNotifierInterface
    {
    private Dispatcher $dispatcher;
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void {
    $this >dispatcher >send(
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class UserNotifier implements UserNotifierInterface
    use Domain\User\User;
    1
    use Domain\User\UserNotifier as UserNotifierInterface;
    2
    use Illuminate\Auth\Notifications\VerifyEmail;
    3
    use Infra\Notifiable\User as NotifiableUser;
    4
    use Infra\Notifications\VerifyEmail;
    5
    6
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    public function __construct(Dispatcher $dispatcher) {
    11
    $this->dispatcher = $dispatcher;
    12
    }
    13
    14
    public function sendEmailVerificationNotification(
    15
    User $user,
    16
    string $url
    17
    ): void {
    18
    $this >dispatcher >send(
    19
    public function __construct(Dispatcher $dispatcher) {
    $this->dispatcher = $dispatcher;
    }
    use Domain\User\User;
    1
    use Domain\User\UserNotifier as UserNotifierInterface;
    2
    use Illuminate\Auth\Notifications\VerifyEmail;
    3
    use Infra\Notifiable\User as NotifiableUser;
    4
    use Infra\Notifications\VerifyEmail;
    5
    6
    class UserNotifier implements UserNotifierInterface
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    11
    12
    13
    14
    public function sendEmailVerificationNotification(
    15
    User $user,
    16
    string $url
    17
    ): void {
    18
    $this >dispatcher >send(
    19
    public function sendEmailVerificationNotification(
    User $user,
    string $url
    ): void {
    $this->dispatcher->send(
    new NotifiableUser($user),
    new VerifyEmail($url)
    );
    }
    6
    class UserNotifier implements UserNotifierInterface
    7
    {
    8
    private Dispatcher $dispatcher;
    9
    10
    public function __construct(Dispatcher $dispatcher) {
    11
    $this->dispatcher = $dispatcher;
    12
    }
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    }
    24

    View Slide

  53. Notifiable
    Infra\Notifiable\User
    use Domain\User\User as DomainUser;
    use Illuminate\Notifications\Notifiable;
    class User
    {
    use Notifiable;
    private DomainUser $user;
    public function __construct(DomainUser $user)
    {
    $this->user = $user;
    }
    public function routeNotificationForMail()
    {
    return $this->user->getRawEmail();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  54. Notifiable
    Infra\Notifiable\User
    use Domain\User\User as DomainUser;
    use Illuminate\Notifications\Notifiable;
    class User
    {
    use Notifiable;
    private DomainUser $user;
    public function __construct(DomainUser $user)
    {
    $this->user = $user;
    }
    public function routeNotificationForMail()
    {
    return $this->user->getRawEmail();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    use Notifiable;
    use Domain\User\User as DomainUser;
    1
    use Illuminate\Notifications\Notifiable;
    2
    3
    class User
    4
    {
    5
    6
    7
    private DomainUser $user;
    8
    9
    public function __construct(DomainUser $user)
    10
    {
    11
    $this->user = $user;
    12
    }
    13
    14
    public function routeNotificationForMail()
    15
    {
    16
    return $this->user->getRawEmail();
    17
    }
    18
    }
    19

    View Slide

  55. Notification
    Infra\Notifications\VerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    class VerifyEmail extends IlluminateVerifyEmail
    {
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    /**
    * @inheritDoc
    */
    public function toMail($notifiable)
    {
    return $this->buildMailMessage($this->verificationUrl);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  56. Notification
    Infra\Notifications\VerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    class VerifyEmail extends IlluminateVerifyEmail
    {
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    /**
    * @inheritDoc
    */
    public function toMail($notifiable)
    {
    return $this->buildMailMessage($this->verificationUrl);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class VerifyEmail extends IlluminateVerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    3
    {
    4
    private string $verificationUrl;
    5
    6
    public function __construct(string $verificationUrl)
    7
    {
    8
    $this->verificationUrl = $verificationUrl;
    9
    }
    10
    11
    /**
    12
    * @inheritDoc
    13
    */
    14
    public function toMail($notifiable)
    15
    {
    16
    return $this->buildMailMessage($this->verificationUrl);
    17
    }
    18
    }
    19

    View Slide

  57. Notification
    Infra\Notifications\VerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    class VerifyEmail extends IlluminateVerifyEmail
    {
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    /**
    * @inheritDoc
    */
    public function toMail($notifiable)
    {
    return $this->buildMailMessage($this->verificationUrl);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class VerifyEmail extends IlluminateVerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    3
    {
    4
    private string $verificationUrl;
    5
    6
    public function __construct(string $verificationUrl)
    7
    {
    8
    $this->verificationUrl = $verificationUrl;
    9
    }
    10
    11
    /**
    12
    * @inheritDoc
    13
    */
    14
    public function toMail($notifiable)
    15
    {
    16
    return $this->buildMailMessage($this->verificationUrl);
    17
    }
    18
    }
    19
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    class VerifyEmail extends IlluminateVerifyEmail
    3
    {
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    12
    * @inheritDoc
    13
    */
    14
    public function toMail($notifiable)
    15
    {
    16
    return $this->buildMailMessage($this->verificationUrl);
    17
    }
    18
    }
    19

    View Slide

  58. Notification
    Infra\Notifications\VerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    class VerifyEmail extends IlluminateVerifyEmail
    {
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    /**
    * @inheritDoc
    */
    public function toMail($notifiable)
    {
    return $this->buildMailMessage($this->verificationUrl);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class VerifyEmail extends IlluminateVerifyEmail
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    3
    {
    4
    private string $verificationUrl;
    5
    6
    public function __construct(string $verificationUrl)
    7
    {
    8
    $this->verificationUrl = $verificationUrl;
    9
    }
    10
    11
    /**
    12
    * @inheritDoc
    13
    */
    14
    public function toMail($notifiable)
    15
    {
    16
    return $this->buildMailMessage($this->verificationUrl);
    17
    }
    18
    }
    19
    private string $verificationUrl;
    public function __construct(string $verificationUrl)
    {
    $this->verificationUrl = $verificationUrl;
    }
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    class VerifyEmail extends IlluminateVerifyEmail
    3
    {
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    12
    * @inheritDoc
    13
    */
    14
    public function toMail($notifiable)
    15
    {
    16
    return $this->buildMailMessage($this->verificationUrl);
    17
    }
    18
    }
    19
    /**
    * @inheritDoc
    */
    public function toMail($notifiable)
    {
    return $this->buildMailMessage($this->verificationUrl);
    }
    use Illuminate\Auth\Notifications\VerifyEmail as IlluminateVerifyEmail;
    1
    2
    class VerifyEmail extends IlluminateVerifyEmail
    3
    {
    4
    private string $verificationUrl;
    5
    6
    public function __construct(string $verificationUrl)
    7
    {
    8
    $this->verificationUrl = $verificationUrl;
    9
    }
    10
    11
    12
    13
    14
    15
    16
    17
    18
    }
    19

    View Slide

  59. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  60. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    return $this->buildMailMessage($verificationUrl);
    }
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //
    24

    View Slide

  61. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $verificationUrl = $this->verificationUrl($notifiable);
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    20
    return $this->buildMailMessage($verificationUrl);
    21
    }
    22
    23
    // ...
    24

    View Slide

  62. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $verificationUrl = $this->verificationUrl($notifiable);
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    // ...
    /**
    * Get the verification URL for the given notifiable.
    *
    * @param mixed $notifiable
    * @return string
    */
    protected function verificationUrl($notifiable)
    {
    if (static::$createUrlCallback) {
    return call_user_func(static::$createUrlCallback, $notifiable);
    }
    return URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
    'id' $ tifi bl t ()
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

    View Slide

  63. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $verificationUrl = $this->verificationUrl($notifiable);
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    return URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
    'id' => $notifiable->getKey(),
    'hash' => sha1($notifiable->getEmailForVerification()),
    ]
    );
    */
    31
    protected function verificationUrl($notifiable)
    32
    {
    33
    if (static::$createUrlCallback) {
    34
    return call_user_func(static::$createUrlCallback, $notifiable);
    35
    }
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    }
    46
    47
    // ...
    48
    }
    49

    View Slide

  64. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $verificationUrl = $this->verificationUrl($notifiable);
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    [
    'id' => $notifiable->getKey(),
    'hash' => sha1($notifiable->getEmailForVerification()),
    ]
    */
    31
    protected function verificationUrl($notifiable)
    32
    {
    33
    if (static::$createUrlCallback) {
    34
    return call_user_func(static::$createUrlCallback, $notifiable);
    35
    }
    36
    37
    return URL::temporarySignedRoute(
    38
    'verification.verify',
    39
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    40
    41
    42
    43
    44
    );
    45
    }
    46
    47
    // ...
    48
    }
    49

    View Slide

  65. 認証
    URL
    の⽣成処理はどこ?
    Illuminate\Auth\Notifications\VerifyEmail
    getKey
    は Eloquent Model
    のメソッドなので使えない!
    認証 URL
    の⽣成を Notification
    から App User
    に切り出そう
    use Illuminate\Notifications\Notification;
    class VerifyEmail extends Notification
    {
    // ...
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * Build the mail representation of the notification.
    *
    * @param mixed $notifiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    public function toMail($notifiable)
    {
    $verificationUrl = $this->verificationUrl($notifiable);
    if (static::$toMailCallback) {
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    }
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $verificationUrl = $this->verificationUrl($notifiable);
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    use Illuminate\Notifications\Notification;
    1
    2
    class VerifyEmail extends Notification
    3
    {
    4
    // ...
    5
    6
    /**
    7
    * Build the mail representation of the notification.
    8
    *
    9
    * @param mixed $notifiable
    10
    * @return \Illuminate\Notifications\Messages\MailMessage
    11
    */
    12
    public function toMail($notifiable)
    13
    {
    14
    $verificationUrl = $this->verificationUrl($notifiable);
    15
    16
    if (static::$toMailCallback) {
    17
    return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
    18
    }
    19
    'id' => $notifiable->getKey(),
    */
    31
    protected function verificationUrl($notifiable)
    32
    {
    33
    if (static::$createUrlCallback) {
    34
    return call_user_func(static::$createUrlCallback, $notifiable);
    35
    }
    36
    37
    return URL::temporarySignedRoute(
    38
    'verification.verify',
    39
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    40
    [
    41
    42
    'hash' => sha1($notifiable->getEmailForVerification()),
    43
    ]
    44
    );
    45
    }
    46
    47
    // ...
    48
    }
    49

    View Slide

  66. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    View Slide

  67. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserNotifier $notifier;
    20
    21

    View Slide

  68. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserId $id;
    private UserRepository $repository;
    private UserNotifier $notifier;
    public function __construct(
    UserId $id,
    UserRepository $repository,
    UserNotifier $notifier
    ) {
    $this->id = $id;
    $this->repository = $repository;
    $this->notifier = $notifier;
    }
    {
    15
    use Authorizable;
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // ...
    32
    33

    View Slide

  69. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserId $id;
    private UserRepository $repository;
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    18
    19
    /**
    * @inheritDoc
    */
    public function markEmailAsVerified()
    {
    return $this->repository->markEmailAsVerified($this->id);
    }
    $this->repository = $repository;
    28
    $this->notifier = $notifier;
    29
    }
    30
    31
    // ...
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    /**
    42
    * @inheritDoc
    43
    */
    44
    public function sendEmailVerificationNotification()
    45
    {
    46

    View Slide

  70. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserId $id;
    private UserRepository $repository;
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    18
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    /**
    * @inheritDoc
    */
    public function sendEmailVerificationNotification()
    {
    $user = $this->repository->get($this->id);
    $url = $this->createVerificationUrl();
    $this->notifier->sendEmailVerificationNotification($user, $url);
    }
    public function markEmailAsVerified()
    37
    {
    38
    return $this->repository->markEmailAsVerified($this->id);
    39
    }
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    private function createVerificationUrl(): string
    53
    {
    54
    return URL::temporarySignedRoute(
    55

    View Slide

  71. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserId $id;
    private UserRepository $repository;
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    18
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private function createVerificationUrl(): string
    {
    return URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
    'id' => $this->id->rawValue(),
    'hash' => sha1($this->getEmailForVerification()),
    ]
    );
    }
    {
    46
    $user = $this->repository->get($this->id);
    47
    $url = $this->createVerificationUrl();
    48
    49
    $this->notifier->sendEmailVerificationNotification($user, $url);
    50
    }
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63

    View Slide

  72. App User
    App\Models\User
    Eloquent Model
    と Notifiable
    への依存がなくなった!
    Respository
    と Notifier
    のインターフェースにのみ依存
    use Domain\User\UserId;
    use Domain\User\UserNotifier;
    use Domain\User\UserRepository;
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    use Illuminate\Foundation\Auth\Access\Authorizable;
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    {
    use Authorizable;
    private UserId $id;
    private UserRepository $repository;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class User implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    MustVerifyEmailContract
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    10
    11
    12
    13
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    private UserId $id;
    private UserRepository $repository;
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    18
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    use Domain\User\UserId;
    1
    use Domain\User\UserNotifier;
    2
    use Domain\User\UserRepository;
    3
    use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
    4
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    5
    use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
    6
    use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
    7
    use Illuminate\Foundation\Auth\Access\Authorizable;
    8
    9
    class User implements
    10
    AuthenticatableContract,
    11
    AuthorizableContract,
    12
    CanResetPasswordContract,
    13
    MustVerifyEmailContract
    14
    {
    15
    use Authorizable;
    16
    17
    private UserId $id;
    18
    private UserRepository $repository;
    19
    'id' => $this->id->rawValue(),
    {
    46
    $user = $this->repository->get($this->id);
    47
    $url = $this->createVerificationUrl();
    48
    49
    $this->notifier->sendEmailVerificationNotification($user, $url);
    50
    }
    51
    52
    private function createVerificationUrl(): string
    53
    {
    54
    return URL::temporarySignedRoute(
    55
    'verification.verify',
    56
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    57
    [
    58
    59
    'hash' => sha1($this->getEmailForVerification()),
    60
    ]
    61
    );
    62
    }
    63

    View Slide

  73. まとめ
    メール認証の実装では検討すべき事項が多く、マニュアル実装するのは結構
    ⼤変
    Laravel
    は少ない⼿数でメール認証を実装する⼿段を⽤意してくれている
    内部実装を理解して依存関係を紐解くことで、保守性・拡張性の⾼いアーキ
    テクチャに組み替えることができる

    View Slide

  74. View Slide

  75. ありがとうございました!🤲

    View Slide