

Service injection
There are three primary types of data we’re most likely to inject into a view: collections of data to iterate over, single objects that you’re displaying on the page, and services that generate data or views.
With a service, the pattern will most likely look like athe code below, where we inject an instance of the service into the route definition by type-hinting it in the route definition’s method signature, and then pass it into the view.
Example 4-19. Injecting services into a view via the route definition constructor
Route
::
get
(
'injecting'
,
function
(
AnalyticsService
$analytics
)
{
return
view
(
'injecting'
)
->
with
(
'analytics'
,
$analytics
);
});
Just as view composers, Blade’s service injection offers a convenient shortcut to reducing duplication in your route definitions. Normally the content of a view using the navigation service above might look like in code below
Using an injected navigation service in a view
<
div
class
=
"finances-display"
>
{{
$analytics
->
getBalance
()
}}
/
{{
$analytics
->
getBudget
()
}}
</
div
>
Blade service injection makes it easy to inject an instance of a class out of the container directly from the view, like in snippet below
Injecting a service directly into a view
@
inject
(
'analytics'
,
'App\Services\Analytics'
)
<
div
class
=
"finances-display"
>
{{
$analytics
->
getBalance
()
}}
/
{{
$analytics
->
getBudget
()
}}
</
div
>
As you can see, this @inject
method has actually made an $analytics
variable available, which we’re using later in our view.
The first parameter of @inject
is the name of the variable you’re injecting, and the second parameter is the class or interface that you want to inject an instance of. This is resolved just like when you type-hint a dependency in a constructor elsewhere in Laravel, and if you’re unfamiliar with how that works, take a look at [Link to Come] to learn more.
Just like view composers, Blade service injection makes it easy to make certain data or functionality available to every instance of a view, without having to inject it via the route definition every time.
Custom Blade directives
All of the built-in syntax of Blade that we’ve covered so far—@if
, @unless
, etc.–are called Blade directives. Each Blade directive is a mapping between a pattern (e.g. @if ($condition)
) and a PHP output (e.g. <?php if ($condition): ?>
).
Directives aren’t just for the core; you can actually create your own. You might think directives are good for making little shortcuts to bigger pieces of code—for example, @button('buttonName')
, and having it expand to a larger set of button HTML. This isn’t a terrible idea, but for simple code expansion like this you might be better off including a view partial.
I’ve found custom directives the most useful when they simplify some form of repeated logic. Let’s say we were tired of having to wrap our code with @if (Auth::guest())
(to check if a user is logged in or not) and we wanted a custom @ifGuest
directive.
As with view composers, it might be worth having a custom Service Provider to register these, but for now let’s just put it in the boot
method of App\Providers\AppServiceProvider
. Take a look at code snippet below to see what this binding will look like.
Binding a custom Blade directive
// AppServiceProvider
public
function
boot
()
{
Blade
::
directive
(
'isGuest'
,
function
()
{
return
"<?php if (Auth::guest()): ?>"
;
});
}
We’ve now registered a custom directive @isGuest
, which will be replaced with the PHP code <?php if (Auth::guest()): ?>
.
This might feel strange. You’re writing a string that will be returned and then executed as PHP. It takes a minute to get your brain wrapped around it, but once you do you can see how powerful it can be.
Warning
You might be tempted to do some logic to make your custom directive faster by performing an operation in the binding and then embedding the result within the returned string:
Blade
::
directive
(
'isGuest'
,
function
()
{
// Anti-pattern! Do not copy.
$isGuest
=
Auth
::
guest
();
return
"<?php if (
{
$isGuest
}
): ?>"
;
});
The problem with this idea is that it assumes this directive will be re-created on every page load. However, Blade caches aggressively, so you’re going to find yourself in a bad spot if you try this.
Parameters in custom Blade directives
What if you want to check a condition in your custom logic? Check out code
Example 4-23. Creating a Blade directive with parameters
// Binding
Blade
::
directive
(
'newlinesToBr'
,
function
(
$expression
)
{
return
"<?php echo nl2br
{
$expression
}
; ?>"
;
});
// In use
<
p
>@
newlinesToBr
(
$message
->
body
)
</
p
>
The $expression
parameter received by the Closure represents whatever’s within the parentheses and the parentheses themselves. So, in snippet above $expression
is actually ($message→body)
. That’s why there are no parentheses after nl2br
in the binding; they’re already included with $expression
.
So, if you find yourself constantly writing the same conditional logic over and over, consider a Blade directive.
Testing
Testing views is not common, but it’s possible. The most common method of testing views is through application testing, meaning that you’re actually calling the route that displays the views, and ensuring the views have certain content. You can also click buttons or submit forms and ensure that you are redirected to a certain page, or that you see a certain error. Learn more in [Link to Come].
Testing that a view displays certain content
// EventsTest.php
public
function
test_list_page_shows_all_events
()
{
$event1
=
factory
(
Event
::
class
)
->
create
();
$event2
=
factory
(
Event
::
class
)
->
create
();
$this
->
visit
(
'events'
)
->
andSee
(
$event1
->
title
)
->
andSee
(
$event2
->
title
);
}
TL;DR
Blade is Laravel’s templating engine. It’s a little bit like Twig and a little bit like straight PHP. Its “safe echo” brackets are {{
and }}
, its unprotected echo brackets are {!!
and !!}
, and it has a series of directives that all begin with @
(@if
and @unless
, for example).
Define a parent template and leave “holes” in it for content using @yield
and @section
/@show
. Teach its child views to extend it using @extends('parent.view.name')
, and define their sections using @section
/@endsection
. Use @parent
to reference the content of the same block in the parent.
View composers make it easy to define that, every time a particular view or subview loads, it has certain information available to it. And service injection allows the view itself to dictate what data it needs.