【Laravel】ファサードとヘルパー関数とマクロでアプリ全体で使用できる共通部品を作る

## 環境
Laravel sail
https://readouble.com/laravel/10.x/ja/sail.html
OS: Mac

## 背景
自分で新しくファサード、ヘルパー、マクロなどを実装する機会って少ないですよね・・・？
え？そうでもない？？

一からプロジェクトを立ち上げるフェーズなら、上記の実装は結構やるとおもいますが、稼働が始まっていて追加機能開発などの案件だと、`すでに実装されているものを使う`　あるいは　`改修する`がほとんどちゃいますかね？

自分はそういう感じで、`使ったことはあるけど一から実装したことがない`という状態だったので、改めて整理して〜なぁ〜っておもたんやわ。

## 作るもの
* アンスコをスペースに置換する処理
イメージは
```
こん_にちは
↓↓
こん にちは
```

## ファサードで実装してみる
### サービスクラスの作成
```php:app/Services/TextFormatterService.php
<?php

namespace App\Services;

class TextFormatterService
{
    public function __construct()
    {
        //
    }

    public function space(string $text): string
    {
        // アンスコをスペースに置換
        return str_replace('_', ' ', $text);
    }
}
```

### ファサードクラス作成
```php:app/Facades/TextFormatter.php
<?php

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class TextFormatter extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'text-formatter';
    }
}

```

### サービスプロバイダ作成
```php:app/Providers/TextFormatterServiceProvider.php
<?php

namespace App\Providers;

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

class TextFormatterServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        $this->app->bind('text-formatter', function () {
            return new TextFormatterService();
        });
    }

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

### サービスプロバイダの登録
```php:config/app.php
    'providers' => 
// 略
App\Providers\TextFormatterServiceProvider::class,
    ])->toArray(), // こちら追記
```


### tinkerで動作確認
```
> App\Facades\TextFormatter::space('こん_にちは')
= "こん にちは"
```

```php:config/app.phpのaliasesに登録すれば、namespaceは書かなくてもよくなるよ
    'aliases' => Facade::defaultAliases()->merge([
        'TextFormatter' => App\Facades\TextFormatter::class,
    ])->toArray(),
````

```
> TextFormatter::space('こん_にちは')
= "こん にちは"
```

## ヘルパー関数で実装
### helpers.phpファイルを作成
```php:app/Helpers/helpers.php
<?php

if (!function_exists('space')) {
    function space(string $text): string
    {
        // アンスコをスペースに置換
        return str_replace('_', ' ', $text);
    }
}

```

### composer.jsonファイルにファイルパスを登録
```json:composer.json
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        },
        // ↓↓ここを追加
        "files": [
            "app/Helpers/helpers.php"
        ]
    },
```

### ヘルパーファイルをロードする。
```
composer dump-autoload
```

### tinkerで動作確認
```
# php artisan tinker
Psy Shell v0.11.18 (PHP 8.2.6 — cli) by Justin Hileman
> space('こん_にちは')
= "こん にちは"
```

Yes！！ This is it!!
That's what I expeted!

## マクロで実装
### サービスプロバイダを作成
```php:app/Providers/MacroServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Str;
use Illuminate\Support\ServiceProvider;

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

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // Strにspaceというメソッドを追加
        Str::macro('space', function (string $text) {
            return str_replace('_', ' ', $text);
        });
    }
}

```

### サービスプロバイダを登録
```php:config/app.php
    'providers' => ServiceProvider::defaultProviders()->merge([
// 略
        App\Providers\MacroServiceProvider::class,
// 略
```

### tinkerで動作確認
```console
> Str::space('こん_にちは')
= "こん にちは"
```

これでLaravelのStrを拡張して使えるようになりました。


## 感想
とりあえず実装の流れを整理しました。
基本的に必要になるファイル群がわかったので、１から立ち上げる際にもまず困ることはないでしょう。

ただ、マクロの登録は、実装と登録部分を分けて実装することもあるかと思います。
・サービスプロバイダのbootメソッドでapp/Macros配下を動的に読み込んで登録
・実装はMacros配下に

みたいな流れですね。

プロジェクトの方針に従ってやるだけなので、本記事のファイル群の関連性だけ把握していればあとは大体なんとでも対処できると思います。

## メモ
### sailのtinkerの日本語対応
tinkerの日本語対応をしていないと謎の文字列が表示されます。本記事作成時には以下の手順で設定しました。
https://qiita.com/mako0104/items/b0d213c03280c4d331cb

Dockerfileいじればもっと簡単。