When someone asks you a question, unless you are in a mood or the question doesn't make sense, you will most likely give them a response. I guess other exceptions are those question-like greetings like when someone says, 'Alright?'. Even then, you should at least give them the nod in return. Some form of response.
Requests made to a web server are no different to the guy that said 'Alright?'. They will hope to get something back. In a previous chapter, our responses took the shape of strings returned from routed closures.
Something like this:
<?php
// app/Http/routes.php
Route::get('/', function () {
return 'Yeh am alright guv.';
});
Here we have the string “Yeh am alright guv.” sent back to the browser. The string is our response and is always return
ed by a routed closure or a Controller action (which we will cover later).
It would be fair to assume that we would like to send some HTML as our response. This is often the case when developing web applications.
I guess we could enclose the HTML in the response string?
<?php
// app/Http/routes.php
Route::get('/', function () {
return '<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Alright!</title>
</head>
<body>
<p>This is the perfect response!</p>
</body>
</html>';
});
Awesome! Now you see the power and grace of Laravel… just kidding. We don't want to serve HTML this way. Embedding logic would get annoying and, more importantly, it's just plain wrong!
Luckily for us, Laravel has some Response
objects that make returning a meaningful reply a whole lot easier. Let's check out the View
response since that's the most exciting one!
Views
Views are the visual part of your application. Within the Model View Controller
pattern, they make up the View
portion. That's why they are called views. It's not rocket science. Rocket science will be covered in a later chapter.
A view is just a plain text template that can be returned to the browser, though it's likely that your views will contain HTML. Views use the .php
extension and are normally located within the resources/views
directory. This means that PHP code can also be parsed within your views.
Let's just create a very simple view for now.
<!-- resources/views/simple.php -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Views!</title>
</head>
<body>
<p>Oh yeah! VIEWS!</p>
</body>
</html>
Great! A tiny bit of HTML stored in resources/views/simple.php
. Now let's make a view.
Didn't we just do that?
Haha! Yes, you did little one, but I didn't mean 'Let's make another view file.' Instead, let's make()
a new view response object based upon the view file we just created. The files representing views can be called templates. This may help you distinguish between the View
objects and the HTML templates.
<?php
// app/Http/routes.php
Route::get('/', function () {
return View::make('simple');
});
Oh, I see! You were talking about the
make()
method.
Indeed, I was little buddy! Using the View::make()
method we can create a new instance of a View
response object. The first parameter we hand to the make()
method is the view template that we wish to use. You will notice that we didn't use the full path resources/views/simple.php
. This is because Laravel is clever. It will by default assume that your views are located in resources/views
and will look for a file with an appropriate view extension.
Tip You can use the global function
view()
instead ofView::make()
to simplify your applications.
If you look a little closer at the Closure
, you will see that the View
object we have created is being returned. This is very important since Laravel will serve the result of our Closure to the web browser.
Go ahead and try hitting the /
URI for your application. Great, that's the template we wrote!
Later in the book, you will learn how to make different types of templates that work with the View
response to make our lives easier. For now, we will stick to the basics to get a good grasp on the fundamental Laravel concepts.
View Data
Being able to show templates is awesome. It really is. What if we want to use some data from our Closure, though? In an earlier chapter, we learned how to use Route parameters. Maybe we want to be able to refer to these parameters in the View? Let's take a look at how this can be done.
<?php
// app/Http/routes.php
Route::get('/{squirrel}', function ($squirrel) {
$data['squirrel'] = $squirrel;
return View::make('simple', $data);
});
In the above route, we take the $squirrel
parameter and add it to our view data array. You see, the second parameter of the make()
method accepts an array that is passed to the view template. I normally call my array $data
to indicate that it is my view data array, but you may use any name you like!
T> Be sure to check out the compact()
PHP native function. It's useful for easily creating small view data arrays.
Before we start using this data, let's talk a little more about the view data array. When the array is passed to the view, the array keys are 'extracted' into variables that have the array key as their name and the given value. It's a little confusing to explain without an example so let me simplify it for you.
Here we have an array to be handed to View::make()
as view data.
<?php
['name' => 'Taylor Otwell', 'status' => 'Code Guru']
In the resulting view template we can access these values by key:
<?php echo $name; // gives 'Taylor Otwell' ?>
<?php echo $status; // gives 'Code Guru' ?>
So our name
array key becomes the $name
variable within the template. You can store multi-dimensional arrays as deep as you like in your view data array. Feel free to experiment!
Let's use the $squirrel
variable in the simple template we created earlier.
<!-- resources/views/simple.php -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Squirrels</title>
</head>
<body>
<p>I wish I were a <?php echo $squirrel; ?> squirrel!</p>
</body>
</html>
Now if we visit the URI /gray
we receive a page stating 'I wish I were a gray squirrel!'.
Well that was simple wasn't it? Using views, you will no longer have to return strings from your Closures!
Earlier, I mentioned that there are different types of response objects. In some circumstances, you may wish to redirect the flow of your application to another route or logic portion. In such a circumstance the Redirect
response object will be useful. See, Laravel’s got your back!
Redirects
A Redirect
is a special type of response object which redirects the flow of the application to another route. Let’s create a couple of sample routes so that I can explain in more detail.
<?php
// app/Http/routes.php
Route::get('first', function () {
return 'First route.';
});
Route::get('second', function () {
return 'Second route.';
});
Having added the above routes, you will receive ‘First route.’ upon visiting the /first
URI and ‘Second route.’ upon visiting the /second
URI.
Excellent, that’s exactly what we expected to happen. Now let’s completely shift the flow of the application by adding a redirect to the first routed closure.
<?php
// app/Http/routes.php
Route::get('first', function () {
return Redirect::to('second');
});
Route::get('second', function () {
return 'Second route.';
});
In the first route we are now returning the result of the Redirect::to()
method and passing the URI of the target location. In this case, we are passing the URI for the second route second
as the location.
T> If you'd like, you can use the redirect()
global function instead of Redirect::to()
.
If you now visit the /first
URI, you will be greeted with the text ‘Second route.’. This is because upon receiving the returned Redirect object, Laravel has shifted the flow of our application to the target destination. In this case, the flow has been shifted to the closure of the second route.
This can be useful when a condition of some kind has failed, and you need to redirect the user to a more useful location. Here’s an example using the authentication system (which we will cover later) that will provide another use case.
<?php
// app/Http/routes.php
Route::get('books', function () {
if (Auth::guest()) {
return Redirect::to('login');
}
// Show books to only logged in users.
});
In this example, if a user who has not yet logged into the system visits the /books
URI then they are considered a guest and would be redirected to the login page.
Later you will find a better way to limit access when we discuss route middleware, so don’t read too much into the above example. Instead, just consider that we could redirect the user to a more sensible destination if our conditions are not met.
Custom Responses
Both View
and Redirect
produce instances of Laravel Response
object. The response object is an instance of a class that can be handed back to Laravel as the result of a routed closure or a controller action to enable the framework to serve the right kind of response to the browser.
Response objects contain a body, a status code, HTTP headers, and other useful information. For example, the body segment of the View would be its HTML content. The status code for a Redirect would be a 301
. Laravel uses this information to construct a sensible result that can be returned to the browser.
We aren’t merely limited to using View
and Redirect
. We could also create our own response object to suit our needs. Let’s have a look at how this can be done.
<?php
// app/Http/routes.php
Route::get('custom/response', function () {
return Response::make('Hello world!', 200);
});
In the above example, we use the Response::make()
method to create a new response object. The first parameter is the content or body of the response and the second parameter is the HTTP status code that will be served with the response.
T> Once again, you can use the response()
global function instead of Response::make()
. Decide which you think looks the best!
If you haven’t seen HTTP status codes before, then think of them as status notifications for the web browser receiving your page. For example, if all goes well, a standard response may contain a 200
status code, which is web-server speak for ‘A-OK.' A 302
status code indicates that a redirect has been performed.
In fact, I bet you have already come across the now infamous 404
not found page. The 404 part is the status code received by the browser when a requested resource could not be found.
Simply put, the above response will serve the content ‘Hello world!’ with a HTTP status code of 200
to let the browser know that its request was a success.
HTTP headers are a collection of key-value pairs of data which represent useful information to the web browser that is receiving the response. Normally they are used to indicate the format of the result or how long a piece of content should be cached for. However, we can define custom headers as we please. Let’s have a look at how we can set some header values.
<?php
// app/Http/routes.php
Route::get('custom/response', function () {
$response = Response::make('Hello world!', 200);
$response->headers->set('our key', 'our value');
return $response;
});
We have created a sample response object just as we did in the previous example. However, this time, we have also set a custom header.
The collection of HTTP headers can be accessed as the headers
property of the response object.
<?php
var_dump($response->headers);
Using the set()
method on this collection we can add our own header to the collection by providing a key as a first parameter and the associated value as the second.
Once our header has been added we simply return the response object as we have done previously. The browser will receive the headers along with the response and can use this information however it wishes.
Let’s think of a more useful example. Hmm. Let’s imagine that we want our application to serve markdown responses instead of HTML. We know that a web browser would not be able to parse a markdown response, but we might have another desktop application that could.
To indicate that the content is markdown and not HTML we will modify the Content-Type
header. The Content-Type
is a common header key used by browsers to distinguish between the various formats of content that are sent to them. Don’t be confused! Let’s have an example.
<?php
// app/Http/routes.php
Route::get('markdown/response', function () {
$response = Response::make('***some bold text***', 200);
$response->headers->set('Content-Type', 'text/x-markdown');
return $response;
});
Having set the body of the response object to some sample markdown, and the Content-Type
header to the mime type for the Markdown plain text format, we have served a response that can be identified as Markdown.
Our desktop application can now make a request to the /markdown/response
URI, examine the Content-Type
header, and in receiving the text/x-markdown
value it will know to use a markdown transformer to handle the body.
Because we are all friends here, I’m going to share a secret with you. Come closer. Get in here. Let’s have a huddle. The response object doesn’t belong to Laravel.
TREACHERY? WHAT MADNESS IS THIS?
Now don’t get too worked up. You see, to avoid a lot of ‘re-inventing the wheel,' Laravel has used some of the more robust components that belong to the Symfony 2 project. The Laravel response object inherits most of its content from the Response
object belonging to the 'Symfony HTTP Foundation' component.
What this means is that if we take a look at the API for the Symfony response object, suddenly we have access to a whole heap of extra methods that aren’t covered in the Laravel docs! Holy smokes! Now that I have given away this secret, there’s nothing to stop you from becoming a Laravel master!
The API documentation for the Symfony Response object can be found here. If you look at the page, you will notice that the class has an attribute called $headers
. That’s right! That’s the collection of headers we were using only a minute ago.
Since the Laravel response object inherits from this one, feel free to use any of the methods you see in the Symfony API documentation. For example, let’s have a look at the setTtl()
method. What does the API say?
public Response setTtl(int $seconds)
Sets the response's time-to-live for shared caches.
This method adjusts the Cache-Control/s-maxage directive.
Parameters:
int $seconds Number of seconds
Return Value:
Response
Right, so this method sets the time-to-live value for shared caches. I’m no expert on this kind of thing, but a time to live suggests how long a piece of information is considered useful before it is discarded. In this instance, the TTL relates to the content caching.
Let’s give it a value for funsies. Having looked at the method signature, we see that it accepts an integer representing the time-to-live value in seconds. Let’s give this response 60 seconds to live. Like some cruel James Bond villain.
<?php
// app/Http/routes.php
Route::get('our/response', function () {
$response = Response::make('Bond, James Bond.', 200);
$response->setTtl(60);
return $response;
});
Now when our response is served, it will have a time to live value of 60 seconds. You see, by interrogating the underlying Symfony component, we have a wealth of advanced options that we can use to modify our application responses to suit our needs.
Don’t feel overwhelmed by the amount of complexity contained within the base Response object. For the most part, you will be happy using Laravel’s View and Response classes to serve simple HTTP responses. The above example simply serves as a good starting point for advanced users looking to tweak their applications for specific scenarios.
JSON Responses
Often within our application, we will have some data that we wish to serve as JSON. It could be a simple object or an array of values.
Laravel provides a Response::json()
method that will configure the response object with some details that are specific to JSON results. For example an appropriate HTTP Content-Type header.
Tip: You can optionally use the
response()->json()
function chain instead ofResponse::json()
.
We could set these up manually, but why bother when Laravel will do it for us? Let’s have a look at this method in action.
<?php
// app/Http/routes.php
Route::get('markdown/response', function () {
$data = ['iron', 'man', 'rocks'];
return Response::json($data);
});
By handing an array to the Response::json()
method it has been converted to a JSON string and set as the body of our new Response
object. Appropriate headers have been set to explain that the provided data is, in fact, a JSON string. The web browser will receive the following body:
["iron","man","rocks"]
Which is both compact and true. Enjoy using this shortcut to build clean yet functional JSON APIs!
Download Responses
Serving download streams for files directly requires certain headers to be set. Fortunately, Laravel takes care of this for you using the Response::download()
shortcut. Let’s see this in action.
<?php
// app/Http/routes.php
Route::get('file/download', function () {
$file = 'path_to_my_file.pdf';
return Response::download($file);
});
If we navigate to the /file/download
URI the browser will initiate a download instead of displaying a response. The Response::download()
method will receive a path to a file which will be served when the response is returned.
You can also provide optional second and third parameters to configure a custom file name and an array of headers. For example:
<?php
// app/Http/routes.php
Route::get('file/download', function () {
$file = 'path_to_my_file.pdf';
return Response::download($file, 'my_file.pdf', ['iron', 'man']);
});
Here we will serve our file with the name 'my_file.pdf' and a header value of iron=man
.
This chapter was a lot longer than I originally anticipated, but I’m sure you will see that returning appropriate response objects can be a lot more valuable than returning simple strings.
My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.
It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new and exciting books!