Using Laravel: How To Use Routes, Controllers and Filters For Public and Private sections of a CMS site

By | January 5, 2013

If you are reading this you probably already know what Laravel is, but just in case: it’s a PHP framework for building applications. It has all the typical stuff such as MVC, DAO, ORM, a templating engine (also supports Twig from Symfony), routes, controllers, clean URLs, RESTful support etc. I really like it because it’s very clean and compact to code in. It’s also much simpler to get started with than something like Zend Frameworks 2, for example, as it doesn’t require a complex install process or configuration. In fact it pretty much just runs out of the box.

Other Tutorials on Laravel

There are a few (very few) tutorials on Laravel. If you prefer learning by watching videos I can highly recommend this series by Andrew Perkins. One text-based tutorial I’ve been working through is Dayle Rees’s. One weakness of his articles is that he starts out showing you how bits hang together, but by the time you get to filters he loses the plot and stops giving you a step-by-step working example- he teaches you concepts but doesn’t show them all working together. This is the case with his discussion about securing an admin section of your site, for example. Another tutorial, written by Nikko Bautista, covers some of the same ideas. That one also leaves some gaps. So here’s my attempt to provide a full working example, along with an explanation of how all the bits and pieces relate to one another.

The Problem

You want to build a CMS. You have public pages, and admin pages. The public pages don’t require any authorization to access them – the user just goes to www.myexamplecms.com/page/home, for example. To access the admin pages you require the user first login. The admin pages all reside at URLs like www.myexamplecms.com/admin/someadminfunction- admin/profile, admin/users, admin/groups etc. I’m guessing this is a fairly typical design.

The Solution – Cookbook

Here’s a cookbook approach to doing this: (I assume you’ve already installed Laravel and become familiar with its directory structure).

  1. Open application/routes.php
  2. Add this code:
    Route::get('page/(:any)', 'page@index');     
    Route::get('admin/(:any?)', 'admin@index'); 
    
    // Present the login page: (give the route a name).   
    Route::get('login', array('as' => 'loginpage', 'do' => function() 
    { 
    	 return View::make('login.index'); 
    }));
    

    Immediately above this code: (which is in the shipped version of routes.php, approx line 35):

    Route::get('/', function()
    {
    	return View::make('home.index');
    });
    
  3. Further below in routes.php, ( immediately before the first Route:filter(…) statement) add this code:

    // Filter all requests to admin pages: 
    Route::filter('pattern: admin/*', array('name' => 'adminauth', function()
    {
     
        	if (Auth::guest()) return Redirect::to_route('loginpage');
    }));
    
  4. Next, we create the controller for the admin pages – create a new file called admin.php in directory application/controllers and put in this code:
    class Admin_Controller extends Base_Controller
    {
    	
        public $restful = true;
    
    	public function __construct()
    	{
    	    $this->filter('before', 'adminauth');
    	}
       
        public function get_index($thingtodo = '')
        {
            echo 'this is the admin part of the site';  
            
            if ($thingtodo != '') echo "<br/>Let's work with: " . $thingtodo; 
        }
    
    }
    
  5. And just to complete the example, let’s create the controller for the page route. Create a file called page.php in application/controllers and add this code:
     
    class Page_Controller extends Base_Controller
    {
        public function action_index($page = 'home')
        {
            echo "This is where all the main code for handling a public page would go.";
            echo "<br/>Page name is: " . $page; 
        }
       
    }
    
  6. Now we need our login page. This example simply sends a View to the user agent, but in reality you probably want a controller here too. Create a subdirectory called login in application/views. Then create a file called index.blade.php inside that directory. Add the following code:
    <!doctype html>
    <html lang="en">
    <head>
    	<meta charset="utf-8">
    	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    	<title>Laravel Sample Login Page</title>
    	<meta name="viewport" content="width=device-width">
    	{{ HTML::style('laravel/css/style.css') }}
    </head>
    <body>
    	<div class="wrapper">
    		
    			<h1>Login Page Goes Here</h1>
    	</div>
    </body>
    </html>			
    

    (This is just a shell page for your login stuff).

That’s it. Now for the detailed explanation.

What happens

If the user goes to myexample.com/page/about the router (code in routes.php) routes them to application/controllerspage.php which runs the default method (‘index’), so function action_index is run, which echoes:


This is where all the main code for handling a public page would go.
Page name is: about

If the user goes to myexamplecms.com/admin or myexamplecms.com/admin/users or myexamplecms.com/aadmin/anyoldtext etc. they will see:

Login Page Goes Here

Because they haven’t logged in yet!

You may be wondering: “What was the point in creating admin.php if we never get to it?” Or you may be wondering: “What’s for dinner?”. I can’t answer the second question, but the answer to the first is twofold:

  1. So that you can get a clear grasp on how this all hangs together.
  2. In a real-world app we’d have a complete login process, in which case you would be able to get here. And, we do ‘get here’ anyway, in that the the constructor for Admin_Controller is executed.

To understand how this all works, comment out this line in admin.php (as shown):

 	 //  $this->filter('before', 'adminauth');

Then go to: myexamplecms.com/admin/users you will now see this:

this is the admin part of the site
Let's work with: users

How It Works

Laravel uses principles of MVC patterns to build your apps. It uses a router (routes.php) to route every request to different parts of your application’s codebase. Usually you route to a controller (like page.php and admin.php) but you can also just run an inline function (strictly speaking, a ‘closure’) like we do with the login page routing.

Laravel looks at your routes in the order you code them, so you should place your more specific routes before more general ones. In this example we have 4 main routes:

  • mycmsexample.com/page/pagename (default is home- see page.php) – specified by Route::get(‘page/(:any)’, ‘page@index’);
  • mycmsexample.com/admin/something (something is optional) – specified by Route::get(‘admin/(:any?)’, ‘admin@index’); – the ? makes it an optional parameter.
  • mycmsexample.com/login – specified by Route::get(‘login’, …
  • mycmsexample.com/ (no additional params) – specified by the default, shipped route: Route::get(‘/’, … – shows the Laravel ‘home’ page.

The authentication code (check to see if we are logged in or not) is in the route filter we defined. A filter is basically a piece of code that intercepts the user’s request and runs before continuing on to the code specified by the matching route. Filters can be global – such as ‘before’ and ‘after’ – which occur before or after every request, regardless of URI pattern, is processed. These are useful for coding system-wide tasks such as logging functions (log what page a visitor is on, for example). In our example, the filter is:

‘pattern: admin/*’ – which means ‘match on admin and everything following it – so /admin, /admin/users, /admin/projects would all be caught by this filter.

We could specify a filter of ‘admin/’ – but that would only match on the one specific value of myexamplecms.com/admin/ – not so useful.

Let’s explain the whole filter code. To refresh your memory, this is what it looks like:

 Route::filter('pattern: admin/*', array('name' => 'adminauth', function()
{
    	if (Auth::guest()) return Redirect::to_route('loginpage');
}));

We’ve already explained the filter match. The second parameter is an array. ‘name’ defines a name for our filter. We could have used the default one shipped with laravel (in the routes.php file) called ‘auth’, but I chose to rename it so that you can see how it matches to this line of code in the constructor in admin.php:

  $this->filter('before', 'adminauth');

What this means is ‘when the router takes me to controllers/admin.php, first construct the Admin_controller object. When constructing it, run the filter named ‘adminauth’ before going continuing on and running the specific method (in this case, function get_index) in the object.’ WHen this happens, the filter named authadmin gets a successful match on the path and therefore runs the code inside it.

That brings us to the last piece of the puzzle:

  if (Auth::guest()) return Redirect::to_route('loginpage');

Auth is a class object that is a part of Laravel’s core. See (some) documentation on it here. In this case, because we are a guest (Auth::guest() is true) we are redirected to a route. Note that it’s a named route called ‘loginpage’ – we specified that name in the ‘as’ array element in this line of code:

Route::get('login', array('as' => 'loginpage', 'do' => function() 
{ blah blah }));

Aside: named routes are cool because you can change the actual routing at some point later and still keep the same name. Otherwise you do a redirect like this, for example:

if (Auth::guest()) return Redirect::to('login'); 

which means your redirect is to a hardcoded route called login – what happens if you decide to change the name of login.php to auth.php, for example?

Conclusion

All that’s left now is to flesh out the login process- create a login view which asks for user id and password, and validate it using the Auth::attempt() class method. But that’s for another article. In this post we’ve learned:

  • How Laravel routes requests to different parts of the application
  • How you can write routes that accept flexible URI’s (like /admin, /admin/users, etc.)
  • How filters can intercept requests and let you do things like redirect
  • How you can embed filters directly in your controllers
  • How little code it takes to do all this, and how easy the code is to read.

When I worked through this example I copied most of the code from existing code that ships with Laravel, which I think is particularly cool. I’m looking forward to working with other features of Laravel, especially the Model stuff- ORM, etc. My only major complaint so far is the documentation. They claim it’s awesome. I think it’s incomplete. For example, on the Auth page, there was no mention of the guest() method. That came from one of the tutorials I read.

One thought on “Using Laravel: How To Use Routes, Controllers and Filters For Public and Private sections of a CMS site

  1. Gohar Sahi

    After doing the following in applications/controllers/admin.php

    // $this->filter('before', 'adminauth');

    I’m still being redirected to Login Page, however when I comment the following line as well in applications/routes.php

    //if (Auth::guest()) return Redirect::to_route('loginpage');

    it takes me to the desired output.

Leave a Reply

Your email address will not be published. Required fields are marked *