Laravel 4: Be Careful With Your After Filters

April 4, 2014 —John Koster

Laravel 4 provides a convenient after filter. This filter will run after your routes and controllers have run. There are many awesome things you can do in the filter, such as logging, or checking various things. A basic usage of this filter might start out like this:

1<?php
2 
3App::after(function($request, $response)
4{
5 if($response instanceof IlluminateHttpResponse)
6 {
7 
8 }
9});

In the above code, we are providing a callback to the after filter and then checking to make sure that the $response argument is an instance of IlluminateHttpResponse. You could use this filter to create a little utility to compress the HTML output before it is sent to the client (I won't get into that here). The basic structure might look like this:

1<?php
2 
3App::after(function($request, $response)
4{
5 if($response instanceof IlluminateHttpResponse)
6 {
7 $output = $response->getOriginalContent();
8 
9 // Do some processing here.
10 
11 $response->setContent($output);
12 }
13});

There is nothing wrong with the above code. It would work just fine. But imagine for a minute that the original content was View. And let's pretend that some coder had placed a function call or a query inside their view, instead of just displaying the value from something inside a repository or controller.

When the last line is called, the $response->setContent($output), PHP will cast the view object to a string, which will run its render() function again. So, if there were nested queries inside the view (which shouldn't be there), the queries would get ran once before the after filter was called, and then again when the view is being cast back into the string.

If this issue arises, and doing processing inside the after function is the only way to solve a problem, the above code example can be changed to this:

1<?php
2 
3App::after(function($request, $response)
4{
5 if($response instanceof IlluminateHttpResponse)
6 {
7 $output = $response->getContent(); // Different function
8 
9 // Do some processing here.
10 
11 $response->setContent($output);
12 }
13});

The only thing that changed in the above code was to use the getContent() function, which returns a string. This method doesn't interact with a view object, and therefore does not have to concern itself with the view being re-cast into a string.

#A Quick Note

This really only applies if the code is actually returning a view. Some code might return a JSON object, or some other textual data.

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.