LaravelのFacadeの作り方

# 手順
1.インスタンス生成対象のクラス作成
2.サービスプロバイダーの登録・使用
　（A）AppServiceProviderを使用する
　（B）そのクラス用のサービスプロバイダーを作成し、config/app.phpに登録
3.インスタンス生成方法を記載
　（A）AppServiceProviderクラスに記載
　（B）作成したサービスプロバイダーに記載
4.Facadeクラスを作成
5.Facadeを使用する
6.Facadeのエイリアスを張る
7.まとめ

## 1.インスタンス生成対象のクラス作成
Eatクラスを作成してみる。

```php
<?php

namespace App\Services;

class Eat
{
    public function eat(string $food) {
        echo $food.'を食べる。';
   }
}
```

Eatクラスは「◯◯を食べる」を表示するeatメソッドのみが実装されている。
◯◯に当たる部分は、eatメソッドを使う際に挿入し、それが表示結果に反映されるようにする。

```php

$instance = new Eat();
echo $instance->eat('ばなな');

->ばななを食べる
```

## 2.サービスプロバイダーの登録・使用
### （A）AppServiceProviderを使用する
AppServiceProviderを使用する場合は、ここでは特に何も行う必要はありません。
初期では以下の様になっています。

```php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
```

### （B）そのクラス用のサービスプロバイダーを作成し、config/app.phpに登録
ここでは、Eatクラスと対応するEatServiceProviderクラスを作成。

Laravelでは以下の様に作成コマンドが用意されていますので、そちらを使います。

```console
php artisan make:provider EatServiceProvider
```
上記コマンドで以下のようなEatServiceProviderクラスが新たに生成されました。
初期では以下の様になっています。

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class EatServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
```

上記で出来上がった**EatServiceProvider**を登録ていきます。

今回のプロジェクトで新規で追加するものをわかりやすくするために、コメントで新規追加と入れておきます。

```config/app.php
<?php

return [
    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,

        /*
         * Package Service Providers...
         */

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\MacroServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

        /**
         * 新規追加
         */
        App\Providers\EatServiceProvider::class, <= ここに追加しました
    ],
];

```

これで「（A）AppServiceProviderを使用する」｜「（B）そのクラス用のサービスプロバイダーを作成し、config/app.phpに登録」共にインスタンス生成の方法を記載する準備が整いました。

## 3.インスタンス生成方法を記載

### （A）AppServiceProviderクラスに記載

実際に登録していきます。

```php

<?php

namespace App\Providers;

use App\Services\Eat;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('eat', function () {
            return new Eat();
        });
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

```

今回は、**eat**というサービスコンテナの結合名で**App\Services\Eat.php**のインスタンスを返しました。
仮に、**eat**というサービスコンテナの結合名で他のオブジェクトのインスタンスを返したくなれば、newするクラスを変えるだけで良いのです！

### （B）作成したサービスプロバイダーに記載
こちらも3(A)同様に登録していきます。

```php
<?php

namespace App\Providers;

use App\Services\Eat;
use Illuminate\Support\ServiceProvider;

class EatServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('eat', function () {
            return new Eat();
        });
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
```
こちらも、3(A)同様に**eat**というサービスコンテナの結合名で**App\Services\Eat.php**のインスタンスを返しました。

## 4.Facadeクラスを作成

こちらは、コマンド等ございませんので、自分で一から作成する形になります。
今回は、**App\Facades**ディレクトリを作成し、そこに**Eat**ファサードクラスを設置したいと思います。

```php
<?php

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Eat extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'eat';
    }
}
```

Facadeは、**getFacadeAccessor**の返り値と一致するサービスコンテナの結合名を探し、あればその結合名で登録されているインスタンスと紐づくというものです。

今回の場合、**Eatファサード**を**App\Services\Eat.php**のインスタンスと紐付けたいため、**App\Services\Eat.php**のインスタンスを返すように登録されている、サービスコンテナ内の結合名を探すと、先程、2(A)+3(A) or 2(B)+3(B)で登録した**eatキー**がありますね。

これをEatファサードのgetFacadeAccessorの返り値として、返せばひも付きができますので、今回は**eat**という文字列を返します。

## 5.Facadeを使用する

では、1~4で準備・作成を行ったEatファサードを実際に使ってみましょう。
まず、phpファイルでファサードを使用します。
今回は、main.phpでEatファサードを下記のように使用してみます。

```main.php

App\Facades\Eat::eat('ばなな');
```

次にconsole上でmain.phpを実行してみます。

```console
php main.php

→　ばななを食べる
```


りんごに変えて実行してみます。

```main.php
App\Facades\Eat::eat('りんご');
```
```console
php main.php

→　りんごを食べる
```

この様に**Eatファサード**経由で**App\Services\Eat.php**の**eatメソッド**を使用できるようになりました。

## 6.Facadeのエイリアスを張る

1~5で完成でもいいのですが、Eatファサードを使用する度に、毎回フルパスでApp\Facades\Eatと書いたり、useしたりするのも若干冗長な気がしますので、今回作成した**Eatファサード**に**エイリアス**を張って、より簡易にアクセスできるようにしていきたいと思います。

今回は、**Eatファサード**のエイリアス**Eat**を登録してきます。
今回のプロジェクトで新規で追加するものをわかりやすくするために、コメントで新規追加と入れておきます。

```config/app.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Class Aliases
    |--------------------------------------------------------------------------
    |
    | This array of class aliases will be registered when this application
    | is started. However, feel free to register as many as you wish as
    | the aliases are "lazy" loaded so they don't hinder performance.
    |
    */

    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'Str' => Illuminate\Support\Str::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,

        /**
         * 新規追加
         */
        'Eat' => App\Facades\Eat::class, <= ここに追加しました
    ],
];
```

登録したエイリアス**Eat**で**Eatファサード**にアクセスできるか試してみます。

```main.php
Eat::eat('ばなな');
```

```console
php main.php
```
表示結果
「**ばなな**を食べる。」

## 7.まとめ
1~6で新規でFacadeを作成し、使用することが可能になりました。
実際問題、Facadeを新規で作成することはさほど多くないように思えますが、新規で作成してみることで、Facadeへの見解が深まり、ライブラリ等が既存で用意しているようなFacadeを使用する際や、プログラムの設計時に役立つこともありましたので、いい勉強になったかなと思います。

疑問点や指摘等ございましたら、ぜひお願い致します。