LaravelでPasswordBrokerを拡張してパスワードリセットに権限チェックを追加する

## 実現したいこと（抽象）
Laravelが提供しているFacadeで呼び出すクラスを差し替えたい。
処理の一部だけを変更したいのでLaravelが提供するクラスをオーバーライドしたい。

## 実現したいこと（具体）
Laravel Breezeを利用している。
自動生成されたパスワードリセット画面にてメールアドレスを入力して送信すると、存在チェックしてパスワードリセット用のメールを送信する。
存在チェックだけではなくて、権限チェックを追加して特定のユーザ権限の場合はエラー（メールアドレス誤りと同様に存在チェックエラー）としたい。

## 対応方法

### `app.php`でプロバイダを独自拡張のプロバイダに差し替え。

```app.php
'providers' => [
        //Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        App\Providers\PasswordResetServiceProvider::class,
```

### 独自拡張のプロバイダを作成。
extends PasswordsPasswordResetServiceProviderしているので、オーバーライドしたいメソッドのみ記載。
registerPasswordBrokerメソッドの`PasswordBrokerManager`を独自拡張のものに差し替える（`use App\Extensions\Auth\Passwords\PasswordBrokerManager`を利用する）
```App\Providers\PasswordResetServiceProvider.php
<?php

namespace App\Providers;

use App\Extensions\Auth\Passwords\PasswordBrokerManager;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider as PasswordsPasswordResetServiceProvider;

class PasswordResetServiceProvider extends PasswordsPasswordResetServiceProvider
{
    /**
     * Register the password broker instance.
     *
     * @return void
     */
    protected function registerPasswordBroker()
    {
        $this->app->singleton('auth.password', function ($app) {
            return new PasswordBrokerManager($app);
        });

        $this->app->bind('auth.password.broker', function ($app) {
            return $app->make('auth.password')->broker();
        });
    }
}

```

### プロバイダから呼び出される拡張PasswordBrokerManagerを作成
extendsするのでオーバーライドしたいメソッドのみ記載。
今回は独自のPasswordBrokerを使いたいのでresolveメソッドのみ書き換え。
```App\Extensions\Auth\Passwords\PasswordBrokerManager.php
<?php

namespace App\Extensions\Auth\Passwords;

use Illuminate\Auth\Passwords\PasswordBrokerManager as PasswordsPasswordBrokerManager;
use InvalidArgumentException;

/**
 * @mixin \Illuminate\Contracts\Auth\PasswordBroker
 */
class PasswordBrokerManager extends PasswordsPasswordBrokerManager
{
    /**
     * Resolve the given broker.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Password resetter [{$name}] is not defined.");
        }

        // App\Extensions\Auth\Passwords配下のものでnewする
        return new PasswordBroker(
            $this->createTokenRepository($config),
            $this->app['auth']->createUserProvider($config['provider'] ?? null)
        );
    }
}

```

### 権限チェックを行う拡張PasswordBrokerを作成
やっと権限チェックを入れたいPasswordBroker。
ここも今までと同じように`extends PasswordsPasswordBroker`して、特定のメソッドのみオーバーライドする。
今回はsendResetLinkメソッドに権限チェックをして問題なければ、親のsendResetLinkを呼ぶ。（`parent::sendResetLink`）
```
<?php

namespace App\Extensions\Auth\Passwords;

use Closure;
use Illuminate\Auth\Passwords\PasswordBroker as PasswordsPasswordBroker;

class PasswordBroker extends PasswordsPasswordBroker
{
    public function sendResetLink(array $credentials, Closure $callback = null)
    {
        $user = $this->getUser($credentials);

        // ここに権限チェックを追加
        if (is_null($user) || $user->is_xxx) {
            return static::INVALID_USER;
        }

        return parent::sendResetLink($credentials, $callback);
    }
}

```


## 参考
以下、ありがとうございます！

メール送信で同じようなことをしている。
https://stackoverflow.com/questions/39102483/add-a-new-transport-driver-to-laravels-mailer/39104567#39104567

ヘルパ関数で同じようなことをしている。
`Extensions`ディレクトリを作るのが自分もしっくりきた。
https://qiita.com/kd9951/items/46ef3559009ee575ea7d