Laravel5.5 LTS 日本語ドキュメント

このリポジトリはPHP Webアプリフレームワークである、LaravelのLTSバージョンである5.5の公式英文ドキュメントを日本語へ翻訳しています。

This project is maintained by okinaka

Bladeテンプレート

イントロダクション

BladeはシンプルながらパワフルなLaravelのテンプレートエンジンです。他の人気のあるPHPテンプレートエンジンとは異なり、ビューの中にPHPを直接記述することを許しています。全BladeビューはPHPへコンパイルされ、変更があるまでキャッシュされます。つまりアプリケーションのオーバーヘッドは基本的に0です。Bladeビューには.blade.phpファイル拡張子を付け、通常はresources/viewsディレクトリの中に設置します。

テンプレートの継承

レイアウト定義

Bladeを使用する主な利点は、テンプレートの継承セクションです。初めに簡単な例を見てください。通常ほとんどのアプリケーションでは、数多くのページを同じ全体的なレイアウトの中に表示するので、最初は”master”ページレイアウトを確認しましょう。レイアウトは一つのBladeビューとして、簡単に定義できます。

<!-- resources/views/layouts/app.blade.phpとして保存 -->

<html>
    <head>
        <title>アプリ名 - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            ここがメインのサイドバー
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

ご覧の通り、典型的なHTMLマークアップで構成されたファイルです。しかし、@section@yieldディレクティブに注目です。@sectionディレクティブは名前が示す通りにコンテンツのセクションを定義し、一方の@yieldディレクティブは指定したセションの内容を表示するために使用します。

これでアプリケーションのレイアウトが定義できました。このレイアウトを継承する、子のページを定義しましょう。

レイアウト拡張

子のビューを定義するには、「継承」するレイアウトを指定する、Blade @extendsディレクティブを使用します。Bladeレイアウトを拡張するビューは、@sectionディレクティブを使用し、レイアウトのセクションに内容を挿入します。前例にあるようにレイアウトでセクションを表示するには@yieldを使用します。

<!-- resources/views/child.blade.phpとして保存 -->

@extends('layouts.app')

@section('title', 'Page Title')

@section('sidebar')
    @@parent

    <p>ここはメインのサイドバーに追加される</p>
@endsection

@section('content')
    <p>ここが本文のコンテンツ</p>
@endsection

この例のsidebarセクションでは、レイアウトのサイドバーの内容をコンテンツに上書きするのではなく追加するために@@parentディレクティブを使用しています。@@parentディレクティブはビューをレンダーするときに、レイアウトの内容に置き換わります。

{tip} 直前の例とは異なり、このsidebarセクションは@showの代わりに@endsectionで終わっています。@endsectionディレクティブはセクションを定義するだけに対し、@showは定義しつつ、そのセクションを即時にその場所に取り込みます

Bladeビューはグローバルなviewヘルパを使用し、ルートから返すことができます。

Route::get('blade', function () {
    return view('child');
});

コンポーネントとスロット

コンポーネントとスロットは、セクションとレイアウトと似た利便を提供します。しかし、コンポーネントとスロットのメンタルモデルのほうが簡単に理解できることに気づくはずです。最初に、アプリケーション全体で再利用する、”alert”コンポーネントをイメージしてください。

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    
</div>

``変数は、このコンポーネントへ注入しようとする内容を含んでいます。では、このコンポーネントを構築するため、@component Bladeディレクティブを使いましょう。

@component('alert')
    <strong>Whoops!</strong> Something went wrong!
@endcomponent

一つのコンポーネントに対し、複数のスロットを定義するのも、役立つことがあるでしょう。”title”を注入できるようにalertコンポーネントを改造してみましょう。名前付きスロットは、名前に一致する変数をただ”echo”します。

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    <div class="alert-title"></div>

    
</div>

これで、@slotディレクティブを使い、名前付きスロットへ内容を注入できます。@slotディレクティブ範囲外の全内容は、$slot変数の中のコンポーネントへ渡されます。

@component('alert')
    @slot('title')
        Forbidden
    @endslot

    You are not allowed to access this resource!
@endcomponent

コンポーネントへ追加のデータを渡す

場合により、コンポーネントへ追加のデータを渡す必要が起きます。そのため、@componentディレクティブの第2引数で、データの配列が渡せます。全データはテンプレート中で変数として利用できます。

@component('alert', ['foo' => 'bar'])
    ...
@endcomponent

データ表示

Bladeビューに渡されたデータは、波括弧で変数を囲うことで表示できます。たとえば、次のルートがあるとしましょう。

Route::get('greeting', function () {
    return view('welcome', ['name' => 'Samantha']);
});

name変数の内容を表示しましょう。

Hello, .

もちろんビューに渡された変数の内容を表示するだけに限られません。PHP関数の結果をechoすることもできます。実際、どんなPHPコードもBladeのecho文の中に書けます。

The current UNIX timestamp is .

{tip} Bladeの``記法はXSS攻撃を防ぐため、自動的にPHPのhtmlspecialchars関数を通されます。

エスケープしないデータの表示

デフォルトでブレードの``文はXSS攻撃を防ぐために、PHPのhtmlspecialchars関数を自動的に通されます。しかしデータをエスケープしたくない場合は、以下の構文を使ってください。

Hello, {!! $name !!}.

{note} アプリケーションでユーザーの入力内容をechoする場合は注意が必要です。ユーザーの入力を表示するときは、常に二重の波括弧の記法でHTMLエンティティにエスケープすべきです。

JSONのレンダ

JavaScriptの変数を初期化するために、配列をビューに渡してJSONとして描画することができます。

<script>
    var app = <?php echo json_encode($array); ?>;
</script>

その際、json_encodeを使う代わりに、@jsonディレクティブを使うことができます。

<script>
    var app = @json($array);
</script>

BladeとJavaScriptフレームワーク

多くのJavaScriptフレームワークでも、与えられた式をブラウザに表示するために波括弧を使っていますので、@シンボルでBladeレンダリングエンジンに波括弧の展開をしないように指示することが可能です。

<h1>Laravel</h1>

Hello, @.

この例で、@記号はBladeにより削除されます。しかし、``式はBladeエンジンにより変更されずにそのまま残り、JavaScriptフレームワークによりレンダリングできるようになります。

@verbatimディレクティブ

テンプレートの広い箇所でJavaScript変数を表示する場合は、HTMLを@verbatimディレクティブで囲めば、各Blade echo文の先頭に@記号を付ける必要はなくなります。

@verbatim
    <div class="container">
        Hello, .
    </div>
@endverbatim

制御構文

テンプレートの継承とデータ表示に付け加え、Bladeは条件文やループなどの一般的なPHPの制御構文の便利な短縮記述方法を提供しています。こうした短縮形は、PHP制御構文の美しく簡潔な記述を提供しつつも、対応するPHPの構文と似せています。

If文

if文の構文には、@if@elseif@else@endifディレクティブを使用します。これらの使い方はPHPの構文と同じです。

@if (count($records) === 1)
    1レコードある!
@elseif (count($records) > 1)
    複数レコードある!
@else
    レコードがない!
@endif

便利な@unlessディレクティブも提供しています。

@unless (Auth::check())
    あなたはログインしていません。
@endunless

さらに、既に説明したように@isset@emptyディレクティブも、同名のPHP関数の便利なショートカットとして使用できます。

@isset($records)
    // $recordsは定義済みでnullでない
@endisset

@empty($records)
    // $recordsが「空」だ
@endempty

認証ショートカット

@auth@guestディレクティブは、現在のユーザーが認証されているか、もしくはゲストであるかを簡単に判定するために使用します。

@auth
    // ユーザーは認証済み
@endauth

@guest
    // ユーザーは認証されていない
@endguest

必要であれば、@auth@guestディレクティブ使用時に、確認すべき認証ガードを指定できます。

@auth('admin')
    // ユーザーは認証済み
@endauth

@guest('admin')
    // ユーザーは認証されていない
@endguest

Switch文

@switch@case@break@default@endswitchディレクティブを使用し、switch文を構成できます。

@switch($i)
    @case(1)
        最初のケース
        @break

    @case(2)
        2番めのケース
        @break

    @default
        デフォルトのケース
@endswitch

繰り返し

条件文に加え、BladeはPHPがサポートしている繰り返し構文も提供しています。これらも、対応するPHP構文と使い方は一緒です。

@for ($i = 0; $i < 10; $i++)
    現在の値は: 
@endfor

@foreach ($users as $user)
    <p>これは  ユーザーです。</p>
@endforeach

@forelse ($users as $user)
    <li></li>
@empty
    <p>ユーザーなし</p>
@endforelse

@while (true)
    <p>無限ループ中</p>
@endwhile

{tip} 繰り返し中はループ変数を使い、繰り返しの最初や最後なのかなど、繰り返し情報を取得できます。

繰り返しを使用する場合、ループを終了するか、現在の繰り返しをスキップすることもできます。

@foreach ($users as $user)
    @if ($user->type == 1)
        @continue
    @endif

    <li></li>

    @if ($user->number == 5)
        @break
    @endif
@endforeach

もしくは、ディレクティブに条件を記述して、一行で済ますこともできます。

@foreach ($users as $user)
    @continue($user->type == 1)

    <li></li>

    @break($user->number == 5)
@endforeach

ループ変数

繰り返し中は、$loop変数が使用できます。この変数により、現在のループインデックスや繰り返しの最初/最後なのかなど、便利な情報にアクセスできます。

@foreach ($users as $user)
    @if ($loop->first)
        これは最初の繰り返し
    @endif

    @if ($loop->last)
        これは最後の繰り返し
    @endif

    <p>これは  ユーザーです。</p>
@endforeach

ネストした繰り返しでは、親のループの$loop変数にparentプロパティを通じアクセスできます。

@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            これは親のループの最初の繰り返しだ
        @endif
    @endforeach
@endforeach

$loop変数は、他にもいろいろと便利なプロパティを持っています。

プロパティ 説明
$loop->index 現在のループのインデックス(初期値0)
$loop->iteration 現在の繰り返し数(初期値1)
$loop->remaining 繰り返しの残り数
$loop->count 繰り返し中の配列の総アイテム数
$loop->first ループの最初の繰り返しか
$loop->last ループの最後の繰り返しか
$loop->depth 現在のループのネストレベル
$loop->parent ループがネストしている場合、親のループ変数

コメント

Bladeでビューにコメントを書くこともできます。HTMLコメントと異なり、Bladeのコメントはアプリケーションから返されるHTMLには含まれません。

PHP

PHPコードをビューへ埋め込むと便利な場合もあります。Bladeの@phpディレクティブを使えば、テンプレートの中でプレーンなPHPブロックを実行できます。

@php
    //
@endphp

{tip} Bladeはこの機能を提供していますが、数多く使用しているのであれば、それはテンプレートへ多すぎるロジックを埋め込んでいるサインです。

サブビューの読み込み

Bladeの@includeディレクディブを使えば、ビューの中から簡単に他のBladeビューを取り込めます。読み込み元のビューで使用可能な変数は、取り込み先のビューでも利用可能です。

<div>
    @include('shared.errors')

    <form>
        <!-- フォームの内容 -->
    </form>
</div>

親のビューの全データ変数が取り込み先のビューに継承されますが、追加のデータも配列で渡すことができます。

@include('view.name', ['some' => 'data'])

もちろん、存在しないビューを@includeすれば、Laravelはエラーを投げます。存在しているかどうかわからないビューを取り込みたい場合は、@includeIfディレクティブを使います。

@includeIf('view.name', ['some' => 'data'])

指定した論理条件にもとづいて@includeしたい場合は、@includeWhenディレクティブを使用します。

@includeWhen($boolean, 'view.name', ['some' => 'data'])

指定するビューの配列から、最初に存在するビューを読み込むには、includeFirstディレクティブを使用します。

@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])

{note} Bladeビューの中では__DIR____FILE__を使わないでください。キャッシュされたコンパイル済みのビューのパスが返されるからです。

コレクションのレンダービュー

Bladeの@eachディレクティブを使い、ループとビューの読み込みを組み合わせられます。

@each('view.name', $jobs, 'job')

最初の引数は配列かコレクションの各要素をレンダーするための部分ビューです。第2引数は繰り返し処理する配列かコレクションで、第3引数はビューの中の繰り返し値が代入される変数名です。ですから、たとえばjobs配列を繰り返す場合なら、部分ビューの中で各ジョブにはjob変数としてアクセスしたいと通常は考えるでしょう。 現在の繰り返しのキーは、部分ビューの中のkey変数で参照できます。

@eachディレクティブには第4引数を渡たせます。この引数は配列が空の場合にレンダーされるビューを指定します。

@each('view.name', $jobs, 'job', 'view.empty')

{note} @eachを使ってレンダされるビューは、親のビューから変数を継承しません。子ビューで親ビューの変数が必要な場合は、代わりに@foreach@includeを使用してください。

スタック

Bladeはさらに、他のビューやレイアウトでレンダーできるように、名前付きのスタックへ内容を退避できます。子ビューで必要なJavaScriptを指定する場合に、便利です。

@push('scripts')
    <script src="/example.js"></script>
@endpush

必要なだけ何回もスタックをプッシュできます。スタックした内容をレンダーするには、@stackディレクティブにスタック名を指定してください。

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

    @stack('scripts')
</head>

サービス注入

@injectディレクティブはLaravelのサービスコンテナからサービスを取得するために使用します。@injectの最初の引数はそのサービスを取り込む変数名で、第2引数は依存解決したいクラス/インターフェイス名です。

@inject('metrics', 'App\Services\MetricsService')

<div>
    Monthly Revenue: .
</div>

Blade拡張

Bladeではdirectiveメソッドを使い、自分のカスタムディレクティブを定義することができます。Bladeコンパイラがそのカスタムディレクティブを見つけると、そのディレクティブに渡される引数をコールバックへの引数として呼び出します。

次の例は@datetime($var)ディレクティブを作成し、渡されるDateTimeインスタンスの$varをフォーマットします。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * サービスの初期起動後に登録する
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('datetime', function ($expression) {
            return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
        });
    }

    /**
     * コンテナへ結合を登録する
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

ご覧の通り、ディレクティブがどんなものであれ、渡された引数にformatメソッドをチェーンし、呼び出しています。そのため、この例のディレクティブの場合、最終的に生成されるPHPコードは、次のようになります。

<?php echo ($var)->format('m/d/Y H:i'); ?>

{note} Bladeディレクティブのロジックを更新した後に、Bladeビューのキャッシュを全部削除する必要があります。view:clear Artisanコマンドで、キャッシュされているBladeビューを削除できます。

カスタムif文

シンプルなカスタム条件文を定義する時、必要以上にカスタムディレクティブのプログラミングが複雑になってしまうことが、時々起きます。そのため、Bladeはクロージャを使用し、カスタム条件ディレクティブを素早く定義できるように、Blade::ifメソッドを提供しています。例として、現在のアプリケーション環境をチェックするカスタム条件を定義してみましょう。AppServiceProviderbootメソッドで行います。

use Illuminate\Support\Facades\Blade;

/**
 * サービスの初期処理後に実行
 *
 * @return void
 */
public function boot()
{
    Blade::if('env', function ($environment) {
        return app()->environment($environment);
    });
}

カスタム条件を定義したら、テンプレートの中で簡単に利用できます。

@env('local')
    // アプリケーションはlocal環境
@elseenv('testing')
    // アプリケーションはtesting環境
@else
    // アプリケーションは、local環境でもtesting環境でもない
@endenv