Route Definitions

In laravel, you will find your "web" routes in routes/web.php and your "API" routes in routes/api.php.

Web routes are those that will be visited by your end users; API routes are those for your API.

Basic route definition

// routes/web.php

aRoute::get('/', function () {
    return 'Hellow, World!';
});

Many simple websites could be defined entirely within the web routes file. With a few simple GET routes combined with some templates, as shown below:

Route::get('/', function () {
    return view('welcome');
});
Route::get('/about', function () {
    return view('about');
});
Route::get('/blog', function () {
    return view('blog');
});
Route::get('/contact', function () {
    return view('contact');
});

Route Verbs

GET, POST, PUT, or DELETE are a few of the other route verb option for methods to call on s route definition, as shown below:

Route::get('/', function () {
    return 'Hello, world!';
});

Route::post('/', function () {});
Route::put('/', function () {});
Route::delete('/', function () {});
Route::any('/', function () {});
Route::match('['get', 'post']', function () {});

Route Handling

Rather than using a closure, we can pass a controller name and method as a string in place of the closure, as below:

Route:get('/', 'WelcomeController@index');

This is telling laravel to pass requests to that path to the index() method of the App\Http\Controller\WelcomeController controller. This method will be passed the same parameters and treated the same way as a closure you might have alternatively put in its place.

Route Parameters

If the route you are defining has parameters -- segments in the URL structure that are variable -- it is simple to define them in your route and pass them to your closure, see below:

Route::get('users/{id}/friends', function ($id) {
    //
});

You can also make a route parameter optional by including a question mark after the oarameter name, as shown below:

Route::get('users/{id?}', function ($id = 'fallbakId') {
    //
});

And you can use regular expressions (reexes) to define that a route should only match if a parameter meets particular requirements, as below:

Route::get('users/{id}', function ($id) {
    //
)}->where('id', '[0-9]+');

Route::get('users/{username}', function ($username) {
    //
})->where('username', '[A-Za-z]+');

Route::get('posts/{id}/{slug}', function ($id, $slug) {
    //
})->where(['id' => '[0-9]', 'slug' => '[A-Za-z]+');

If you visit a path that matches a route string, but the regex does not match the parameter, it will not be matched. Since routes our matched top to bottom, users/abc would skip the first closure in [Example 3-7](), but it would be matched by the second closure, so it would get routed there. On the other hand, post/abs/123 would not match any of the closures, so it would return a 404.

Route Names

The simplest way to refer to these routes elsewhere in your application is just by their path. There is a url() helper to simplify that linking in your views. The helper will prefix your route with the full domain of your site.

<a href =" <? php echo url('/'); ?>" >

// outputs <a href ="http://myapp.com/"> 

However, Laravel also allows you to name each route, which enables you to refer to it without explicitly referencing the URL. This is helpful because it means you can give simple nicknames to complex routes, and also because linking them by name means you don’t have to rewrite your frontend links if the paths change.

// Defining a route with name in routes/ web.php: 
Route::get('members/{id}', 'MembersController@ show')->name('members.show'); 

// Link the route in a view using the route() helper 
<a href="<?php echo route('members.show', ['id' => 14]); ?>"> 

This illustrates a few new concepts. First, we’re using fluent route definition to add the name, by chaining the name() method after the get() method.

This method allows us to name the route, giving it a short alias to make it easier to reference elsewhere.

In our example, we’ve named this route members.show; resourcePlural.action is a common convention within Laravel for route and view names.

##### Route Naming Conventions 

You can name your route anything you’d like, but the common convention is to use the plural of the resource name, then a period, then the action. So, here are the routes most common for a resource named `photo`: 

photos.index 
photos.create 
photos.store 
photos.show 
photos.edit 
photos.update 
photos.destroy 

To learn more about these conventions, see Resource Controllers. 

We also introduced the route() helper. Just like url(), it’s intended to be used in views to simplify linking to a named route. If the route has no parameters, you can simply pass the route name: route(' members.index') and receive a route string http:// myapp.com/members/index. If it has parameters, pass them in as an array as the second parameter like we did in this example.

In general, I recommend using route names instead of paths to refer to your routes, and therefore using the route() helper instead of the url() helper. Sometimes it can get a bit clumsy — for example, if you are working with multiple subdomains — but it provides an incredible level of flexibility to later change the application’s routing structure without major penalty.

Passing Route Parameters to the route() Helper

When your route has parameters (e.g., users/{id}), you need to define those parameters when you are using the route() helper to generate a link to the route. There are a few different ways to pass these parameters. Let’s imagine a route defined as users/{userId}/comments/{commentId}. If the user ID is 1 and the comment ID is 2, let's look at the options avaible to us:

Option 1:

route('users.comments.show', [1, 2])
// http://myapp.com/users/1/comments/2

Option 2:

route('users.comments.show', ['userId' => 1, 'commentId' => 2])
// http://myapp.com/users/1/comments/2

Option 3:

route('users.comments.show', ['commentId' => 2, 'userId' => 1])
// http://myapp.com/users/1/comments/2

Option 4:

route('users.comments.show', ['userId' => 1, 'commentId' => 2, 'opt' => 'a'])
// http://myapp.com/users/1/comments/2?opt=a

As you can see, nonkeyed array values are assigned in order; keyed array values are matched with the route parameters matching their keys, and anything left over is added as a query parameter.

Route Groups

Often a group of routes share a particular characteristic — a certain authentication requirement, a path prefix, or perhaps a controller namespace. Defining these shared characteristics again and again on each route not only seems tedious but also can muddy up the shape of your routes file and obscure some of the structures of your application.

Route groups allow you to group several routes together, and apply any shared configuration settings once to the entire group, to reduce this duplication. Also, route groups are visual cues to future developers that these routes are grouped together.

To group two or more routes together, you "surround" the route definitions with a route group, as shown below. In reality, you are actually passing a closure to the group definition, and defining the grouped routes within that closure.

Route::group([], function () {
    Route::get('hello', function () {
        return 'Hello';
    });
    Route::get('world', function () {
        return 'World';
    }); 
});

By default, a route group doesn’t actually do anything. There is no difference between the group in [Example 3-10]() and separating a segment of your routes with code comments. The empty array that is the first parameter, however, allows you to pass a variety of configuration settings that will apply to the entire route group.

Middleware

Probably the most common use for route groups is to apply middleware to a group of routes. To learn more about middleware see [Chapter 10](), but, among other things, they’re what Laravel uses for authenticating users and restricting guest users from using certain parts of a site.

In [Example 3-11](), we’re creating a route group around the dashboard and account views and applying the auth middleware to both. In this example, it means users have to be logged in to the application to view the dashboard or the account page.

Applying middleware in controllers

Often it is clearer and more direct to attach middleware to your routes in the controller instead of at the route definition. You can do this by calling the middleware() method in the constructor of your controller. The string you pass to the middleware() method is the name of the middleware, and you can optionally chain modifier methods (only() and except()) to define which methods will receive that middleware:

class DashboardController extends Controller 
{ 
    public function __construct() 
    { 
        $this->middleware('auth');
        $this->middleware('admin-auth')->only(' admin'); 
        $this->middleware('team-member')->except(' admin'); 
    } 
} 

Note that, if you are doing a lot of "only" and "except" customizations, that’s often a sign that you should create a new controller for the execepttional routes.

Path Prefixes

If you have a group of routes that share a segment of their path — for example, if your site’s API is prefixed with /api — you can use route groups to simplify this structure (see [Example 3-12]()).

Example 3-12. Prefixing a group of routes

Route::group(['prefix' => 'api'], function () { 
    Route::get('/', function () { 
        // Handles the path /api 
    }); 
    Route::get('users', function () { 
        // Handles the path /api/users 
    }); 
}); 

Note that each prefixed group also has a / route that represents the root of the prefix — in [Example 3-12]() that is /api.

Subdomain Routing

Subdomain routing is the same as route prefixing, but it is scoped by subdomain instead of route prefix. There are two primary uses for this. First, you may want to present different sections of the application (or entirely different applications) to different subdomains. [Example 3-13]() shows how you can achieve this.

Example 3-13. Subdomain routing

Route:: group([' domain' = > 'api.myapp.com'], function () { Route:: get('/', function () { // }); });

Second, you might want to set part of the subdomain as a parameter, as illustrated in [Example 3-14](). This is most often done in cases of multitenancy.

Example 3-14. Parameterized subdomain routing

Route:: group([' domain' = > '{ account}. myapp.com'], function () { 
    Route:: get('/', function ($ account) { 
        // 
    }); 
    Route:: get(' users/{id}', function ($ account, $ id) { 
        // 
    }); 
}); 

Note that any parameters for the group get passed into the grouped routes’ methods as the first parameter(s).

Namespace Prefixes

When you are grouping routes by subdomain or route prefix, it’s likely their controllers have a similar PHP namespace. In the API example, all of the API routes’ controllers might be under an API namespace. By using the route group namespace prefix, as shown in [Example 3-15](), you can avoid long controller references in groups like "API/ControllerA@index" and "API/ControllerB@index".

Example 3-15. Route group namespace prefixes

// App\Http\Controllers\ControllerA 

Route:: get('/', 'ControllerA@ index'); 

Route:: group(['namespace' = > 'API'], function () { 
    // App\Http\Controllers\API\ControllerB 
    Route::get('api/', 'ControllerB@index'); 
}); 

Name Prefixes

The prefixes don’t stop there. It’s common that route names will reflect the inheritance chain of path elements, so users/comments/5 will be served by a route named users.comments.show. In this case, it’s common to use a route group around all of the routes that are beneath the users.comments resource.

Just like we can prefix URL segments and controller namespaces, we can also prefix strings to the route name. With route group name prefixes, we can define that every route within this group should have a given string prefixed to its name. In this context, we’re prefixing "users." to each route name, then "comments." (see [Example 3-15]()).

Route::group(['as' => 'users.', 'prefix' => 'users'], function () {
    Route::group(['as' => 'comments.', 'prefix;' => 'comments'], function () {
        // Route name will be users.comments.show
        Route::get('{id}', function () {
            //
        })->name('show');
    });
});

Views

In a few of the route closures we’ve looked at so far, we’ve seen something along the lines of return view('account'). What’s going on here?

If you are not familiar with the Model–View–Controller (MVC) pattern, views (or templates) are files that describe what some particular output should look like. You might have views for JSON or XML or emails, but the most common views in a web framework output HTML.

In Laravel, there are two formats of view you can use out of the box: plain PHP, or Blade templates (see [Chapter 4]()). The difference is in the filename: about.php will be rendered with the PHP engine, and about.blade.php will be rendered with the Blade engine.

Three ways to load a view()

There are three different ways to return a view. For now, just concern yourself with view(), but if you ever see View:: make(), it’s the same thing, and you could also inject the Illuminate\View\ViewFactory if you prefer.

Once you have loaded a view, you have the option to simply return it (as in [Example 3-17]()), which will work fine if the view doesn’t rely on any variables from the controller.

Example 3-17. Simple view() usage

Route:: get('/', function () { 
    return view(' home'); 
}); 

This code looks for a view in resources/views/home.blade.php or resources/views/home.php, and loads its contents and parses any inline PHP or control structures until you have just the view’s output. Once you return it, it’s passed on to the rest of the response stack and eventually returned to the user.

But what if you need to pass in variables?

Route::get('tasks', function () {
    return view('tasks.index')->with('tasks', Task::all());
});

This closure loads the resources/views/taks/index.blade.php view and passes it a single variable named tasks, which contains the result of the Task::all() method.

Task::all() is an Eloquent databse query. More in [Chapter 8]().

Using View Composer to Share Variables with Every View

Sometimes it can become a hassle to pass the same variables over and over. There may be a variable that you want accessible to every view in the site, or to a certain class of views or a certain included subview — for example, all views related to tasks, or the header partial.

It’s possible to share certain variables with every template or just certain templates, like in the following code:

view()->share('variableName', 'variableValue');

To learn more, check out [View Composers and Service Injection]().

Controllers

I have mentioned controllers a few times, but until now most of the examples have shown route closures. If you are not familiar with the MVC pattern (Figure 3-1), controllers are essentially classes that organize the logic of one or more routes together in one place.

Controllers tend to group similar routes together, especially if your application is structured along a traditionally CRUD-like format; in this case, a controller might handle all the actions that can be performed on a particular resource.

MVC


What is CRUD

CRUD stands for create, read, update, delete, which are the gfour primary operations that web apps most commonly provide on a resource.

It may be tempting to cram all of the application’s logic into the controllers, but it’s better to think of controllers as the traffic cops that route HTTP requests around your application. Since there are other ways requests can come into your application — cron jobs, Artisan command-line calls, queue jobs, etc. — it’s wise to not rely on controllers for much behavior.

This means a controller’s primary job is to capture the intent of an HTTP request and pass it on to the rest of the application.


So, let’s create a controller. One easy way to do this is with an Artisan command, so from the command line run the following:

php artisan make:controller TasksController

This creates a new file named TasksController in app/Http/Controllers, with the contonet below:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Request;

class TasksController extends Controller
{
}

Modify this file as below, creating a new public method called home(). We will just return some text:

<?php

use App\Http\Controllers\Controller;

class TasksController extends Controller
{
 public function home()
 {
    return 'Hello, World!';
 }
}

Then, we will hook up a route to it, as shown below:

Route::get('/', 'TasksController@home');

Visit the / route, and you will see the words, "Hello, World!"


Controller namespacing

In [Example 3-21]() we referenced a controller with the fully qualified class name of App\Http\Controllers\TasksController, but we only used the class name. This isn’t because we can simply reference controllers by their class name. Rather, we can ignore the App\Http\Controllers\ when we reference controllers; by default, Laravel is configured to look for controllers within that namespace. This means that if you have a controller with the fully qualified class name of App\Http\Controllers\API\ExercisesController, you’d reference it in a route definition as API\ExercisesController.


The most common use of a controller method, then, will be something like this:

// TasksController.php

...
public function index()
{
    return view('tasks.index')->with('tasks', Tasks::all());
}

The above controller method loads the resources/views/tasks/index.blade.php view and passes it a single variable named tasks, which contains the results of the Task::all() Eloquent Method.

Getting User Input

The second most common action to perform in a controller method is to take input from the user and act on it. That introduces a few new concepts, so let’s take a look at a bit of sample code and walk through the new pieces.

First, let’s bind it quickly:

Example 3-23. Binding basic form actions

// routes/web.php 

Route::get('tasks/create', 'TasksController@create'); 
Route::post('tasks', 'TasksController@store'); 

Notice that we’re binding the GET action of tasks/ create (which shows the form) and the POST action of tasks/ (which is where we POST when we’re creating a new task). We can assume the create() method in our controller just shows a form, so let’s look at the store() method below.

Example 3-24. Common form input controller method

// TasksController.php 
... 
public function store() 
{ 
    $task = new Task; 
    $task->title = Input::get('title'); 
    $task->description = Input::get(' description'); 
    $task->save(); 

    return redirect(' tasks'); 
} 

This example makes use of Eloquent models and the redirect() functionality, but what we are doing here, we:

  • create a new Task,
  • pull data out of the user input and set it on the task,
  • save it,
  • and then redirect back to the page that shows all tasks.

There are two main ways to get user input from a POST: the Input facade, which we used here, and the Request object, which we’ll talk about next.


IMPORTING FACADES

If you follow any of these examples, whether in controllers or any other PHP class that is namespaced, you might find errors showing that the facade cannot be found. This is because they’re not present in every namespace, but rather they’re made available in the root namespace.

So, in [Example 3-24](), we’d need to import the Input facade at the top of the file. There are two ways to do that: either we can import \Input, or we can import Illuminate\Support\Facades\Input. For example:

<?php 

namespace App\Http\Controllers; 

use Illuminate\Support\facades\Input; 

class TasksController 
{ 
    public function store() 
    { 
        $task = new Task; 
        $task->title = Input::get('title'); 
        $task->description = Input::get('description');
        $task->save();

        retun redirect('tasks');
    }

As you can see, we can get the value of any user-provided information, whether from a query parameter or a POST value, using Input::get('fieldName'). So our user filled out two fields on the "add task" page: "title" and "description." We retrieve both using the Input facade, save them to the database, and then return.

Injecting Dependencies into Controllers

Laravel’s facades present a simple interface to the most useful classes in Laravel’s codebase. You can get information about the current request and user input, the session, caches, and much more.

But if you prefer to inject your dependencies, or if you want to use a service that doesn’t have a facade, you’ll need to find some way to bring instances of these classes into your controller. This is our first exposure to Laravel’s service container. For now, if this is unfamiliar, you can think about it as a little bit of Laravel magic; or, if you want to know more about how it’s actually functioning, you can skip ahead to Chapter 11.

All controller methods (including the constructors) are resolved out of Laravel’s container, which means anything you typehint that the container knows how to resolve will be automatically injected.

As a nice example, what if you’d prefer having an instance of the Request object instead of using the facade? Just typehint Illuminate\Http\Request in your method parameters, like below:

Controller method injection via typehinting

// TasksController.php

public function store(\Illuminate\Http\Request $request)
{
    $task = new Task;
    $task->title = $request->input('title');
    $task->description = $request->input('description');
    $task-save;

    retun redirect('tasks');
}

So, you have defined a parameter that must be passed into the store() method. And since you have typehinted it, and since laravel knows how to reslove that class name, you are going to have the Request object ready for you to use in your method with no work on your part. No expicit bionding, nothing else -- it is just there as the $request variable.

This is how many other developers prefer to get the user input: inject the instance of the request and read the user input form there, instead of relying on the Input facade.

Resource Controllers

Sometimes naming the methods in your controllers can be the hardest part of writing a controller. Thankfully, Laravel has some conventions for all of the routes of a traditional REST/ CRUD controller (called a “resource controller” in Laravel); additionally, it comes with a generator out of the box and a convenience route definition that allows you to bind an entire resource controller at once.

To see the methods that Laravel expects for a resource controller, let’s generate a new controller from the command line:

php artisan make:controller MySampleResourceController --resource

Now open app/Http/Controllers/MySampleResourceController.php. You will see it comes prefilled with quite a few methods. Let’s walk over what each represents. We’ll use a Task as an example.

The methods of Laravel’s resource controllers

For each, you can see the HTTP verb, the URL, the controller method name, and the "name." The [Table 3-1]() shows the HTTP verb, the URL, the controller method name, and the “name” for each of these default methods.

Resource Controller

Binding a resource controller

We have seen that these are the conventional route names to use in Laravel, and also that it’s easy to generate a resource controller with methods for each of these default routes. Thankfully, you don’t have to generate routes for each of these controller methods by hand, if you don’t want to. Instead, there’s a trick for that, and it’s called "resource controller binding."

Example 3-26. Resource controller binding

// routes/web.php 

Route::resource(' tasks', 'TasksController'); 

This will automatically bind all of the routes for this resource to the appropriate method names on the specified controller.

It will also name these routes appropriately; for example, the index() method on the tasks resource controller will be named tasks.index.

Route Model Binding

One of the most common routing patterns is that the first line of any controller method tries to find the resource with the given ID, like in [Example 3-27]().

Example 3-27. Getting a resource for each route

Route::get('conferences/{id}', function ($id) {
    $conference = Conference::findOrFail($id); 
});

Laravel provides a feature that simplifies this pattern called "route model binding."

This allows you to define that a particular parameter name (e.g., {conference}) will indicate to the route resolver that it should look up an Eloquent record with that ID and then pass it in as the parameter instead of just passing the ID.

There are two kinds of route model binding: implicit and explicit.

Implicit Route Model Binding

To use route model binding is to name your route parameter something unique to that model (e.g., name it $conference instead of $id), then typehint that parameter in the closure/controller method and use the same variable name there.

Route::get('conferences/{conference}', function (Conference $ conference){
    return view('conferences.show')->with('conference', $conference); 
}); 

Because the route parameter ({conference}) is the same as the method parameter ($conference), and the method parameter is typehinted with a Conference model (Conference $conference), Laravel sees this as a route model binding.

Every time this route is visited, the application will assume that whatever is passed into the URL in place of {conference} is an ID that should be used to look up a Conference, and then that resulting model instance will be passed in to your closure or controller method.


Customizing the route key for an eloquent model

Any time an eloquent model is looked up via a URL segment, the default column Eloquent will look it up by is its primary key (ID). To change the column your Eloquent model uses for URL lookups, add a method to your model named getRouteKeyByName():

public function getRouteKeyName()
{
    return 'slug';
}

Now, a URL like conference/{conference} will expect to get the slug instead of the ID, and will perform its lookups accordingly.


Custom Route Model Binding

To manually configure route model bindings, add a line like the one below to the boot() method in App\Providers\RouteServiceProvider

public function boot(Router $router)
{
    // just allows the parent's boot() method to still run
    parent::boot($router);

    // Preforms binding
    $router->model('event', Conference::class);
}

You have now defined that whenever a route has a parameter in its definition named {event}, as demonstrated in [Example 3-30](), the route resolver will return an instance of the Conference class with the ID of that URL parameter.

Example 3-30. Using an explicit route model binding

Route::get('events/{event}', function (Conference $ event) { 
    return view('events.show')->with('event', $event);
});

Route Cashing

If you are looking to squeeze every millisecond out of your load time, you may want to take a look at route caching. One of the pieces of Laravel’s bootstrap that can take anywhere from a few dozen to a few hundred milliseconds is parsing the routes/* files, and route caching speeds up this process dramatically.

To cache your routes file, you need to be using all controller and resource routes (no route closures). If your app isn’t using any route closures, you can run php artisan route:cache, Laravel will serialize the results of your routes/* files. If you want to delete the cache, run php artisan route:clear.

Here is the drawback: Laravel will now match routes against that cached file instead of your actual routes/* files. You can make endless changes to those files, and they won’t take effect until you run route:cache again. This means you’ll have to recache every time you make a change, which introduces a lot of potential for confusion.

Here’s what I would recommend instead: since Git ignores the route cache file by default anyway, consider only using route caching on your production server, and run the php artisan route:cache command every time you deploy new code (whether via a Git post-deploy hook, a Forge deploy command, or as a part of whatever other deploy system you use). This way you won’t have confusing local development issues, but your remote environment will still benefit from route caching.

Form Method Spoofing

Sometimes, you need to manually define which HTTP verb a form should send as. HTML forms only allow for GET or POST, so if you want any other sort of verb, you’ll need to specify that yourself.

An Introduction to HTTP Verbs

We’ve talked about the GET and POST HTTP verbs already. If you are not familiar with HTTP verbs, the other two most common ones are PUT and DELETE, but there’s also HEAD, OPTIONS, PATCH, and two others that are pretty much never used in normal web development, TRACE and CONNECT.

Here’s the quick rundown: GET requests a resource and HEAD asks for a headers-only version of the GET, POST creates a resource, PUT overwrites a resource and PATCH modifies a resource, DELETE deletes a resource, and OPTIONS asks the server which verbs are allowed at this URL.

HTTP Verbs in Laravel

As we have already shown, you can define which verbs a route will match in the route definition using Route::get (), Route::post (), Route::any (), or Route::match(). You can also match with Route::patch(), Route::put (), Route::delete ().

But how does one send a request other than GET with a web browser? First, the method attribute in an HTML form determines its HTTP verb: if your form has a method of "GET", it will submit via query parameters and a GET method; if the form has a method of "POST", it will submit via the post body and a POST method.

JavaScript frameworks make it easy to send other requests, like DELETE and PATCH. But if you find yourself needing to submit HTML forms in Laravel with verbs other than GET or POST, you’ll need to use form method spoofing, which is spoofing the HTTP method in an HTML form.

HTTP Method Spoofing in HTML Forms

To inform Laravel that the form you are currently submitting should be treated as something other than POST, add a hidden variable named _method with the value of either "PUT", "PATCH", or "DELETE", and Laravel will match and route that form submission as if it were actually a request with that verb. The form in [Example 3-31](), since it’s passing Laravel the method of "DELETE", will match routes defined with Route::delete() but not those with Route::post().

<form action="/tasks/5" method="POST">
    <input type="hidden" name="_method" value="DELETE">
</form>

CSRF Protection

If you have tried to create and submit a form in a Laravel application already — including the form in [Example 3-31]() — you have likely run into the dreaded TokenMismatchException.

By default, all routes in Laravel except "read-only" routes (those using GET, HEAD, or OPTIONS) are protected against cross-site request forgery (CSRF) attacks by requiring a token, in the form of an input named _token, to be passed along with each request. This token is generated at the start of every session, and every non–read-only route compares the submitted _token against the session token.


WHAR IS CSRF?

A cross-site request forgery is when one website pretends to be another. The goal is for someone to hijack your users’ access to your website, by submitting forms from their website to your website via the logged-in user’s browser.

The best way around CSRF attacks is to protect all inbound routes — POST, DELETE, etc. — with a token, which Laravel does out of the box.


You have two options for getting around this. The first, and preferred, method is to add the _token input to each of your submissions. In HTML forms, that’s simple; look at [Example 3-32]().

Example 3-32. CSRF tokens

<form action ="/tasks/5" method="POST"> <?php echo csrf_field(); ?> <!-- or: --> < input type =" hidden" name ="_token" value =" <? php echo csrf_token(); ?>" > </ form >

In JavaScript applications, it’s a bit more work, but not much. The most common solution for sites using JavaScript frameworks is to store the token on every page in a < meta > tag like this one:

<meta name =" csrf-token" content =" <? php echo csrf_token(); ?>" id =" token" >

Storing the token in a <meta> tag makes it easy to bind it to the correct HTTP header, which you can do once globally for all requests from your JavaScript framework, like in [Example 3-33]().

Example 3-33. Globally binding a header for CSRF

// in jQuery: 

$.ajaxSetup({ 
    headers: { 
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    } 

}); 

// in Vue:

Vue.http.interceptors.push((request, next) => { 
    request.headers[' X-CSRF-TOKEN'] = 
        document.querySelector('#token').getAttribute('content'); 

    next(); 
});

Laravel will check the X-CSRF-TOKEN on every request, and valid tokens passed there will mark the CSRF protection as satisfied.

Note that the Vue syntax for CSRF in this example is not necessary if you’re working with the 5.3 Vue bootstrap; it already does this work for you.

Redirects

So far the only things we’ve returned from a controller method or route definition have been views. But there are a few other structures we can return to give the browser instructions on how to behave.

First, let’s cover the redirect. There are two common ways to generate a redirect; we’ll use the redirect global helper here, but you may prefer the facade. Both create an instance of Illuminate\Http\RedirectResponse, perform some convenience methods on it, and then return it. You can also do this manually, but you’ll have to do a little more work yourself. Take a look at [Example 3-34]() to see a few ways you can return a redirect.

Example 3-34. Different ways to return a redirect

// Using the global helper to generate a redirect response 
Route:: get('redirect-with-helper', function () { 
    return redirect()->to('login');
}); 

// Using the global helper shortcut 
Route::get('redirect-with-helper-shortcut', function () { 
    return redirect('login');
});

// Using the facade to generate a redirect response 
Route::get('redirect-with-facade', function () {
    return Redirect:: to('login'); 
}); 

Note that the redirect() helper exposes the same methods as the Redirect facade, but it also has a shortcut; if you pass parameters directly to the helper, instead of chaining methods after it, it’s a shortcut to the to() redirect method.

redirect()->to()

The method signature for the to() method for redirects looks like this:

function to( $to = null, $status = 302, $ headers = [], $ secure = null) 

$to is a valid internal path; $status is the HTTP status (defaulting to 302 FOUND); $headers allows you to define which HTTP headers to send along with your redirect; and $secure allows you to override the default choice of http versus https (which is normally set based on your current request URL). [Example 3-35]() shows another example of its use.

Example 3-35. redirect()->to()

Route:: get('redirect', function () { 
    return redirect()-> to('home'); 

    // or same, using the shortcut: 
    return redirect('home'); 
}); 

redirect()->route()

The route() method is the same as the to() method, but rather than pointing to a particular path, it points to a particular route name (see [Example 3-36]()).

Example 3-36. redirect()->route()

Route:: get('redirect', function () { 
    return redirect()-> route(' conferences.index'); 
}); 

Note that, since some route names require parameters, its parameter order is a little different. route() has an optional second parameter for the route parameters:

function route( $to = null, $parameters = [], $status = 302, $headers = []) 

So, using it might look a little like [Example 3-37]().

Example 3-37. redirect()-> route() with parameters

Route::get('redirect', function () { 
    return redirect()-> route('conferences.show', [' conference' = > 99]); 
}); 

redirect()->back()

Because of some of the built-in conveniences of Laravel’s session implementation, your application will always have knowledge of what the user’s previously visited page was. That opens up the opportunity for a redirect()->() redirect, which simply redirects the user to whatever page she came from. There’s also a global shortcut for this: back().

Other Redirect Methods

The redirect service provides other methods that are less commonly used, but still available:

  • home() redirects to a route named home.
  • refresh() redirects to the same page the user is currently on.
  • away() allows for redirecting to an external URL without the default URL validation.
  • secure() is like to() with the secure parameter set to "true".
  • action() allows you to link to a controller and method like this: redirect()-> action('MyController@ myMethod').
  • guest() is used internally by the auth system; when a user visits a route he’s not authenticated for, this captures the “intended” route and then redirects the user (usually to a login page).
  • intended() is also used internally by the auth system; after a successful authentication, this grabs the “intended” URL stored by the guest() method and redirects the user there.

redirect()->with()

When you’re redirecting users to different pages, you often want to pass certain data along with them. You could manually flash the data to the session, but Laravel has some convenience methods to help you with that.

Most commonly, you can pass along either an array of keys and values or a single key and value using with(), like in [Example 3-38]().

Route::get(' edirect-with-key-value', function () { 
    return redirect('dashboard')->with('error', true); 
}); 

Route::get('redirect-with-array', function () { 
    return redirect('dashboard')->with(['error' => true, 'message' => 'Whoops!']); 
});

CHAINING METHODS ON REDIRECTS

As with many other facades, most calls to the Redirect facade can accept fluent method chains, like the with() calls in [Example 3-38]().


You can also use withInput(), as in [Example 3-39](), to redirect with the user’s form input flashed; this is most common in the case of a validation error, where you want to send the user back to the form she just came from.

Example 3-39. Redirect with form input

Route:: get('form', function () { 
    return view('form'); 
}); 

Route:: post('form', function () { 
    return redirect('form')
        ->withInput()
        ->with(['error' => true, 'message' => 'Whoops!']); 
});

The easiest way to get the flashed input that was passed with withInput() is using the old() helper, which can be used to get all old input (old()) or just the value for a particular key (old('username'), with the second parameter as the default if there is no old value). You’ll commonly see this in views, which allows this HTML to be used both on the "create" and the "edit" view for this form:

<input name =" username" value =" <? = 
    old(' username', 'Default username instructions here'); 
?>" > 

Speaking of validation, there is also a useful method for passing errors along with a redirect response: withErrors(). You can pass it any "provider" of errors, which may be an error string, an array of errors, or, most commonly, an instance of the Illuminate Validator.

[Example 3-40]() shows an example of its use.

Example 3-40. Redirect with errors

Route::post('form', function () { 
    $validator = Validator:: make( $request-> all()), $ this-> validationRules); 

    if ($validator->fails()) { 
        return redirect(' form')->withErrors( $validator) -> withInput(); 
    } 
});

withErrors() automatically shares an $errors variable with the views of the page it’s redirecting to, for you to handle however you’d like.


The validate() shortcut in controller methods

Like how [Example 3-40]() looks? If you’re defining your routes in a controller, there’s a simple and powerful tool that cleans up that code.


Aborting the Request

Aside from returning views and redirects, the most common way to exit a route is to abort. There are a few globally available methods (abort(), abort_if(), and abort_unless()), which optionally take HTTP status codes, a message, and a headers array as parameters.

As [Example 3-41]() shows, abort_if() and abort_unless() take a first parameter that is evaluated for its truthiness, and perform the abort depending on the result.

Example 3-41. 403 Forbidden aborts

Route:: post(' something-you-cant-do', function (Illuminate\ Http\ Request) { abort( 403, 'You cannot do that!'); abort_unless( $ request-> has(' magicToken'), 403); abort_if( $ request-> user()-> isBanned, 403); }); 

Custom Responses

There are a few other options available for us to return, so let’s go over the most common responses after views, redirects, and aborts. Just like with redirects, you can either use the response() helper or the Response facade to run these methods on.

response()->make()

If you want to create an HTTP response manually, just pass your data into the first parameter of response()->make(): e.g., return response()->make('Hello, World!'). Once again, the second parameter is the HTTP status code and the third is your headers.

response()->json() and ->jsonp()

To create a JSON-encoded HTTP response manually, pass your JSON-able content (arrays, collections, or whatever else) to the json() method: e.g., return response()->json(User::all());. It’s just like make(), except it json_encodes your content and sets the appropriate headers.

response()->download() and ->file()

To send a file for the end user to download, pass either an SplFileInfo instance or a string filename to download(), with an optional second parameter of the filename: e.g., return response()->download('file501751.pdf', 'myFile.pdf').

To display the same file in the browser (if it’s a PDF or an image or something else the browser can handle), use response()->file() instead, which takes the same parameters.

Testing

In some other communities, the idea of unit testing controller methods is common, but within Laravel (and most of the PHP community), it’s most common to rely on application testing to test the functionality of routes.

For example, to verify that a POST route works correctly, we can write a test like [Example 3-42]().

Example 3-42. Writing a simple POST route test

// AssignmentTest.php 
public function test_post_creates_new_assignment() 
{ 
    $this->post('/assignments', [ 
        'title' => 'My great assignment' 
    ]);

    $this-> seeInDatabase('assignments', [ 
        'title' = > 'My great assignment' 
    ]);
}

Did we directly call the controller methods? No. But we ensured that the goal of this route — to receive a POST and save its important information to the database — was met. You can also use similar syntax to visit a route and verify that certain text shows up on the page, or that clicking certain buttons does certain things (see [Example 3-4]()).

Example 3-43. Writing a simple GET route test

// AssignmentTest.php 

public function test_list_page_shows_all_assignments() 
{ 
    $assignment = Assignment::create([ 
        'title' = > 'My great assignment' 
    ]); 

    $this-> visit('assignments')
        ->see(['My great assignment']); 
}    

Conclusion

Laravel’s routes are defined in routes/web.php and routes/api.php, where you can define the expected path for each route, which segments are static and which are parameters, which HTTP verbs can access the route, and how to resolve it. You can also attach middleware to routes, group them, and give them names.

What is returned from the route closure or controller method dictates how Laravel responds to the user. If it’s a string or a view, it’s presented to the user; if it’s other sorts of data, it’s converted to JSON and presented to the user; and if it’s a redirect, it forces a redirect.

Laravel provides a series of tools and conveniences to simplify common routing-related tasks and structures. These include resource controllers, route model binding, and form method spoofing.