template
PHP7
blade
LaraDock
laravel5.6

これからWeb開発のバックエンドを学ぶ in 2018(PHP7編 - 1.7日目)|Laravel5.6のBlade(Component)を用いたコンポーネント志向なレイアウト作り

これからWeb開発のバックエンドを学ぶ in 2018(PHP7編 - 1.3日目)|自宅サーバでWebサイト公開の続きです。

LaravelにはBladeというテンプレート機能が用意されています。

それを使った簡単な実装はUdemyのオンライン教材
【2日でできる】はじめての PHP 7 x Laravel 5.5 入門で学びましたが、Laravel5.5での実装でした。

Bladeを利用してコンポーネント志向なビューにする

私の環境はLaravel5.6なので、もうちょいナウな実装に取り組む事にしました。
JSフレームワークでお馴染みのコンポーネント志向な実装に変えてみました。

Conponentの書き方の基本

Laravel公式サイト|コンポーネントの使い方

Laravel5.5と5.6でのコンポーネントの書き方の違い

Laravel5.5ではこういう感じでした

Laravel5.5のComponentの呼び出し
@component('component.alert', ['foo', $foo])
・・・・・
@endcomponent

Laravel5.6では、より簡潔で直感的な呼び出しが可能となっており、今回はその記述方法を採用しました。

Laravel5.6のComponentの呼び出し
@alert(['foo', $foo])
・・・・・
@endalert

実装

まずはレイアウトとコンポーネントを分離

app/view/layouts/books.blade.php(レイアウト用テンプレート)
@extends('layouts.app')

@section('pageCss')
<link href="{{ asset('css/layouts/book.css') }}" rel="stylesheet">
@endsection

@section('content')
    <div class="container" >
        <div class="card-columns">
            // 本の新規登録コンポーネント
            @newBook
            @endnewBook

            // 本の一覧表示コンポーネント(パラメータとして$books変数を渡す)
            @bookList(['books' => $books])
            @endbookList

        </div>
    </div>
@endsection
app/Http/Controllers/BookController.php
・・・・・・
    public function index()
    {
        // layoutsディレクトリにBookのテンプレートを移動したので、返却するビューにディレクトリ名を付けるよう変更
-        return view('ooks', ['books' => $this->bookService::getBooks()]);
+        return view('layouts.books', ['books' => $this->bookService::getBooks()]);
    }
・・・・・・
app/providers/AppServiceProvider.php
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
+        // Bladeコンポーネントを使えるようにプロバイダー登録 
+        $this->registerComponents();
    }

+    /**
+     * Register Blade components.
+     *
+     * @return void
+     */
+    private function registerComponents(): void {
+        Blade::component('components.new-book', 'newBook');
+        Blade::component('components.book-list', 'bookList');
+    }
app/view/components/new-book.blade.php(本の新規登録コンポーネント)
<div class="card">
    <div class="card-header">
        {{ __('新規書籍の登録') }}
    </div>

    <div class="card-body">
        <!-- Display Validation Errors -->
        @include('common.errors')

        <!-- New Book Form -->
        <form action="/books" method="POST" class="form-horizontal">
            {{ csrf_field() }}

            <!-- Book Name -->
            <div class="form-group">
                <label for="task-name" class="col-sm-3 control-label">{{ __('書籍名') }}</label>

                <div class="col-sm-6">
                    <input type="text" name="name" id="book-name" class="form-control" value="{{ old('book') }}">
                </div>
            </div>

            <!-- Add Book Button -->
            <div class="form-group">
                <div class="col-sm-offset-3 col-sm-6">
                    <button type="submit" class="btn btn-primary">
                        <i class="fa fa-plus"></i>{{ __('追加') }}
                    </button>
                </div>
            </div>
        </form>
    </div>
</div>
app/view/components/book-list.blade.php(本の一覧表示コンポーネント)
@if (count( $books  ) > 0)
    <div class="card">
        <div class="card-header">
            {{ __('書籍一覧') }}
        </div>

        <div class="card-body">
            <table class="table table-striped task-table">
                <thead>
                    <th>{{ __('書籍名') }}</th>
                    <th>&nbsp;</th>
                </thead>
                <tbody>
                    @foreach ($books as $book)
                        <tr>
                            <td class="table-text"><div>{{ $book->title }}</div></td>

                            <!-- Task Delete Button -->
                            <td>
                                <form action="/books/{{ $book->id }}" method="POST">
                                    {{ csrf_field() }}
                                    {{ method_field('DELETE') }}

                                    <button type="submit" class="btn btn-danger">
                                        <i class="fa fa-trash"></i>{{ __('削除') }}
                                    </button>
                                </form>
                            </td>
                        </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    </div>
</div>
@endif

画面表示できた

書籍レイアウトの中に
・上部が新規登録コンポーネントとして表示
・下部が一覧表示コンポーネントとして表示

スクリーンショット 2018-03-18 15.45.18.png

途中困った事

一覧表示コンポーネントに渡したパラメータの\$booksですが、最初はbook-list.blade.php側で
{{$books}}として記述していたのですが、うまく認識されずにエラーになり続けてました。

呼び出し元のレイアウト側からパラメータを渡す際に

@bookList(['books' => 'books'])
@endbookList

としていたのが原因でした。変数としてじゃなく文字列で渡してた。。。
これを

@bookList(['books' => $books])
@endbookList

として、コンポーネントのテンプレート側は、普通に$booksとして記述する事でちゃんと配列として
コンポーネントへパラメータを渡すことができ、動くようになりました。

コンポーネント毎のCSSを用意して分離できればなって思ってますが、何か方法あるんでしょうか。

今回の修正履歴

https://github.com/masaaki-uegaki/bookapp/commit/810f7195e5bae1fb42d7a64bb3c505859b5dd90a

自宅サーバで公開した作成中アプリ

書籍リスト

勉強で作ってるプロジェクトのソース

https://github.com/masaaki-uegaki/bookapp