1. Laravel Routing and Controllers

The essential function of any web application framework is to take requests from a user and deliver the responses. Defining an application’s routes is the first and most important project to tackle.

Laravel routing documents

Route Definitions

In a Laravel application, we can define ‘web’ routes in routes/web.php and API routes in routes/api.php

1
2
3
Route::get('/',function () {
return 'Hello World';
})

Now, when you visit the ‘/‘ (route of your domain), you will see ‘Hello World’.

You can also define a route combined with some templates

1
2
3
Route::get('/', function() {
return view('welcome');
})

Route Verbs

In above examples, we are using Route::get which means we are telling Laravel to only match for the routes when HTTP request uses the GET action; however, normally, HTTP actions may inlclude GET, POST, PUT, DELETE and so on. We have a few other options to call on a route.

1
2
3
4
Route::post('/', function() {});
Route::put('/', function() {});
Route::delete('/', function() {});
Route::match(['get','post'],'/',function(){});

Route Handling

Passing a closure to the route definition is not the only way to tell Laravel how to resolve a route. Additionally, applications using route closures can’t take advantage of Laravel’s route caching, which can shave up to hunders of milliseconds off of each request.

The common option is to pass a controller name and method as a string in place of the closure.

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

Above code means when Laravel receives the GET request, it will pass the request to WelcomeController (App\Controller\WelcomeController) and invoke the index() method

Route Parameters

If the route you’re defining has parameters, you can pass it like this

1
Route::get('user/{id}', function($id) {});

You may ask, do I need to use the same names for both route parameter({id}) and the method parameter($id)?

Well, the answer is unless you are using route/model binding, no. Their order (left to right) defines which route parameter matches which method parameter. For example:

1
2
3
Route::get('users/{userId}/comments/{commentId}', function ( $thisIsActuallyTheUserId, $thisisReallyTheCommentId ) {
// your logic
});

You can also make your route parameter optional by including a question mark (?)

1
2
3
Route::get('user/{id?}', 
function($id = 'fallbackId'){ // provide a default value
});

Note: Routes are matched from top to bottom. Let’s say we have two routes

1
2
3
4
5
6
1.  Route::get('user/{$id}',function($id){
// function that find a user by id
});
2. Route::get('user/verified', function(){
// function that return all verified users
});

Now when you visit the ‘/user/verified’, it will return an error. This is becaue Laravel will match the first route and treat ‘verified’ as a paramater, then it will find a user by the id ‘verified’.

The solution is to move the second route to the top

1
2
3
4
5
6
Route::get('user/verified', function(){
// function that return all verified users
});
Route::get('user/verified', function(){
// function that return all verified users
});

Route Names

The simplest way to refer to routes elsewhere in your application is by their path. There’s a url() helper to prefix your route with the full domain of your site.

1
2
<a href="{{url('/')}}"> // we are using blade template here
// outputs <a href="http://yoursite.com/">

However, in Laravel we can name each route, which enables you to refer to it by using its name.

1
2
3
4
5
6
7
8
9
10
11
12
13
// Define a route with name
Route::get('user/{userId}/comment/{commentId}','UserController@show')->name('user.show');

// Refer to the route by name and pass parameters to it --> keyed array values are matched with the route parameters matching their keys,
<a href="{{route('user.show',['userId'=>1,'commentId'=>2])}}">
<a href="{{route('user.show',['commentId'=>2', userId'=>1])}}">

// Also you can pass parameters like this --> nonkeyed array values are assigned in order
<a href="{{route('user.show',[1,2])}}">

//and anything left over is added as a query parameter.
<a href="{{route('user.show',['commentId'=>2', userId'=>1,'opt' => 2])}}">
//http://yoursite.com/user/1/comment/2?opt=2

In Laravel 5.4 you can define the name like this

1
2
Route::name('user.show')->get('user/{id}',function($id) {});
Route::middleware('test')->name('user.show')->prefix('test/')->post('/user',function(){});

Route Groups

Route groups allow you to group several routes that sharing any configurations together.

Sharing same middleware

1
2
3
4
5
6
7
8
9
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});

Route::get('user/profile', function () {
// Uses Auth Middleware
});
});

Sharing same path prefixes

1
2
3
4
5
6
7
8
Route::gropu(['prefix' => 'api'],function(){
Route::get('/',function(){
// handle path /
});
Route::get('/test',function(){
// handle path api/test/
});
});

Subdomain Routing

1
2
3
4
5
6
7
8
9
10
11
12
Route::group(['domain' => 'api.yoursite.com'], function(){
Route::get('/',function(){

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

Namespace Prefixes

1
2
3
4
Route::group(['namespace'=>'API'],function() {
// App\Http\Controllers\API\UserController
Route::get('/','UserController@index');
});

Name Prefixes

1
2
3
4
5
6
7
8
Route::group(['as' => 'users.'],function(){
Route::gropu(['as' => 'comments.' ], function(){
// route name will be users.comments.show
Route::get('/',function(){

})->name('show');
})
})

Views

In Laravel, there are two formats of view you can use out of the box: plain PHP, or Blade templates. about.php will be render with the PHP engine, and about.blade.php will be rendered with Blade engine.

1
2
3
Route::get('/', function(){
return view('welcome');
})

This code will looks after a view in resources/views/home.blade.php or resources/views/home.php and parses any inline PHP or control structures and eventually return the result to user.

You can pass in variables by this

1
2
3
4
5
6
7
8
9
10
11
12
Route::get('/',function(){
return view('tasks.index')->with('task',Task::all());
})
// or
Route::get('/',function(){
return view('tasks.index',['task'=> Task::all()]);
})
//or
Route::get('/',function(){
$task = Task::all();
return view('task.index', compact('task'));
})

It will find resources/views/tasks/index.blade.php or resources/views/tasks/index.php and passes a single variable named task

Controllers

Controllers are essentially classes that organize the logic of one or more routes together in on place. Think of controllers as the traffice cops that route HTTP requests around your application.

One easy way to create a controller is with an Artisan command

1
php artisan make:controller TasksController

Now you could find the controller in app/Http/Controllers

Get User Input

1
2
3
4
5
6
7
8
9
// TasksController.php ... 
public function store() {
$task = new Task;
$task->title = Input::get('title');
$task->description = Input::get('description');
$task->save();
return redirect('tasks');
}
// 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.

Resources controller

there’s a trick for generating routes, and it’s called “resource controller binding.”

1
Route::resource('user','UserController');

And the command for create resource controller is

1
php artisan make:controller UserController --resource

Route Model Binding

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

  1. Implicit

    1
    2
    3
    Route::get('user/{user}', function(User $user){
    return $user
    });

    Becasue the parameter ({user}) is the same as the method parameter ($user), and the method parameter is typehinted with a User model (User $user), 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 {user} is an ID that should be used to look up a User and then that resulting model instance will be passed in to your closure or controller method.

    Note: By default, Eloquent will look it up by its primary key (ID), to change the column your Eloquent model uses for URL lookups, add a method to your model named getRouteKeyName():

    1
    2
    3
    public function getRouteKeyName(){
    return 'slug';
    }

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

  2. Explicit

    To manually configure route model bindings, add a link to the boot() method in App\Providers\RouteServiceProvider.

    1
    2
    3
    4
    5
    6
    7
    public function boot()
    {
    parent::boot();

    // use Illuminate\Support\Facades\Route
    Route::model('users', App\User::class);
    }

    Now whenever a route has a parameter in its definition named {users}, as demonstrated in Example 3-30, the route resolver will return an instance of the Conference class with the ID of that URL parameter.

    1
    2
    3
    4
    Route::get('user/{users}', function(User $user){ 
    // now the request parameter name could be different from //function parameter name (users vs $user)
    return $user
    });

Redirects

There are two common ways to generate a redirect: redirect global helper or Facade.

1
2
3
4
5
6
7
8
9
10
11
Route::get('redirect-with-helper', function(){
return redirect()->to('login');
});
//or
Route::get('redirect-with-facade', function(){
return Redirect::to('login');
});
//or
Route::get('redirect-with-helper-shortcut', function(){
return redirect('login');
});

redirect()->to()

the to() method looks like this:

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

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

1
2
3
Route::get('redirect',function(){
return redirect()->route('user.show');
});

The route() function looks like this:

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

So we can pass parameters to route by

1
2
3
Route::get('redirect/{user}',function(User $user){
return redirect()->route('user.show',['user' => $user]);
});

redirect()->back()

which simply redirects the user to whatever page she came from. There’s also a global shortcut for this: back().

redirect()->with()

1
2
3
4
Route::get('redirect-shortcut-with-array',function(){
$user // assume we have a user variable
return redirect('user')->with(['user' => $user]);
})