Let's take a little closer look at Laravel Blades. In my usual style I'm going to start us really super simple and challenge what you "know", then we'll peek at some more interesting features, include the new to 5.1 @inject.

The Basics: @stop vs. @endsection vs. @show

Make a new view and call it "basic.blade.php", then add this code:

@section('basic_section_1')
    {{ "Basic body 1" }}
@stop

@section('basic_section_2')
    {{ "Basic body 2" }}
@endsection

@section('basic_section_3')
    {{ "Basic body 3" }}
@show

@yield('basic_section_1')
@yield('basic_section_2')	
@yield('basic_section_3')

When you look at page, you might expect to see "Basic body 1 Basic body 2 Basic body 3", right? But instead, the order is 3, 1, 2. This introduces us to our first point - @stop/@endsection vs. @show.

We can see what is happening merely from the behavior. @stop and @endsection are buffering the content, to be used later. @show echos the content directly - but without being reusable (you'll notice the 3rd yield didn't render anything). This one time let's dip into the source code to help set our foundation.

Open up Illuminate\View\Compilers\BladeCompiler.php and check out compileShow() for starters.


protected function compileShow($expression)
{
	return "<?php echo \$__env->yieldSection(); ?>";
}	

You notice this is an echo function - it will render the content. Contrast with compileEndsection() where it merely stops (although after doing more, which will tackle in a moment.) The scary looking part is the $__env, but I'll tip you off. It corresponds to the Illuminate\View\Factory, and if you open that up you can see the yieldSection() function. Studying these two files, we can see the division of work. BladeCompiler is converting the blade syntax into php statements, and Factory is running them.

A last thought about this all. If @stop and @endsection buffer the data for later use, they must be stored somewhere, right? So it is safe to imagine there is a content array of some sort handling all of this, like $content['basic_section_1'] = "Basic body 1". So if we are essentially just working with an array of stored strings, that starts to make all these @yield and @parent and other directives a lot easier to figure out what must be happening, doesn't it?

So what is the difference between @stop and @endsection? Nothing - check your BladeCompiler.php again. If memory serves, @stop is just the old v3 directive that was left in for backward compatibility.

Let's touch on a few more topics more briefly, so we don't run too long. These are all well documented, but you should make an effort to know that they are there.

@parent

This is one of the inheritance features of Blade that I don't see used very often, with people opting for using @include partials instead. It's an interesting one to study though - perhaps you'll find a use case.

@parent takes no parameter, and instead refers to a @section of the same name and on the blade you are extending.

// from layouts/master.blade.php
@section('main')
	{{ "I'm in the main" }}

	{{ $var or '' }}
@show	

// from welcome.blade.php
@extends('layouts.master')

@section('main')
	{{ "Prepend me" }}
	@parent
	{{ "Append me" }}

	<?php $var = "I'm a child" ?>
@show	

Notice that because we inject the welcome blade into the master, we can set the variable there. So if these were a series of partials you could make these injections dynamic. Notice also that I use the blade "or" - one of Taylor's nice little additions that allows us to set a default. (If we tried to set a default $var in the master blade, it would always be getting called after the welcome blade, and so we couldn't pass it in).

I'll be honest - I don't do a lot of view inheritance and am not really sure what use cases you would want this for instead of @includes, but I'd love to hear your ideas.

View::exists('myview')

Does what it says - checks to see if the view file exists. I include it to share a little trick I recently used, where I wanted a certain view for most of the index routes I had, but wanted to be able to overwrite them for a specific route without using conditionals.

$view = (\View::exists('objects.'.$this->model.'.index')) ? 'objects.'.$this->model.'.index' : 'objects.index'; 
return View::($view);	

Using the above, I would check if there was an index.blade made for the specific object or else just use the main generic version at "objects/index".

@inject

And now for something totally new! This is due to come out with 5.1, but you can already go play with it - Service Injection. The new @inject declaration allows you to call a service directly and return it into a variable, then use it. An example from the docs:

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

Monthly Revenue: {{ $metrics->monthlyRevenue() }}.

Now I'll be honest - my first impression was to recoil in horror as I listened to how we've come full circle and are once again making db calls from our views. However...I do like the ability to encapsulate your code into a little "package" that lives independently. This could be ideal for dashboard-type apps with lots of dynamically added widgets, for example. So give it a try, but don't abuse it.

So there's a few thoughts on Blades that might open up some ideas for you beyond the very basics. Hope they help!

Read it Monday, Use it by Friday!

Laravel Quick Tips Weekly Newsletter. Short, immediately helpful bits you'll use in your own codebase before the next one arrives.

Join us now and get a FREE PDF of the first fix months of Laravel Quick Tips!

No Spam, Unsubscribe Anytime

Contact me