前回、validate()のソースコードで登場したマクロ、今回は有用なマクロの活用の例を紹介します。

マクロに関してのLaravelのマニュアルでは以下で、response()のマクロの例が紹介されています。

https://laravel.com/docs/5.5/responses#response-macros

これを見て「あ、これはここで使える!」と思ったのは、コントローラから出力するHTMLの中身の画像のURLの変換です。

まずは、ちょっと背景説明を。

私のお客さんのサイトでは画像がかなり多いので、サーバー(EC2)の負担を減らすために画像はすべてAWSのS3にアップしています。どれだけアクセスがあっても画像はS3から配信されるのでサーバーが落ちる心配もないし、サーバーをアップグレードする必要もなくコストセーブとなります。

しかし、ブレードを管理するデザイナーに、

<img src="/user/images/example.jpg">

のような参照を、

<img src="//example.s3.amazonaws.com/user/images/example.jpg">

と毎回書き換えてもらうのは、やっかい。もちろん、エディターやsassとかでのプリ処理は可能だけれども、1つステップ増えるしプログラマでないデザイナーにはちょっと。また、S3のURLも本サイトと開発サイトでは変えたいケースもあり、そうしてもらうとこちらも困ります。

ということで、出力時にダイナミックに変えるのは必須となりました。ダイナミックに変えるには、ウェブサーバーでの設定でも可能ですが、やはり、HTMLの中にS3のURLが入るのがサーバーにも負担にならず、ユーザーにとっても表示速度の点で最適です。

このために、以下のようなユーザー定義のヘルパーを作成して、

// Lobは、私の会社 Lots of Bytesの略です。

class Lob {
    ...
    public static function view($view, $data)
    {       
        $host = '//example.s3.amazonaws.com';
        $html = View::make($view)->with($data)->render());
        $output = preg_replace('#/user/images/#', $host.'/user/images/, $html);    

        return response($output);
    }
  ...
}

コントローラで以下のように、コールしていました。

    return Lob::view('user/product', compact('page', 'product'));

これで用は足りるのですが、なんかLaravelらしくない。

そこで、マクロの登場です。

app/Providers/AppServiceProvider.phpを編集して、viewWithS3のマクロを定義します。


namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\View;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);

        Response::macro('viewWithS3', function ($view, $data) {
            $host = '//example.s3.amazonaws.com';
            $html = View::make($view)->with($data)->render());
            $output = preg_replace('#/user/images/#', $host.'/user/images/, $html);

            // 以下の$thisは、AppServiceProviderのインスタンスでなく、Illuminate\Http\Response
            return $this->make($output); 
        });
    }
...
}

コントローラでは、以下のようにコールします。Laravelらしくわかりやすくなりましたね。

        return response()->viewWithS3('user/product', compact('page', 'product'));

By khino