Code Bright: Controllers

← Back to Index

This title was written for Laravel version 4. If you're looking for material on the latest version of Laravel, then please check out Code Smart.

Creating Controllers

In the basic routing chapter we were taught how to link routes to closures, little pockets of logic, which make up the structure of our application. Closures are a nice and quick way of writing an application, and personally, I believe they look great within the book’s code examples. However, the preferred choice for housing application logic is the Controller.

The Controller is a class used to house routing logic. Normally, the Controller will contain a number of public methods known as actions. You can think of actions as the direct alternative to the closures we were using in the previous chapter, they are very similar in both appearance and functionality.

I don’t like explaining what something is, without first showing you an example. So let’s dive right in and look at a controller. Here’s one I made earlier! Cue Blue Peter theme. Actually that last reference might only make sense to British folk. Never mind, it’s been done now and I don’t have the heart to delete it! So, controllers..

<?php

// app/controllers/ArticleController.php

class ArticleController extends BaseController
{
    public function showIndex()
    {
        return View::make('index');
    }

    public function showSingle($articleId)
    {
        return View::make('single');
    }
}

There’s our controller! Nice and simple. This example would be suited to a blog or some other form of CMS. Ideally, a blog would have a page to view a listing of all articles, and another page to show a single article in detail. Both of these activities are related to the concept of an Article, which means it would make sense to group this logic together. This is why the logic is contained in one single ArticleController.

In honesty, you can call the Controller whatever you like. As long as your controller extends either BaseController or Controller then Laravel will know what you are trying to do. However, suffixing a controllers name with Controller, for example ArticleController is somewhat of a standard that web developers employ. If you plan to be working with others, then standards can be extremely useful.

Our controller has been created in the app/controllers directory which Laravel has created for us. This directory is being ‘classmap file loaded’ from our composer.json by default. If app/controllers doesn’t suit your workflow, then you can put the file wherever you like. However, you must make sure that the class can be autoloaded by Composer. For more information on this topic, please refer back to the Composer primer.

The class methods of our Controller are what actually contain our logic. Once again you can name them however you like, but personally I like to use the word ’show’ as a prefix if the result is that they display a web page. These methods must be public for Laravel to be able to route to them. You can add additional private methods to the class for abstraction, but they cannot be routed to. In fact, there’s a better place for that kind of code which we will learn about in the models chapter.

Let’s have a closer look at our first action, which in this example would be used to display a blog article listing.

public function showIndex()
{
    return View::make('index');
}

Hmm, doesn’t that look awfully familiar? Let’s quickly compare it to a routed closure that could be used to achieve the same effect.

Route::get('index', function()
{
    return View::make('index');
});

As you can see, the inner function is almost identical. The only difference is that the controller action has a name, and the closure is anonymous. In fact, the controller action can contain any code that the Closure can. This means that everything we have learned so far is still applicable. Shame, if it was different I could have sold another book on controllers!

There is one other difference between the two snippets however. In the basic routing chapter we were taught how to route a URI to a piece of logic contained within a Closure. In the above routed closure example the URI /index would be routed to our application logic. However, our Controller action doesn’t mention a URI at all. How does Laravel know how to direct it’s routes to our controller? Let’s take a look at Controller routing and hope we find an answer to our question.

Controller Routing

Controllers are neat and tidy, and provide a clean way of grouping common logic together. However, they are useless unless our users can actually reach that logic. Fortunately, the method of linking a URI to a Controller is similar to the routing method we used for Closures. Let’s take a closer look.

<?php

// app/routes.php

Route::get('index', 'ArticleController@showIndex');

In order to link a URI to a Controller we must define a new route within the /app/routes.php file. We are using the same Route::get() method that we used when routing Closures. However, the second parameter is completely different. This time we have a string.

The string consists of two sections that are separated by an at sign (@). Let’s have another look at the Controller that we created in the last section.

<?php

// app/controllers/ArticleController.php

class ArticleController extends BaseController
{
    public function showIndex()
    {
        return View::make('index');
    }

    public function showSingle($articleId)
    {
        return View::make('single');
    }
}

So we can see from the example that the class name is ArticleController, and the action we wish to route to is called showIndex. Let’s put them together, with an at (@) in the middle.

ArticleController@showIndex

It really is as simple as that. Now we can use any of the methods that we discovered in the basic routing chapter, and point them to controllers. For example, here’s a controller action that would respond to a POST HTTP request verb.

<?php

// app/routes.php

Route::post('article/new', 'ArticleController@newArticle');

You guys are pretty smart chaps, you bought this book right? So now you can see that the above route will respond to POST requests to the /article/new URI, and that it will be handled by the newArticle() action on the ArticleController.

Here’s a neat thing to know. You can namespace your controller and Laravel won’t bat an eyelid. Just make sure to include the namespace within your route declaration and everything will be just dandy! Let’s see this in action.

<?php

// app/controllers/Article.php

namespace Blog\Controller;

use View;
use BaseController;

class Article extends BaseController
{
    public function showIndex()
    {
        return View::make('index');
    }
}

So here we have a similar Controller to that used in the other example. This time however, it is contained within the Blog\Controller namespace. Since it’s located within the Controller section of the namespace, I have omitted the Controller suffix from the class name. This is my own personal preference, I leave it up to you to decide whether you keep it or not.

Let’s see how this namespaced controller can be routed to. You’ve probably already guessed it!

<?php

// app/routes.php

Route::post('index', 'Blog\Controller\Article@showIndex');

Just as before, only this time the name of the controller has been prefixed with its namespace. See, namespaces don’t have to complicate things! You can even store your namespaced Controller in a nested directory, or elsewhere in a PSR-0 loading scheme. Laravel doesn’t care, as long as Composer knows where to find your class, then Laravel will be able to use it.

RESTful Controllers

Laravel offers solutions, we know this much. It also provides options, RESTful Controllers are a prime example of this.

We know that we can define the HTTP request verb that we want to match using the routing methods. This is really convenient when routing to Closures. However, when routing to Controllers you might want to keep the defining of the request verb close to your application logic. Well the good news is that Laravel provides this alternative configuration.

Let’s alter our Controller a little shall we?

<?php

// app/controllers/Article.php

namespace Blog\Controller;

use View;
use BaseController;

class Article extends BaseController
{
    public function getCreate()
    {
        return View::make('create');
    }

    public function postCreate()
    {
        // Handle the creation form.
    }
}

Here we have our Article controller once more. The intention of the actions are to provide a form to create and handle the creation of a new blog article. You’ll notice that the names of the actions have been prefixed with get and post. Those are our HTTP request verbs.

So, in the above example you might think that we have represented end points for the following URLs:

GET  /create
POST /create

You might also be wondering how we route to our RESTful controller. You see, using the verb methods on the Route class wouldn’t make much sense here. Well, say goodbye to routing to individual actions. Let’s take a look at another routing method.

<?php

// app/routes.php

Route::controller('article', 'Blog\Controller\Article');

This single method will route all of the actions represented by our RESTful controller. Let’s take a closer look at the method signature.

The first parameter is the base URL. Normally RESTful routing is used to represent an object, so in most circumstances the base URL will be the name of that object. You can think of it as some what of a prefix to the actions that we have created within our RESTful controller.

The second parameter you will already be familiar with. It’s the controller that we intend to route to. Once again, Laravel will happily accept a namespaced controller as a routing target so feel free to organise your Controllers however suits your needs.

As you can see, using this method to route to your controllers provides a distinct advantage over the original routing method. With this method, you will only have to provide a single routing entry for the Controller, rather than routing to every action independently.

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 books from the comfort of my sofa!