If you wanted to, you could build a pretty substantial application and never make use of a controller. How could this be? Well, we saw in our introduction to basic routing and views that we can pass a closure to the second argument of a Route::get() request. The drawback is that pretty soon, you are going to have a routes file the size of Manhattan, and that is probably not ideal. We just want the routes file to direct traffic, not do any heavy lifting. To accomplish this goal, we will now start making use of dedicated controllers in our little games application. Let’s see how to get them set up.
The Current Routes File
Using the routes file is still good for smaller sites. In fact, the examples we have been looking at so far are a good time to be using the routes file to hold some simple logic. Here is our current routes file.
<?php
use App\Game;
Route::get('games', function () {
$games = Game::all();
return view('games.index', ['games' => $games]);
});
Route::get('games/{id}', function ($id) {
$game = Game::find($id);
return view('games.show', ['game' => $game]);
});
What are controllers?
Controllers are a way to tie together different parts of your application to work together. The controller is a little bit like a middle man, that takes requests, and decides how to fulfill those requests with a valid response. The routes file will now route incoming requests to a particular controller, that controller might make use of a Model to get data, then the data gets handed off to the view layer for presentation.
We can use Artisan to make Controller files
Just like models and migrations that we have looked at already, Artisan can also create controllers for us. Let’s see how to use Artisan for this purpose by typing php artisan help make:controller.
Once you are comfortable with creating Models and Controllers, you can even move on to creating them at the same time if you like. For now, we are just going to pick a name for our controller. So how do you name a controller? Well, we’ve been working with Games so far. We have a game model, and a games table. Let’s name our controller GamesController. We can created it by typing php artisan make:controller GamesController.
The convention is to typically choose a word that describes what the controller will be dealing with, having the first letter capitalized followed by the word “Controller” with a capital C and no spaces or underscores.
Working With The New Controller
We see the message that our controller was created successfully. Let’s have a peek at what was done for us. We can find our new controller in app/Http/Controllers.
Each route will point to a method on a controller. We have two routes, and one controller, so that means we need to create two methods on our new controller. We will have one named index
to represent all games, and one called show
to handle displaying one game at a time. Here is the controller with those items stubbed out.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class GamesController extends Controller
{
public function index()
{
}
public function show($id)
{
}
}
We now want to move the logic from the routes file to the new controller.
The full GamesController will now look like the following. Note that since we are now making use of the Eloquent Game Model we had created, we need to import that using use App\Game; You’ll see that highlighted in this code snippet as well.
app/Http/Controllers/GamesController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Game;
class GamesController extends Controller
{
public function index()
{
$games = Game::all();
return view('games.index', ['games' => $games]);
}
public function show($id)
{
$game = Game::find($id);
return view('games.show', ['game' => $game]);
}
}
Routes will now point to methods
When both a routes file and one or more controllers are used in your application, routes will typically now point to a method of a controller. Initially, we were passing a function Closure as the second argument to a route. Now that we have a controller, we will swap out the Closure for a simple string. That string follows a specific format of ‘ControllerName@methodname’.
Clean up that routes file
We can now completely clean up the routes file. We will remove the function Closure from both routes. In addition, since this routes file no longer makes use of the Eloquent Game class we had created, we can also remove the use App\Game; from the file. So we will still have two routes in place /games
and /games/{id}
but notice the simple string passed as the second argument.
<?php
Route::get('games', 'GamesController@index');
Route::get('games/{id}', 'GamesController@show');
This is now very simple, clean, and easy to understand. If a request is made to /games
, then Laravel knows to invoke the index
method on the GamesController. If a request is made to /games/{id}
, then Laravel will invoke the show
method of the GamesController. Anything to the left of the @ sign is the controller. Anything to the right of the @ sign is the method or function name in that particular controller.
Moving From Routes to Controllers in Laravel Summary
Controllers in Laravel give us a way to take any logic we might have declared as Closures in the routes file, and move that logic into dedicated Controllers with specific methods. This way you can group together similar requests in a single class. In our tutorial, we now have a dedicated GamesController. In the future, we could create other controllers that might deal with requests about Posts, or Notifications, or any other type of resource we may have in our application.