Simple and Easy Laravel Routing
One of the coolest (arguably the coolest) features of Laravel is its amazing routing features. Coming from Codeigniter where all routing is done by controller and method names, this was a breath of fresh air. I like seeing a top down view of my application and where all the pages are, and the routes file is like staring down at a roadmap from the clouds.
Today, we will not only explore the types of routes and features like filters, we will look more closely at applying them to real world scenarios. These scenarios include:
- Routing for basic static pages
- Passing parameters to functions
- Using named routes to make URLs easier to use
- Group routing
- Filtering routes for Auth or anything else
- Handling 404 Errors
Routing to Controllers and Controllers will be handled more in depth in a totally separate article. So much info there that it deserves its own party.
Let’s create an imaginary application to test all of our routing. We’ll
make an online portfolio site with a blog and a backend admin section to
add posts. Here are the guidelines for our little application.
Requirements:
- Super cool name
- Basic pages (Home, About, Work)
- Blog pages (main page and category page)
- Admin section (Authentication required)
- Login page for the admin section
- 404 page
Routing Only This tutorial will only deal with the code
associated with routing. More tutorials will follow to explain how to
fully build a web application with all the glorious parts of Laravel.
Let’s get started!Super Cool Name
Naming your application is half the battle. Maybe not half, but it sure feels like it. Let’s call this projectLagavulin
.Basic Pages Basic Routing
Let’s open up ourapp/routes.php
file and get our static
pages (Home, About, and Work) routed to. These will be the easiest
since they don’t really require anything other than their view. No
login, no parameters, just good ol’ displaying a page.Delete everything out of your routes.php and we will start fresh.
// app/routes.php
<?php
// ===============================================
// STATIC PAGES ==================================
// ===============================================
// show a static view for the home page (app/views/home.blade.php)
Route::get('/', function()
{
return View::make('home');
});
// about page (app/views/about.blade.php)
Route::get('about', function()
{
return View::make('about');
});
// work page (app/views/work.blade.php)
Route::get('work', array('as' => 'work', function()
{
return View::make('work');
}));
Now you can visit yoursite.com
, yoursite.com/about
, or yoursite.com/work
.Named Routing
You’ll notice on the work route, we’ve added an arrayas
. This creates a named route. With a named route, you can link to it in your application views using {{ URL::route('work') }}
. This will not work for the home or about page, however, since we did not name them.The home and about pages will need to be linked to using
{{ URL::to('/') }}
and {{ URL::to('about') }}
.
The benefit of a named route is that even if you change the location of
the route, as long as the name stays the same, the link will still
work.Here’s a little table to shows why named routes are great. Hint: You don’t have to go through your entire application spend time changing links.
Original | Changed To | Works? |
Route::get(‘about’)… | Route::get(‘about-us’)… | {{ URL::to(‘about’) }} |
Route::get(‘work’, array(‘as’ => ‘work’… | Route::get(‘our-work’, array(‘as’ => ‘work’… | {{ URL::route(‘work’) }} |
Blog Pages with Categories Route Parameters
Now we’re past the easy peazy static page routing. Our blog pages will need more than just static pages. They will need information from the database like our posts which include pictures, content, title, author, date, etc…We will create one route to handle all our blog stuff. This route uses optional route parameters to check if there are categories present. If there is a category, it will pull those blog posts. If not, it will show all posts.
To make the category required, just take out the
?
and = null
.// app/routes.php
<?php
...
// ===============================================
// BLOG PAGES ====================================
// ===============================================
// blogroll to show all blog posts
Route::get('blog/{category?}', function($category = null)
{
// get all the blog stuff from database
// if a category was passed, use that
// if no category, get all posts
if ($category)
$posts = Post::where('category', '=', $category);
else
$posts = Post::all();
// show the view with blog posts (app/views/blog.blade.php)
return View::make('blog')
->with('posts', $posts);
});
You can break this down into separate routes if you like. This can
make things cleaner for you if you need to have different styled views
based on category or any other special things.We get all the blog posts using Eloquent ORM You have other options for accessing the database, but since we’re just explaining routes, we’ll keep it simple. We’ll talk more on Eloquent and that database stuff later. That wraps it up for our blog pages.
Admin Section Group Routing, Route Prefixing, and Auth Filters
Our blog needs an admin section so we can add posts. It needs to be protected from the crazy people in the world so we’ll add authentication requirements. We also want all our URLs to start with/admin
.Route groups are a great way to apply the same prefixes, filters, or anything else to a group of routes. Read more about route groups.
Route prefixing will allow us to add
/admin
to the beginning of all admin routes. This way, we won’t have to do Route::get('admin/something')...
every time. Read more about prefixing.// app/routes.php
<?php
...
// ===============================================
// ADMIN SECTION =================================
// ===============================================
Route::group(array('prefix' => 'admin'), function()
{
// main page for the admin section (app/views/admin/dashboard.blade.php)
Route::get('/', function()
{
return View::make('admin.dashboard');
});
// subpage for the posts found at /admin/posts (app/views/admin/posts.blade.php)
Route::get('posts', function()
{
return View::make('admin.posts');
});
// subpage to create a post found at /admin/posts/create (app/views/admin/posts-create.blade.php)
Route::get('posts/create', function()
{
return View::make('admin.posts-create');
});
});
Auth filters will be applied to the entire group to
protect the entire admin section. You can create your own filters and do
anything you like to limit access to a route. For our purposes, we will
use the before
Read more about filters.We will add the auth filter, which is already defined in
app/filters.php
to our group. This will redirect a user to /login if they are not
logged in. Let’s add the auth filter to the group and add a route for
the login page.// app/routes.php
<?php
...
// ===============================================
// LOGIN SECTION =================================
// ===============================================
// show the login page
Route::get('login', function()
{
// show the login page (app/views/login.blade.php)
return View::make('login');
});
// ===============================================
// ADMIN SECTION =================================
// ===============================================
Route::group(array('prefix' => 'admin', 'before' => 'auth'), function()
{
// main page for the admin section (app/views/admin/dashboard.blade.php)
Route::get('/', function()
{
return View::make('admin.dashboard');
});
...
});
Now if somebody tries to access lagavulin.com/admin
or lagavulin.com/admin/posts
, they will be redirected to the login page.Login Form POST Routing
We will need to validate and process the login form. Let’s make a quick route to do that and useRedirect::intended()
to redirect them back to their intended destination before our filter so kindly kicked them to the login page.// app/routes.php
<?php
...
// ===============================================
// LOGIN SECTION =================================
// ===============================================
// show the login page
Route::get('login', function()
{
// show the login page (app/views/login.blade.php)
return View::make('login');
});
// process the login
Route::post('login', function()
{
// validate
// process login
// if successful, redirect
return Redirect::intended();
});
// ===============================================
// ADMIN SECTION =================================
// ===============================================
...
}));
Creating Blog Posts
Now that we’ve seen howPOST
routing works, let’s handle creating the new blog post form. The Route::get('posts/create')...
will show the form. In our form action, we can set it to <form action="/admin/posts/create">
. Let’s add a route to process the form, and show a message that the post was saved.// app/routes.php
<?php
...
// ===============================================
// ADMIN SECTION =================================
// ===============================================
Route::group(array('prefix' => 'admin', 'before' => 'auth'), function()
{
...
// subpage to create a post found at /admin/posts/create (app/views/admin/posts-create.blade.php)
Route::get('posts/create', function()
{
return View::make('admin.posts-create');
});
// process the create blog post form
Route::post('posts/create', function()
{
// add the post to the database
// $post = new Post;
// $post->title = Input::get('title');
// more stuff here
// $post->save();
// create a success message
Session::flash('message', 'Successfully created post!');
// redirect
return Redirect::to('admin/posts/create');
});
});
Processing forms and saving to the database is easy and fun. We’ll
get to it in the next few Laravel posts. Now that we have static pages,
blog pages, admin section and blog post creation, let’s handle 404
errors.404 Errors
404 Errors are very easy to handle. We’ll add a simple route to the end of our routes.php file and call it a day. To read up more on handling all sorts of errors, read the error docs.// app/routes.php
<?php
...
// ===============================================
// 404 ===========================================
// ===============================================
App::missing(function($exception)
{
// shows an error page (app/views/error.blade.php)
// returns a page not found error
return Response::view('error', array(), 404);
});
Conclusion
As you can see, Laravel makes it very easy to lay the foundation of your entire site in the routes.php file. You can see every page, section, authorization requirements, and handle RESTful routes. This helps us to maintain our application from this file and really get a vision of how everything works together.Here is the full code for our routes.php file now. We were able to set the foundation for a blog and portfolio site with an authenticated admin section!
// app/routes.php
<?php
// ===============================================
// STATIC PAGES ==================================
// ===============================================
// show a static view for the home page (app/views/home.blade.php)
Route::get('/', function()
{
return View::make('home');
});
// about page (app/views/about.blade.php)
Route::get('about', function()
{
return View::make('about');
});
// work page (app/views/work.blade.php)
Route::get('work', array('as' => 'work', function()
{
return View::make('work');
}));
// ===============================================
// BLOG PAGES ====================================
// ===============================================
// blogroll to show all blog posts
Route::get('blog/{category?}', function($category = null)
{
// get all the blog stuff from database
// if a category was passed, use that
// if no category, get all posts
if ($category)
$posts = Post::where('category', '=', $category);
else
$posts = Post::all();
// show the view with blog posts (app/views/blog.blade.php)
return View::make('blog')
->with('posts', $posts);
});
// ===============================================
// ADMIN SECTION =================================
// ===============================================
Route::group(array('prefix' => 'admin'), function()
{
// main page for the admin section (app/views/admin/dashboard.blade.php)
Route::get('/', function()
{
return View::make('admin.dashboard');
});
// subpage for the posts found at /admin/posts (app/views/admin/posts.blade.php)
Route::get('posts', function()
{
return View::make('admin.posts');
});
// subpage to create a post found at /admin/posts/create (app/views/admin/posts-create.blade.php)
Route::get('posts/create', function()
{
return View::make('admin.posts-create');
});
// process the create blog post form
Route::post('posts/create', function()
{
// add the post to the database
// $post = new Post;
// $post->title = Input::get('title');
// more stuff here
// $post->save();
// create a success message
Session::flash('message', 'Successfully created post!');
// redirect
return Redirect::to('admin/posts/create');
});
});
// ===============================================
// 404 ===========================================
// ===============================================
App::missing(function($exception)
{
// shows an error page (app/views/error.blade.php)
// returns a page not found error
return Response::view('error', array(), 404);
});