bladeのcomponent化による再利用

最近 blade を使ったhtmlのコンポーネント化について調べたのでまとめます。
Laravel公式の[bladeテンプレート](https://readouble.com/laravel/5.8/ja/blade.html)のセクションにも記載があり、実用できそうでした。

## サンプル
コンポーネントを`/resources/views/components/attribute.blade.php`から呼び出すサンプルです。

`resources/views/sample.blade.php`

```php
<div class="attribute-wrapper">
    @component('components.attribute',
                ['attributeName'=>__("氏名"),
                    'required'=>true,
                    'attributeInfo'=> __("名前を入力してください")])
    @endcomponent
</div>
```

`/resources/views/components/attribute.blade.php`

```php
<div class="attribute-name">
    <span>{{ $attributeName }}</span>
    <div class="d-flex justify-content-between position-relative">
        @if($required)
        <div class="required ">{{ __('必須') }}</div>
        @endif
        <i class="fas fa-info-circle attribute-info-mark"></i>
        <p class="attribute-info">{{ $attributeInfo }}</p>
        
    </div>
</div>
```

## cssとhtmlの記述をbladeで完結させたい
コンポーネント化をすすめていく中で、cssとhtmlの記述をbladeで完結させたいと思いつきました。
調べたところ@ push ディレクティブと、@ stackディレクティブを使うと
pushしたテンプレートをstackで取り出すことができるようです。
>スタック
Bladeはさらに、他のビューやレイアウトでレンダできるように、名前付きのスタックへ内容を退避できます。子ビューで必要なJavaScriptを指定する場合に、便利です。

```php
@push('scripts')
    <script src="/example.js"></script>
@endpush
```
>必要なだけ何回もスタックをプッシュできます。スタックした内容をレンダするには、@stackディレクティブにスタック名を指定してください。

```php
<head>
    <!-- Headの内容 -->

    @stack('scripts')
</head>
```

laravel5.8公式ドキュメント(https://readouble.com/laravel/5.8/ja/blade.html)

## コンポーネントのcssが複数回呼び出される
stackに登録したcssを呼び出すと、コンポーネントが複数回呼び出されている場合、複数の同じcssが登録されてしまいました。
解決方法として、Bladeファサードを使い、同一コンポーネントからの同じ要素のpushを防ぐ独自のディレクティブ pushonceを作成することで解決する方法を記載します。

### 1. pushonceディレクティブの登録

`App\Providers\AppServiceProvider`

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
        \Blade::directive('pushonce', function ($expression) {
            $var = '$__env->{"__pushonce_" . md5(__FILE__ . ":" . __LINE__)}';
        
            return "<?php if(!isset({$var})): {$var} = true; \$__env->startPush({$expression}); ?>";
        });
        
        \Blade::directive('endpushonce', function ($expression) {
            return '<?php $__env->stopPush(); endif; ?>';
        });
    }

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

```

### 2. component毎にcssをpushする
`resources\views\components\operations.blade.php`

```php
div class="operations-container status-bar">
    {{ $slot }}
</div>

@pushonce('css')
    <style>
        .operations-container{
            display: flex;
            /* justify-content: space-evenly; */
            flex-flow: row wrap;
            align-content: space-around;
        }
    </style>
@endpushonce

```
pushonceの呼び出し方は、pushと全く同じです。

### 3. stackで css を呼び出す。

`resources\views\layouts\app.blade.php`

```php

    <body>
       <main id="app">
            <div class="main-container">
                @yield('content')  
            </div>
        </main>
    </body>
    @stack('css') 

```
stackは通常の通りの呼び出しです。
これでコンポーネントのcssの重複呼び出しはなくなりました。

以上です。