LoginSignup
13
11

More than 3 years have passed since last update.

Bladeテンプレートの@showと@endsectionを間違えないようにする

Posted at

この記事はLaravel 5.7.19をもとに書かれています。

要約

  • 親テンプレートの中では@showを使う
  • 子の中では@endsectionを使う

事の始まり

Laravelの公式ドキュメントの日本語訳としてよくお世話になるreadoubleですが、そのBladeテンプレートの項にこんな記述があります。

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

なんとなく言っていることが分かるような分からないような…
曖昧なままコードを書くのは火傷の元、ということで今一度ちゃんとこのあたりの整理をしようと思いました。

実験

普通に書いてみる

まずはreadoubleにあるのと同じようなコードを書いてみます。

layouts/app.blade.php
<html>
<head>
    <title>Bladeテスト</title>
</head>
<body>
@section('content')
    <p>親の内容</p>
@Show 
</body>
</html>
child.blade.php
@extends('layouts.app')

@section('content')
    @parent

    <p>子の内容</p>
@endsection

app.blade.phpcontentというセクションを定義し、そこに「親の内容」という文を埋め込んでいます。
一方、child.blade.phpapp.blade.phpを継承しており、やはりcontentというセクションに「子の内容」という文を埋め込んでいます。ただし、継承元であるapp.blade.phpにもcontentセクションが存在するため、その内容に追加する形になります。1

注目すべきなのはセクションの終わりを表すディレクティブです。app.blade.phpでは@showでセクションを閉じていますが、child.blade.phpでは@endsectionでセクションを閉じています。

このコードをコンパイルブラウザで表示すると次のようなHTMLが生成されます。

<html>
<head>
    <title>Bladeテスト</title>
</head>
<body>
    <p>親の内容</p>
    <p>子の内容</p>
</body>
</html>

想定通りの出力がされました。

親でも@endsectionを使う

親テンプレートであるapp.blade.phpにおいて、@showの代わりに@endsectionを使ってみます。

layouts/app.blade.php
<html>
<head>
    <title>Bladeテスト</title>
</head>
<body>
@section('content')
    <p>親の内容</p>
@endsection {{--@show->@endsection--}}
</body>
</html>

ページをブラウザで開くと、こんなHTMLが生成されています。

<html>
<head>
    <title>Bladeテスト</title>
</head>
<body>

</body>
</html>

セクションの内容が丸々消えてしまいました!

子でも@endsectionを使う

最後に、親テンプレートであるchild.blade.phpにおいて、@endsectionの代わりに@showを使ってみます。

child.blade.php
@extends('layouts.app')

@section('content')
    @parent

    <p>子の内容</p>
@show {{--@endsection -> @show--}}

ブラウザで見てみましょう。

<html>
<head>
</head>
<body>
    <p>子の内容</p>
    <title>Bladeテスト</title>
    <p>親の内容</p>
    <p>子の内容</p>
</body>
</html>

子の内容が2度表示されてしまいます。しかも変なところに<title>タグが表れてカオス。

実験結果からわかること

どうも@showがないとそもそもセクションの内容が埋め込まれないようです。これがreadoubleで言うところの「@showは定義しつつ、そのセクションを即時にその場所に取り込みます」ということなのでしょう。逆に、@showがあるとそこで埋め込みが即座に行われてしまうため、複数回@showが記述されるような場合はやはり埋め込みも複数回発生してしまいます。

コードを読む

実際のところ@show@endsectionがどんな処理をするのか、Bladeテンプレートのコンパイル結果を見てみます。
今一度ソースコードを最初のまともに表示されていた状態に戻し、コンパイル結果を確認します。

layouts/app.blade.phpのコンパイル結果
<html>
<head>
    <title>Bladeテスト</title>
</head>
<body>
<?php $__env->startSection('content'); ?>
    <p>親の内容</p>
<?php echo $__env->yieldSection(); ?>
</body>
</html>
child.blade.phpのコンパイル結果
<?php $__env->startSection('content'); ?>
    ##parent-placeholder-040f06fd774092478d450774f5ba30c5da78acc8##

    <p>子の内容</p>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>

このように、@show<?php echo $__env->yieldSection(); ?>に、@endsection<?php $__env->stopSection(); ?>に展開されます。前者はechoされるため表示が行われるが、後者はechoがないのでそのままでは表示されないということになります。
ちなみに、これらのメソッドの実態はIlluminate\View\Concerns\ManagesLayoutsクラスに記述されています。

ManagesLayouts->yieldSection
   public function yieldSection()
    {
        if (empty($this->sectionStack)) {
            return '';
        }

        return $this->yieldContent($this->stopSection());
    }
ManagesLayouts->stopSection
    public function stopSection($overwrite = false)
    {
        if (empty($this->sectionStack)) {
            throw new InvalidArgumentException('Cannot end a section without first starting one.');
        }

        $last = array_pop($this->sectionStack);

        if ($overwrite) {
            $this->sections[$last] = ob_get_clean();
        } else {
            $this->extendSection($last, ob_get_clean());
        }

        return $last;
    }

yieldSection()は内部的にはstopSection()を呼び出すため、どちらもセクションを終わらせることがわかります。

おわり

Bladeテンプレートの表示処理は結構面白そうなので、もっといろいろ見てみたいですね。

参考


  1. @parentディレクティブを使用していない場合、親の内容に追記するのではなく、親の内容に上書きします。 

13
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11