Code Happy
Code Happy
Code Happy
Contents
Acknowledgments
Errata
ii
Feedback
iii
Introduction
iv
Getting Started
1.1
1.2
1.3
Project Structure
2.1
2.2
Using Controllers
3.1
Routing Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2
Passing Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
3.3
Using Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
3.4
RESTful Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.5
The Base_Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
3.6
Advanced Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
15
4.1
Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
4.2
16
4.3
Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4.4
Route Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
20
5.1
Retrieving URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
5.2
Generating Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
CONTENTS
ii
Forms
25
6.1
Creating Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
6.2
Adding Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
6.3
Generating Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
6.4
Generating Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
6.5
Secret Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
6.6
CSRF Token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
6.7
Form Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
Handling Input
30
7.1
Request data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
7.2
Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
7.3
Flash Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
Validation
33
8.1
Set up validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
8.2
Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
8.3
Validation Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
8.4
38
8.5
39
8.6
Validation Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
Migrations
41
9.1
Database Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
9.2
Migrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
47
48
48
50
10.4 Ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
51
52
10.7 Aggregates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
10.8 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
CONTENTS
iii
53
10.10 Insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
10.11 Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
10.12 Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
11 Eloquent ORM
56
56
11.2 Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
63
65
65
67
12 Events
68
68
69
69
69
70
13 Blade Templates
72
72
13.2 Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
73
14 Authentication
76
14.1 Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
78
79
81
14.5 Customization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
CONTENTS
iv
85
85
86
88
15.4 Routes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
88
15.5 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
89
91
95
16 Unit Testing
97
16.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
97
97
98
99
17 Caching
100
102
105
108
CONTENTS
21 Encryption
v
112
114
121
125
Acknowledgments
First of all I would like to thank my girlfriend Emma, for not only putting up with all my nerdy
ventures, but also for taking the amazing red panda shot for the books cover! Love you Emma!
Taylor Otwell, I love you too man, but in a totally manly way. Thanks for making a framework
thats a real pleasure to use, makes our code read like poetry, and for putting so much time, and
passion into its development.
Eric Barnes, Phill Sparks, Shawn McCool, Jason Lewis, Ian Landsman, thanks for all the support
with the framework, and for allowing me to be part of a project with so much potential.
To all my blog readers who took interest in my tutorials, thanks! Without you I would never
have had the confidence to write a book.
Errata
Although I have taken every care to ensure that the book is error-free, sometimes tired eyes will
proof read badly, and errors will slip through the radar. If you do happen to encounter an error in
the book, be it a spelling mistake or an error within a code block. I would be grateful if you could
alert me to its presence by emailing me at [email protected] and let me know the chapter and
location of the error.
Errors will be fixed as they are discovered, and fixes will be released with the next publish of the
book.
mailto:[email protected]
ii
Feedback
Likewise you can send any feedback you may have about the content of the book or otherwise
by sending an email to [email protected]. I will endevour to reply to all mail that I receive
about the book.
mailto:[email protected]
iii
Introduction
Hi there! Im Dayle Rees, and Im going to be taking you on a magical journey into the world of
Laravel! Okay on second thoughts that sounds really cheesy. You see this is my first book, so I
am gonna be a little rusty at all the posh literary stuff, so if you like straight talking, and being
spoken to like a real human being boy are you in for a treat!
You might be asking yourselves So why should I trust this guy to teach me Laravel? He isnt
even an experienced author!
Well what I lack in experience, I make up for in enthusiasm. I am a huge fan of web development,
and the tools and tricks that save us time, or make our job a lot easier. Laravel fills both of those
requirements, and is one of the most useful pieces of software I have ever discovered. In fact my
enthusiasm and passion for the framework, that can only be rivaled by the framework author
himself has led to me being included as a member of the Laravel core team, or Council as we
like to call it, sounds fancier right?
Being on the Council grants me certain privaledges such as being notified of new ideas and
planned additions to the framework, and by contributing to the framework I am constantly in
touch with its forever improving codebase. This puts me in a good position to keep the book up
to date, which I intend to do with every future release of the framework.
Although I despise going off-topic, it seems compulsary to have a short paragraph about the
author within books of this kind, so lets keep it short and sweet. I live on the coast of Wales
(thats a country on the side of England for you Americans) and I work for a large public
sector organization in Aberystwyth but in my spare time I am highly involved with the Laravel
framework. Oh and as I said before, I dont claim to be a literary genius, lets be honest my
writing is gonna suck, its not gonna be all fancy like those other coding books. I will be talking
to you like a real person, you might actually talk back too, we will see. Hopefully my passion
for Laravel will make up for my common English (to be fair, I am a Welshman). You dont need
to know anything more about me though, lets switch our focus to Laravel.
Laravel is a breath of fresh air in the world of PHP. The PHP programming language is generally
quite renowned for its ugly function names, and while we PHP developers have learned to love
it, the syntax can be a little ugly compared to some modern Japanese languages. Hi Ruby!
Fortunately Laravel changes this, in fact.. I believe that the Laravel syntax (which granted builds
on PHPs own) is so expressive, and neat that I find it much easier to read than Ruby. Its not
too compact, and while it wont read like an English sentence, it will read like poetry that can
only be seen by the eyes of a programmer.
But Dayle..
You say, suddenly worried that your $4.99 could have been better spent on some mind numbing
fun juice.
Laravel is a framework, not a language!
iv
Introduction
Its true, you got me. Laravel may not be a language, but it doesnt need to be. We love PHP,
come on, lets be honest, we put up with its ugliness, we enjoy typing all those brackets and
semi-colons. Laravel simply adds the shortcuts, or a code disguise on top to make the experience
so much sweeter.
I think that the pleasure of working from the framework, is brought on by its expressive methods,
which are consistent throughout the framework. Str::upper() Try to tell me you dont know
what this does, try to tell me it doesnt make sense.
I cant.
Yep, I thought so. Well I could jabber on all day about everything that makes Laravel wonderful,
lets see, theres Eloquent, the best ORM I have ever seen. It was what first brought me to the
framework.
The option of using closures to route, but only if you want to. I think they look great!
Not having to load libraries before using them, yes.. you heard me right. You will see this in
action later.
No there are far too many wonderful features to explain here, I think it would be best if we dived
in and started learning, after all.. if you spent $4.99 on this instead of mind numbing juice, you
must already have had your interests peaked by the framework right? Onwards!
1 Getting Started
Laravel is a PHP 5.3 web application framework written by Taylor Otwell. It was written with
PHP 5.3 features in mind, the combination of these features and its very expressive syntax has
led to the framework gaining in popularity.
In this book we will be exploring Laravel from the ground up starting with its installation, which
I am sure you will agree is a breeze.
In order to use any PHP Framework (not just Laravel) you will need to have a PHP enabled web
server, I would recommend installing a webserver on your local development machine, to allow
you to test your work without needing to upload your files each time you make a change.
This chapter makes the following assumptions:
You have a working Apache-based web server.
You are familiar with the servers file system, and how to move / copy files.
You have access to modify Apache config files.
If you use a different web server, you will be able to find many articles online on how to
accomplish the tasks found below for your server.
First we will need a copy of the frameworks source code, simply head over to Laravel.com
and hit the big orange download button. For added security, I would recommend extracting the
contents of the package to somewhere other than your web root. Make a mental note of where
you extracted the source to (or find a sticky note!).
We now have two options to allow the framework to execute as expected, I would advise trying
the first method, as it is the real way of installing the framework and allows us to specify a
more thorough config. However I find the second method much quicker when working with
many projects on a development server.
<VirtualHost 127.0.0.2>
DocumentRoot "/path/to/laravel/project/public"
ServerName myproject
http://laravel.com
https://twitter.com/#!/taylorotwell
http://laravel.com
Getting Started
4
5
6
7
8
<Directory "/path/to/laravel/project/public">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
</Directory>
</VirtualHost>
We must update the IP address to one which is not currently in use. (Best not to use 127.0.0.1,
this is your loopback address, and you may have something else using it.) Change the two paths
to point to your Laravel source packages public folder. Now restart your webserver.
Next we will create a new local DNS entry to point a project name to your VirtualHost. First
open the hosts file normally found at c:\windows\system32\drivers\etc\hosts on Windows
or /etc/hosts on unix-based OSs.
Add the following line, using the IP address you used in your VirtualHost declaration, and a pet
name for your project:
1
127.0.0.2
myproject
ln -s /path/to/laravel/public/folder /path/to/web/root/subdirectory
For example :
1
ln -s /home/dayle/laravel/myapp/public /var/www/html/myapp
Note: You could also symbolic link the public folder directly to your web root, but I prefer
using a subdirectory so I can work on several projects.
You should now be able to navigate to : http://localhost/myapp
with your web browser to see the Laravel welcome page.
Getting Started
http://daylerees.com
http://laravel.com
http://laravel.com/docs
http://laravel.com/api
http://forums.laravel.com
2 Project Structure
Laravels source package contains a number of different directories, lets take a look at the project
structure, to gain a greater understanding of how things work. I may use some terms to describe
various features of Laravel that could be confusing if you are just starting out, if so, bear with
me as we will cover each feature in more detail in a later chapter.
/application
/bundles
/laravel
/public
/storage
/vendor
/artisan [file]
/paths.php [file]
Project Structure
used to hold any publicly accessible assets, such as CSS, Javascript files and images. The laravel
subfolder contains the files needed to render the offline documentation correctly.
/storage
The storage directory is used as file store for services that use the file system as a driver, for
example Sessions, or the Cache class. This directory must be writable by the web-server. You
will not need to interact with this directory to build a Laravel application.
/vendor
The vendor directory contains code used by Laravel, but wasnt written by the frameworks
author or contributors. The folder contains open source software, or parts of software that
contribute to Laravels features.
/artisan [file]
Artisan is Laravels Command Line Interface, it allows you to perform numerous tasks on the
command line, and even create your own tasks! To run Artisan simply type:
1
php artisan
/paths.php [file]
This file is used by the Framework to determine paths to the important directories mentioned
above, and provide a shortcut for retrieving them ( using path()). You should not need to edit
this file.
/config
/controllers
/language
/libraries
/migrations
/models
/tasks
/tests
/views
/bundles.php [file]
/routes.php [file]
/start.php [file]
http://laravel.com/docs/artisan/commands
Project Structure
Project Structure
/tests
The tests folder provides a location for you to keep your application Unit tests. Also if you use
PHPUnit, you are able to execute all tests at once using the Laravel Artisan PHP command line
interface.
/views
The views directory contains your HTML template files to be used by controllers or routes,
although please use a .php extension for files in this folder. You can alternatively use a .blade.php
extension to enable parsing with the Blade templating library which is better explained in the
official documentation.
/bundles.php [file]
To enable a bundle, simply add it to the array in bundles.php, you can also use a key-value namearray pair to define extra options for the bundle. These options can be found in the Laravel
documentation.
/routes.php [file]
The routes file contains the methods which enable routes to be mapped to their appropriate
outcome with Laravel, this topic will be explained more thoroughly in upcoming posts. This
file also contains declarations for several events including error pages, and can be used to define
View Composers or Route Filters.
/start.php [file]
The start.php contains startup routines for the /application bundles, such as auto-loading
directories, loading configs, and other wonderful useful stuff! Feel free to append to this file.
In the next chapter we will be covering Routing using Controllers by creating a small dynamic
website with several pages.
http://laravel.com/docs/bundles#starting-bundles
3 Using Controllers
In this chapter we will be creating a simple multi page website to demonstrate the workings of
Laravels routing system, without delving into anything too complicated.
As I mentioned in the previous chapter, there are two options available to route web requests
to your code, Controllers and Routes. In this chapter we will be using Controllers, as anyone
joining us from other Frameworks may be more familiar with them.
<?php
2
3
4
5
// application/controllers/account.php
class Account_Controller extends Base_Controller
{
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
A Controller is a PHP Class that represents a section of your website, or web application. Its
Methods or Actions represent an individual page, or an end-point of a HTTP request.
In the above example our Account Controller represents our users section of the web site, a
profile page, a login page, and a logout page. Note that the Controller name is appended with
_Controller and that action names are prefixed with action_. Controllers must extend the
Base_Controller, Controller or another Controller class.
Our controller is created in the application/controllers folder as a lower-case file matching
the controller name, the Controller above would be saved at :
8
Using Controllers
/application/controllers/account.php
Before we can use our Controller, we need to register it in /application/routes.php, lets add
the following line :
1
<?php
2
3
4
// application/routes.php
Route::controller('account');
If our controller is in a sub-folder of the controllers directory simply use periods (.) to separate
the director(y | ies) like so :
1
<?php
2
3
4
// application/routes.php
Route::controller('in.a.sub.folder.account');
If our controller exists in a bundle, simply prefix with the bundle name and a double colon :
1
<?php
2
3
4
// application/routes.php
Route::controller('mybundle::account');
Now if we visit:
1
http://myproject/account/login
we see This is the login form.. This is because now that our Controller has been mapped in
the Route class, the first segment (between the slashes) of the URL specifies the controller, and
the second segment (yes, again between the slashes) specifies the action.
In simple terms /account/login is mapped to Account_Controller->action_login() and the
result of our method is displayed.
Now lets try visiting /account instead :
1
Why does this happen? The index action is a special action, it is called when no action is specified
in the URL, therefore the above page could also be called with the following URL :
1
/account/index
Using Controllers
10
<?php
2
3
4
5
6
7
// application/controllers/account
public function action_welcome($name, $place)
{
echo "Welcome to {$place}, {$name}!";
}
Here our action parameters are method parameters, so the above code should seem familiar, lets
try visiting the route /account/welcome/Dayle/Wales..
1
Parameters can be used to pass resource identifiers to enable CRUD actions on data, or anything
you can think of! As you can see, they offer a great deal of flexibility to our actions.
Note : You can assign values to your action parameters to make them optional in the URL.
/application/views/welcome.php
<h1>Holla!</h1>
<p>This is the welcome action of the account controller.</p>
Now we need to return the View from our welcome action, Laravel has a beautiful expressive
way of doing this, lets take a look :
Using Controllers
11
<?php
2
3
4
5
6
7
// application/controllers/account.php
public function action_welcome($name, $place)
{
return View::make('welcome');
}
The more nerdy types among my readers will have realized that the statement is telling Laravel
to create (make) a View object from the file application/views/welcome.php (extension not
needed here) and return it as the result of the welcome action.
You will also notice that the make() method looks in the application/views folder for its views.
If you would like to specify an absolute path to a view file simply use the path: prefix, for
example path: /path/to/my/view.php.
Now if we visit /account/welcome/Dayle/Wales we will be greeted with the web page which
we defined in our View file.
Note that you can also use the same sub-folder and bundle prefixes that we previously used with
controllers, to refer to Views.
I know what youre thinking, now our welcome message isnt very dynamic at all? Lets see if
we can fix this. Lets pass our action parameters to the View, we can do this using the with()
method and we can see Laravels elegant method chaining in action, here we go!
1
<?php
2
3
4
5
6
7
8
9
// application/controllers/account.php
public function action_welcome($name, $place)
{
return View::make('welcome')
->with('name', $name)
->with('place', $place);
}
With the with() method you can pass any value (or object) to the View, and give it a nickname
for accessing it from the view, we have used the same nicknames as our parameter names in this
example, but you can call them anything you want!
Now lets use this data in our view :
1
2
<h1>Holla!</h1>
<p>Welcome to <?php echo $place; ?>, <?php echo $name; ?>!</p>
Now our action works as it did before, only better formatted with neater source code separating
all logic from our visual layer.
Instead of using several with() methods, you can pass an array as a second parameter to make()
with key-value pairs, this can save space but has the same result, here is an example.
Using Controllers
12
<?php
2
3
4
5
6
7
8
9
// application/controllers/account.php
public function action_welcome($name, $place)
{
$data = array(
'name'
=> $name,
'place' => $place
);
10
11
12
Note : I like to call my view array $data, but you can call it whatever you want!
In a later tutorial we will cover Views in more detail, including Blade templating, nested views
and other advanced templating options.
<?php
2
3
4
5
6
// application/controllers/home.php
class Home_Controller extends Base_Controller
{
public $restful = true;
8
9
10
11
12
13
14
15
16
17
18
Using Controllers
13
Simply add a boolean public class attribute names $restful and set it to true, then prefix your
actions with the HTTP verb to respond to, rather than action_.
Common HTTP verbs are GET, POST, PUT and DELETE.
<?php
2
3
4
//application/routes.php
Route::get('superwelcome/(:any)/(:any)', 'account@welcome');
Here we are saying, lets send all web requests with the GET HTTP verb, and the address
/superwelcome/(:any)/(:any) to the welcome action of the account controller. The (:any)
segments are place-holders for our parameters, and will be passed in the order that they are
provided. Using (:num) will match only numbers, and using (:any?) will create an optional
segment.
So now a visit to /superwelcome/Dayle/Wales will show our lovely view page!
The advantage of defining routes, is that we can have our URLs in whatever order we like, in
whatever format we like, for example we could also have..
1
<?php
2
3
4
5
//application/routes.php
Route::get('superwelcome/(:any)/(:any)', 'account@welcome');
Route::get('welcome/(:any)/to/(:any)', 'account@welcome');
Using Controllers
14
Now we have two different routes, with the same result page.
It is worth noting that Routes that are defined higher up in the routes.php file are given a
higher priority, so with the following example..
1
<?php
2
3
4
5
// application/routes.php
Route::get('(:any)/(:any)', 'account@welcome');
Route::get('welcome/(:any)/to/(:any)', 'account@welcome');
..the second route would never be triggered because the (:any) in the first route would respond
to the welcome in the second route. This is a common mistake when starting out with Laravel,
be sure to keep an eye on the priority of your routes!
We will be covering routing in more depth in the next chapter which will also cover routing with
closures instead of controllers.
4.1 Closures
Lets have a look at a route that routes to a closure.
1
<?php
2
3
4
5
6
7
// application/routes.php
Route::get('/', function()
{
return View::make('home.index');
});
In this example we are responding to requests to the root of the web application that use the
HTTP verb GET with a closure that simply returns a view object. The output is the default
welcome page.
Please note that you only need the root slash for the root page, all other routes omit it, for
example..
1
<?php
2
3
4
5
6
7
// application/routes.php
Route::get('account/profile', function()
{
return View::make('account.profile');
});
Routes are RESTful by nature, but you can use Route::any() to respond to any HTTP verb. Here
are your options:
http://php.net/manual/en/functions.anonymous.php
15
16
<?php
2
3
4
5
6
7
8
// application/routes.php
Route::get();
Route::post();
Route::put();
Route::delete();
Route::any();
To pass parameters to your Closures, simply add the usual view placeholders to the URI, and
define parameters in your Closure, they will be matched in the order from left to right, for
example..
1
<?php
2
3
4
5
6
7
// application/routes.php
Route::get('user/(:any)/task/(:num)', function($username, $task_number)
{
// $username will be replaced by the value of (:any)
// $task_number will be replaced by the integer in place of (:num)
$data = array(
'username'
'task'
);
9
10
11
12
=> $username,
=> $task_number
13
14
15
});
Explanation
(:any)
(:num)
(:any?)
<?php
3
4
5
6
7
17
// application/routes.php
Route::get('/', function()
{
return Redirect::to('account/profile');
});
Lovely! Couldnt be simpler, wait no, it could, and is! Lets take a look at a named route :
1
<?php
2
3
4
5
6
Instead of passing a Closure as the second parameter, we now pass an array with the key do
pointing to the closure instead, this allows us to add all kind of extra information to the route.
The as key, assigns a nickname to our route, this is what named routing is all about. Lets see
how it can be used to improve the Redirect:: from before.
1
<?php
2
3
4
5
6
Route::get('/', function()
{
return Redirect::to_route('profile');
});
There, now we have that nasty URI out of our code, very pretty. All of the classes or helpers
which refer to routes have a similar method to route to a named route, this can really clean up
your code, and makes it read like a book. Also, if you later decide to change the URI for a certain
page, you will not have to go back and change all of your links and redirects!
4.3 Filters
Ok ok I said I was going to be explaining Routes in this one, but I honestly cant think of a
better place to cover Filters, and they are related, so here we go.
Filters are exactly as they sound, they are code, or tests that can be performed before or after
a route, and other key events within the framework. Laravel has four special route filters that
are defined by default in application/routes.php, lets take a look at them.
1
<?php
2
3
Route::filter('before', function()
{
// Do stuff before every request to your application...
5
6
18
});
7
8
9
10
11
Route::filter('after', function($response)
{
// Do stuff after every request to your application...
});
12
13
14
15
16
Route::filter('csrf', function()
{
if (Request::forged()) return Response::error('500');
});
17
18
19
20
21
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::to('login');
});
The first two routes, execute the encapsulated closure before and after every request (or route /
action) to your application. What you do within the enclosure is entirely up to you, start libraries,
provide data to something, your own creativity is your only limitation. They are special filters
in that they do not need to be assigned to individual routes.
The csrf filter is used to prevent cross-site-request-forgery and can be applied to routes which
are the result of an AJAX call for extra security.
The auth filter can be applied to any route, to prevent access unless a user is currently logged
in using Laravels authentication system.
To apply csrf or auth filters to your Routes, simply add a new array entry to the second
parameter like so:
1
<?php
2
3
4
5
6
7
Route::get('/', array('as' => 'profile', 'before' => 'auth', 'do' => functi\
on()
{
return View::make('account/profile');
}));
The key for the array can be either before to run the filter before your route, or after to run
it after. Multiple filters can be applied by seperating their names with a | (pipe) for example
auth|csrf.
As of Laravel 3.1, if you would like to add a filter to a number of requests whose URIs match a
specific pattern, use the following line :
http://en.wikipedia.org/wiki/Cross-site_request_forgery
19
<?php
2
3
This will apply the auth filter to all route URIs that start with admin/.
<?php
2
3
4
5
6
7
8
Route::get('dashboard', function()
{
// do stuff
});
10
11
12
13
14
});
now both the panel and dashboard routes are protected by the auth filter.
Although routing can be very simple, routes can also be as complex as you need them to be, use
route groups to avoid duplicating common rules across many routes and keep your code DRY.
(Dont repeat yourself!)
The next chapter will cover the creation of links, so that we can move from one routes page to
the next.
<?php
2
3
4
echo URL::base();
// http://myproject/
Great! Now we have the full URL to our site, with or without the index.php on the end, it all
depends on your current setup. What about the current URL, the one that is being routed at the
moment, can we get that? You betcha! Simply use the current() method.
1
<?php
2
3
4
echo URL::current();
// http://myproject/this/page
By default, Laravel will strip off the query string, if one is appended to the URL. If we want to
retrieve the current URL along with the query string, we can use the full() method instead.
1
<?php
2
3
4
echo URL::full();
// http://myproject/this/page?thing=stuff
20
21
Knowing our base URL and current URL can be handy, but it would be more useful if we could
get the URL to other routes or pages, then we could create links.
To generate a URL to a route, we use the to() method, and hand it the route we are trying to
retrieve, this is much easier than specifying the full path, for example..
1
<?php
2
3
4
echo URL::to('my/route');
// http://myproject/my/route
If we want to link to this page securely, via the HTTPS protocol we can use the method to_secure() instead.
1
<?php
2
3
4
echo URL::to_secure('my/route');
// https://myproject/my/route
Do you remember being taught about named routes in the routing chapter? Of course you do!
Heres an example of one again..
1
<?php
2
3
4
5
Here we have a route that we have named login using the as array key. Well I told you that
it would be useful later, and now is the time for named routes to shine. Lets make a link to our
named login route..
1
<?php
2
3
4
echo URL::to_route('login');
// http://myproject/login
Woah! Very clean and expressive I think you will agree. What if we need to supply parameters
to our route? Simple, just pass an array of parameters as a second parameter to the to_route()
method. Lets imagine for a second that our login route looks more like this
1
<?php
2
3
Route::get('my/(:any)/login/(:any)/page')..
22
Its a terrible route, please dont use ugly URLs like this one, but it will help to illustrate a point.
You see if you pass parameters to the to_route() method, Laravel will automatically work out
which order they should appear in the URL, and return the full URL with the parameters in the
right place, neat!
1
<?php
2
3
http://myproject/my/5/login/7/page
Great! Now our routes will look squeaky clean.. as long as we dont create routes as complicated
as that one.
So thats routes cleared up, but we shouldnt forget controllers. No one likes to be left out.
Fortunately theres a nice and clean way to create a link to a controller action. Simply use the
to_action() method, for example..
1
<?php
2
3
4
echo URL::to_action('dashboard@home');
// http://myproject/dashboard/home
Simply pass the controller name and action, separated by an @ (at) symbol. Once again you can
pass an array of extra parameters as a second parameter to the to_action() method if you need
to.
If we are dealing with assets, a CSS style-sheet for example, rather than routes pages we will
need a very different URL. We cant use URL::to() because that might put an index.php in the
URL, or resolve it to one of our routes.
Instead we can use the to_asset() method to generate a correct link. Simply pass the application
relative path to our style-sheet, and Laravel will take care of the rest.
1
<?php
2
3
echo URL::to_asset('css/style.css');
http://myproject/css/style.css
These methods are already very handy, but Laravel takes this a step further by providing shorter
helper methods which look great when used in our views. Here is a list of these helpers, and
their longer alternatives.
23
Helper
Method
url()
asset()
route()
action()
URL::to()
URL::to_asset()
URL::to_route()
URL::to_action()
Sure that would work, but its a little ugly. In Laravel if something is a little ugly, there is always
a better way of handling it. Links are no exception.
Why dont we use the HTML class to generate a link? After all, thats what the HTML class is
for. It is used to generate all kinds of HTML tags.
1
If you are an SEO ninja, and cannot stand to see a link without a title attribute, simply pass an
extra array.
1
2
Which gives..
1
One of the great features of Laravel is how consistent its method naming is, many of the
HTML::link methods follow a similar naming pattern as the URL::to methods, which makes
them easy to remember. Lets take a look at how we can link to a secure page (via HTTPS).
1
<?php
2
3
4
24
We can also use link_to_route, to create a link to a named route just like we did with the URL
library.
1
<?php
2
3
4
HTML::link_to_route('login', 'Login!');
// <a href="http://myproject/login/page">Login!</a>
Once again we can use the link_to_action() method to link to a controller-action pair, for
example..
1
<?php
2
3
4
HTML::link_to_action('account@login', 'Login!');
// <a href="http://myproject/account/login">Login!</a>
Laravel even gives us a method of easily creating mailto links from an email address. Lets take
a look.
1
<?php
2
3
4
6 Forms
Forms are an important part of any web-based application. They help control the flow of
the application, allow us to receive input from our users and make decisions that affect the
functionality of our applications. They are also my least favorite thing in the world to write.
Fortunately for me, Laravels form class takes care of a lot of the hard work for us, by providing
useful methods for generating common form elements. Lets use the form class to create a simple
web form in one of our views.
// form.php
<?php echo Form::open('my/route'); ?>
3
4
5
6
7
8
9
10
11
12
13
14
15
Take a moment, stare at the form source, you have never seen a form so clean. Say it out loud
to yourself, go on.. I will wait.
I have never seen a form so clean.
You are right, its beautiful, lets have a look at the generated source to make sure Im not just
teaching you wrong, you know, for fun?
1
2
3
4
5
6
7
8
25
26
Forms
9
10
11
12
13
14
</form>
Great, it worked! I mean of course it did! Lets go over the form line by line to see how it works,
on our first line we have the Form::open() method, which creates a form open tag for us.
1
The first parameter to the method is the URI we wish to submit the form to. The second
parameter is the METHOD used to submit the form, if you dont provide a method as a string
Laravel will assume that you want a POST form, which is the most common usage.
The third parameter is also optional, you can pass an array of attribute => value pairs to add
extra attributes to the <form> tag. For example if you wished to target the form with Javascript
you may want to pass array('id' => 'myform') as the third parameter to give the element an
id.
To submit a form to a secure URI (https) you will need to use the open_secure() method instead
of open(), it accepts the same parameters.
If you wish to be able to have files uploaded from your form, it will need to use multipart/data,
use open_for_files() instead of the open() method. This method also accepts the same
parameters.
Finally if you wish to submit to a secure URI, and have files uploaded you will need to use
the open_secure_for_files() method, which once again accepts the same parameters, and is a
combination of both open_secure() and open_for_files().
Forms
27
The first parameter to the method, is the value of the elements name attribute, the second optional
parameter is the default value of the element. Once more we can pass an array of HTML
attributes as an optional third parameter, are you starting to see a pattern yet?
The textarea() and hidden() fields also accept the same parameters.
Checkboxes can be created using the checkbox() method, with the first parameter being the
name of the element, the second being the value, and the third option is an optional boolean
switch to set whether the element is initially checked or not. The fourth optional parameter
again sets attributes, in fact.. go ahead an assume all future inputs accept an attributes array as
their optional final parameter. Lets have a look at a checkbox generator..
1
2
The radio() method creates radio buttons, and shares the same parameters as the checkbox()
method.
Next we have drop downs, the most awkward of all form elements. Fortunately all we need
to do is pass a name, an array of value => label options, and an optional parameter to state
which option should be selected by default to the select() method. Our dropdown will then be
generated for us, for example..
1
<?php
2
3
4
5
6
7
8
Form::select('roles', array(
0 => 'User',
1 => 'Member',
2 => 'Editor',
3 => 'Administrator'
), 2);
and we get..
1
2
3
4
5
6
<select name="roles">
<option value="0">User</option>
<option value="1">Member</option>
<option value="2" selected="selected">Editor</option>
<option value="3">Administrator</option>
</select>
Forms
28
<?php
2
3
Form::submit('Login');
<?php
2
3
4
5
6
7
8
9
<?php
2
3
Form::token();
Forms
29
<?php
2
3
4
5
Form::macro('shoe_size', function() {
return '<input type="show_size" />';
});
Now we can use the Form class to generate our shoe size field in the same way as any other
input, for example..
1
If you need to use parameters, simply add them as parameters to the closure. Enjoy creating
your own unique input generators!
7 Handling Input
Now that we know how to create forms, we need to learn how to handle the input that has been
sent by them. As always, Laravel has provided an ultra clean way of dealing with your input
data. No need to interact with PHP arrays such as $_POST, $_GET and $_FILES. Lets be honest,
those look ugly.
<?php
2
3
$panda = Input::get('panda');
Now we have a Panda! Great.. we have too many already. One thing you need to remember
about the get() method on the Input class, is that it doesnt refer to $_GET data, get() is just
a nice and expressive short method name for retrieving all kinds of data. The input class adds
responds to get() with all kinds of request data, including $_POST.
If a piece of request data isnt set, the Input class will return null. If you pass a second
parameter to the get() method and the index doesnt exist, then the method will return the
second parameter instead. Very useful!
1
<?php
2
3
If you would like to retrieve the entire request array, simply skip the index. Easy as that.
1
<?php
2
3
$morepandas = Input::get();
By default the get() array wont includes values from the $_FILES array, however if you use
all() instead of get() it will contain files too.
1
<?php
2
3
$pandas_and_files = Input::all();
If you would like to check if a piece of post data exists, without actually returning it, simply use
the elegant and highly expressive has() method, which will return a boolean result.
1
<?php
2
3
$do_we_have_a_panda = Input::has('panda');
30
Handling Input
31
7.2 Files
To access an element from the $_FILES array, simple make a call to the Input::file() method,
for example..
1
<?php
2
3
$file = Input::file('spoon');
If you simply want to retrieve a file attribute, then add a period, and an attribute key to the first
parameter, for example to retrieve the file size..
1
$size = Input::file('spoon.size');
Once again, calling the method without a parameter will retrieve the full array of files.
1
$files = Input::file();
<?php
2
3
Input::flash();
If you only want to flash a portion of the current request data, simply pass only as the first
parameter to the method, and an array of field names that you wish flashed as the second
parameter.
1
<?php
2
3
Now we will take Betty and Simon with us to the next request. Alternatively we could specify
a list of fields that we dont want to take with us using the except option, for example..
1
<?php
2
3
Input::flash('except', array('uncle_bob'));
Handling Input
32
There, now we can leave Uncle Bob behind, hes an arrogant soul, and dislikes our national
animal the red panda.
Now we can use the usual Redirect::to() method to move to a new request. From here we
can use the expressive Input::old() method to retrieve a value that has been flashed from a
previous request.
1
<?php
2
3
$betty = Input::old('betty');
As you can see, Betty has survived the transition. You can think of flash data as those fuzzy
transporter pads from Star Trek, moving Kirk and his buddies from one request to the next.
Once again you can skip the parameter to return a full array of flash data.
1
<?php
2
3
$people = Input::old();
You can use the had() method to see if an index of flash data exists.
1
<?php
2
3
Input::had('uncle_bob');
<?php
2
3
return Redirect::to('party')->with_input();
The with_input() method will flash all of our request data for us, it also accepts the same only
and except methods as our flash() method.
1
<?php
2
3
4
8 Validation
Validation is an important part of many web applications. You can never trust your users, they
have been plotting to destroy you for weeks, by abusing your forms with evil javascripts.
We cant let them win, they must not destroy our beautiful applications. Lets validate all input
provided by the user, that way they wont be able to harm us at all.
Naturally Laravel has a library, aptly named Validation that will do all the hard work for us.
<?php
2
3
$input = Input::get();
Now normally you dont want to use the get() method, as its an easy way to populate your
input array with extra data you dont need. In fact the open source collaboration site github
was a victim to mass assignment. I have used get() to simplify the tutorial, in your applications
please build the input array only with the fields you need.
Our input array now contains something that looks a little like this..
1
<?php
2
3
array(
'name' => 'John',
'age' => 15
4
5
6
Lets validate these fields to make sure they make sense to our application, before we can start
the validation process we need to create a set of rules that will be used to validate each field.
With the validator class, rules are defined in an array format, lets jump right in and take a look.
1
<?php
2
3
4
5
6
$rules = array(
'name'
'age'
);
=> 'required|min:3|max:32|alpha',
=> 'required|integer|min:16'
33
Validation
34
Great, now we have some rules. The array key is the field that is being validated upon, and the
array value contains a number of validation rules separate by a pipe | symbol.
In our case we are validating that both fields contain a value, by using the required rule. The
length of the users name must be a minimum of 3 characters (min:3) and a maximum length of 32
characters (max:32). The alpha rule will check to make sure that the name field only contains
letters.
Our age field must contain an integer and the value must be at least 16, you see that the min
rule has adapted to fit the content that its validating, very clever!
Dont worry, we will cover all the validation rules later, for now lets see the validation in action,
here we go.
1
<?php
2
3
$v = Validator::make($input, $rules);
We have made our validator object with the make() method, passing it our input array, and our
rules array. Lets see if it validates!
1
<?php
2
3
4
5
6
7
8
9
10
if( $v->fails() )
{
// code for validation failure :(
}
else
{
// code for validation success!
}
As you can see, we use the fails() method to check the result of the validation attempt, it will
return true if the validation has failed, and false if it was successful.
If you prefer a more positive outlook on your validations, you could use the passes() method,
which returns the opposite values..
1
<?php
2
3
4
5
6
7
8
9
10
if( $v->passes() )
{
// code for validation success!
}
else
{
// code for validation failure :(
}
There, now we are positive and can dance over rainbows with sparkleponies.
35
Validation
8.2 Errors
If your validation fails, which it will because our user is under 16 (sorry for slaying your
sparklepony), you will want to find out what went wrong. The validator provides an errors
Messages object which allows us to easily find the information we need.
The errors object has similar methods to the Input class, so I will not need to go over them all,
lets retrieve an array of errors for a specific field.
1
<?php
2
3
$age_errors = $v->errors->get('age');
Now we have an array containing all of the errors associated with the age field..
1
<?php
2
3
array(
'The age must be at least 16.'
4
5
Most of the time I find myself using the first() method in my views, which returns the first
array item if it exists, or null if it doesnt. For example..
1
2
3
Now our validation errors will appear for this field if any are present. You can also pass a second
parameter to the first() method to format the output..
1
2
Neat!
You can also use has() to check to see if an error exists, and all() to retrieve all errors as an
array.
Validation
36
Validation
37
The field value must be equal to yes or 1. Useful for validating checkboxes.
same:age
The field value must match the field specified by the same rule.
different:age
The field value must not match the field specified by the same rule.
match:/[a-z]+/
The field value must match the provided regular expression.
unique:users
This is one of my favorites, the validator will look at the users database table, and make sure
that the value is unique within the column that has the same name as the field name. Useful for
making sure that duplicate usernames or email addresses dont occur.
If you would like to specify an alternate column name, simply pass it as a second parameter..
1
unique:users,nickname
You can also force the rule to ignore a provided id by passing it as a third parameter.
1
unique:users,nickname,5
exists:colors
Acts as the opposite of unique, the value must already exist in the database table. Once more
you can pass a second parameter to refer to another column.
before:1984-12-12
The date provided by the field, must have occurred before the date template provided to the
before rule.
The before and after filters use strtotime() to calculate a timestamp for comparison, this means
you can do some neat tricks like..
1
before:next Thursday
Unfortunately I was on the one that added this functionality, so if it breaks you can go ahead
and shout at me sorry!
after:1984-12-12
Similar to before, only the date must occur after the date provided to the after rule.
email
The value must be a valid email address.
url
38
Validation
...
"after"
"alpha"
"alpha_dash"
dashes.",
...
Laravel replaces the :attribute marker with the name of the field. Other markers also exist
within the rules, and their purpose is quite self explanatory.
If you would rather change the messages for a single form, rather than edit them globally, you
can pass a third array of messages to the Validator::make() method.
1
<?php
2
3
4
5
6
$messages = array(
'same'
=> 'The :attribute and :other must match, fool!',
'size'
=> 'The :attribute must be exactly :size , like duh!'
);
7
8
Great now we have custom messages! We can even specify error messages for individual fields,
by setting the message key to field_rule, for example..
39
Validation
<?php
2
3
4
5
$messages = array(
'age_required'
);
<?php
2
3
4
5
6
Our newly created validation rule superdooper will ensure that our value matches the string
superdooper. Your custom validations should return true on success, or false on failure.
The $attribute value will be the name of the field being validated, and $value will of course
contain the value.
The $parameters attribute contains an array of parameters that have been passed to the rule
after the colon, and separated by commas.
As you have created a new validator, there will be no error messages associated with it yet, we
will need to add one so that Laravel knows what to say when it fails. We can add an error
message in the same way as we have previously..
1
<?php
2
3
Once again you can pass the extra error message array as a third parameter to the Validator::make() method, or simply add it to your application/language/en/validation.php file
for safe keeping.
Validation
40
<?php
2
3
// application/libraries/validator.php
4
5
7
8
9
10
11
12
As you can see our Validator class extends the Laravel\Validator namespaced core class and
provides additional validations in the form of validate_<rulename> methods. The validation
methods accept the same parameters as the Validator::register() closure, and work in the
same way.
In order to use our new validation class, we will need to remove the existing alias for Validator
from our application/config/application.php file. This way Laravel will use our created
class instead of the one in the Laravel source folder.
You could use this method to replace the original validation methods with your own, for example
you could create a validate_size method and calculate the size in an alternate format.
I would suggest adding custom error messages to the validation language file when using
Validation classes, this will allow for a much easier migration to another project, and will not
require any source-digging to find all the messages used.
In the next chapter, we will cover some typical form validation scenarios that are common to
web applications, this includes input forms, edit forms, form re-population and more.
9 Migrations
Originally I had attempted to include a guide to the Fluent Query Builder with this chapter,
but I now feel that the chapter has become too long, so I have decided to cover database setup
and migrations only in this chapter. Get ready for a nice long explanation of Fluent in the next
chapter.
Migrations are one of my favorite Laravel features, I hate writing SQL, and the Schema class
allows me to create my tables easily, without writing a single line of that foul language! Not
only that, the Schema code looks absolutely beautiful and reads like a book.
If you have not encountered migrations before, they are a way of describing changes to your
database in files, so that different installations / development copies of your application are aware
of the current schema. Changes to the schema can also be reverted or rolled back. Migrations
can also be used to populate tables with example data (also known as seeding).
<?php
2
3
4
5
6
7
8
9
10
11
=>
=>
=>
=>
=>
=>
=>
'mysql',
'localhost',
'codefun',
'root',
'pandaseatbamboo',
'utf8',
'',
There we go, now you will want to scroll up a little bit, and change the default array key to
reflect the database you are using. For me its already on mySQL.
1
<?php
2
3
Now we have our database configures, we need some tables to play with. Onwards to migrations!
41
42
Migrations
9.2 Migrations
Lets get started by creating a migration file.
We are going to use Laravels command line interface artisan to create our new migration. To
run Artisan you will need to have PHP CLI installed (normally this will be installed along side
your web-server). You will also need to open a terminal to the root of your Laravel package
where the artisan file exists. Right, lets type our first artisan command :
1
We are telling artisan, to run the make method on the migrate task, we pass a name for our
migration to identify it by, I like to name it after the action being performed, in this case we are
creating the users table.
Lets have a look at the result.
1
Enthusiastic! If we take a look in our application/migrations folder, we see a new file named
2012_03_30_220459_create_users.php, well yours might not be called that! You see artisan
takes the current date, and adds the time in His format to create the file name. The reason for
this is that dates are very important to migrations (and single people), the system needs to be
able to know in which order to apply the changes.
Lets open up the file and take a look at the migration class.
1
<?php
2
3
class Create_Users {
4
5
6
7
8
9
10
11
12
13
/**
* Make changes to the database.
*
* @return void
*/
public function up()
{
//
}
14
15
16
17
18
19
/**
* Revert the changes to the database.
*
* @return void
*/
43
Migrations
20
21
22
23
24
25
As you can see, our migration class consists of two methods, up() is responsible for making all
of your database changes, where down() accomplishes the exact reverse, this way a migration
can be performed, and rolled back when necessary. If you were to create a table within the up()
method, we would DROP the same table in the down() method.
So how do we perform changes on our database, no doubt with some complex ugly SQL query
right? Haha, no. We are using Laravel, if its ugly, its not in the framework. Lets have a look at
creating a table with the Laravel Schema class.
1
<?php
2
3
4
5
Schema::create('users', function($table) {
// auto incremental id (PK)
$table->increments('id');
// varchar 32
$table->string('username', 32);
$table->string('email', 320);
$table->string('password', 64);
7
8
9
10
11
// int
$table->integer('role');
12
13
14
// boolean
$table->boolean('active');
15
16
17
18
19
20
});
We call the create() method on the Schema class to create a new table, as parameters we pass
the name of the table to be created, and a closure as the second parameter. We also need to pass
a parameter to the closure, you can call it whatever you like, but I like using $table because I
think it makes the code read better.
Inside the closure, we can use the $table parameter to create our fields with a number of handy,
well-named methods, lets take a quick look at them.
increments()
Add an auto-incrementing ID to the table, most of your tables will have this!
Migrations
44
string()
Create a VARCHAR field, string sounds a lot better doesnt it?
integer()
Add an integer field to the table.
float()
Add a float field to the table.
boolean()
Add a boolean field to the table.
date()
Add a date field to the table.
timestamp()
Add a timestamp field to the table.
timestamps()
Add created_at updated_at timestamp fields.
text()
Add a text field to the table.
blob()
Add a blob data field to the table.
You can also use the chainable method ->nullable() to allow the field to receive NULL values.
Full details on the parameters available to the above methods can be found in the official
documentation.
Great, so now we have created our table! Since we created the table in the up() method, we
now need to DROP the table in the down() method, so that the schema would return to its original
form after a rollback. Fortunately the Schema class has another method that is perfect for this
task.
1
<?php
2
3
Schema::drop('users');
Yep, it doesnt get easier than that. The Schema class also has functions for performing other
schema tasks, such as dropping columns drop_column(), adding indexes unique() and a number
of foreign key methods. I think that covering all of them here would turn the book into an API,
something I dont wish to do, besides they are explained well in the official documentation, and
if you take a look there we can move on to new things, how about finding out how we run these
migrations? Lets do it!
http://laravel.com/docs/database/migrations
http://laravel.com/docs/database/schema
Migrations
45
Before we can run our migrations, we need to install the laravel_migrations table, so that
Laravel can keep track of which migrations have been run. Fortunately artisan has a command
which will perform the necessary database changes for you, lets have a go.
1
Great! Now the laravel_migrations table has been created, we can finally run our new
migration. Simply use the task name this time, here we go.
1
2
Woop, if we take a look at our database the users table has been created successfully. Wait, we
made a mistake! (we didnt, but I like drama and I need an excuse to use rollback) Lets rollback
our schema to redo the changes.
1
2
Please note that if you would like to provide example data to populate your database with, simply
create it with the Fluent Query Builder, however a guide on this topic will not appear until the
next chapter, so you might want to wait a day or so!
Easy as pie! Now you know how to use migrations, you can build your schema and populate
your database whenever you please! Next chapter we will be looking at the Fluent Query Builder.
And now, as promised, a list of names / messages from those who have purchased the book for
more than $9.99.
Please dont forget to talk about the IoC container and how this can be useful with
unit tests. You made a great choice with Laravel. - Jorge Martinez
Thanks for buying the book Jorge, we will be covering the IoC container in a later section, once
we have covered all the basics of app building.
We at @HelpSpot really support what youre doing to expand the Laravel community, keep up the great work! - Ian Landsman
Thanks Ian! We the Laravel community really support what youre doing to expand the
Framework, so now we are even! For those of you who do not know, Ian Landsman is the
head of UserScape, a company which provided the frameworks author with a job that lets him
expand the framework. UserScape also sponsor the bundle site for Laravel, and many other
things! Please check out their product Helpspot, a wonderfully flexible and affordable piece of
help desk software!
http://www.helpspot.com/
Migrations
46
There were some other purchases over $9.99 that I have not received an email from yet, remember
if you pay more than $9.99 and you would like your name to appear in the book, please send an
email to [email protected] , unfortunately I cant see the names of those who purchased on the
sales tab.
<?php
2
3
Class::make()->chain()->chain()->chain()->trigger();
This is a very useful way of stringing options together, and is a lovely way of expressing SQL (as
you will see later). The class is instantiated with the make() method, sometimes you will also
pass startup parameters to the class this way. The chain() methods are used to modify the
request with different options, and the trigger() method is used to bring back the final result.
This might sound a bit confusing, but lets take a look at an example from fluent.
1
<?php
2
3
and bring back an array of objects, representing database rows that are the result of the query.
The table() method is instantiating the object, and setting the table that we intend to work
with. The where() is a chain method that applies a WHERE clause to our query, and get() is
the final trigger method that retrieves all objects that are the result of the query.
The get() trigger will bring back an array of results, so lets start by looping the result set with
a foreach.
1
<?php
2
3
4
5
6
As you can see in the above example, fields for the row are accessed using the attributes of the
result object, the loop above would output the email addresses for all of our users.
47
48
<?php
2
3
Here we have the same snippet again, but we are concentrating on the where() part of the chain
:
1
<?php
2
3
The great thing about how Laravel handles the where clause, is that the chain looks a little bit like
the SQL being generated. In the chain method above we are saying WHERE username = 'dayle',
the first parameter to the method states the field which we are comparing, the second parameter
states the operator to use for the comparison, and the third parameter is the value which we are
comparing with. We could also use :
49
<?php
2
3
4
5
What if we want more conditions? Well first we need to decide, if we need AND WHERE, or
OR WHERE, to include an AND where clause, simply use the where() method again in the
chain, for example :
1
<?php
2
3
4
5
6
$users = DB::table('users')
->where('username', '=', 'dayle')
->where('sexyness', '>', 5000)
->get();
As you can see in the above example, I have put each chain method on a new line, I find this
is easier to read, and avoids having terribly long lines of code. This chain will perform the
following SQL :
1
SELECT * FROM users WHERE username = 'dayle' AND sexyness > 5000;
If we would prefer to use an OR where condition we simply use the or_where() method, which
accepts the same parameters, for example :
1
<?php
2
3
4
5
6
$users = DB::table('users')
->where('username', '=', 'dayle')
->or_where('face', 'LIKE', '%malemodel%')
->get();
which gives us :
1
Now I dont need to explain how every feature of SQL works, there are plenty of other books for
that, but I will name the methods used to accomplish common tasks instead.
Use the where_in(), where_not_in(), or_where_in() and or_where_not_in() methods to
match a field to one of an array of items.
The where_null(), where_not_null(), or_where_null(), and or_where_not_null() methods
to match a field to a NULL value.
Sometimes you will want to nest where clauses together, Laravel provides functionality for this
in the form of Nested Where Clauses, lets take a look at a code example from the official docs.
50
<?php
2
3
4
5
6
7
8
9
10
$users = DB::table('users')
->where('id', '=', 1)
->or_where(function($query)
{
$query->where('age', '>', 25);
$query->where('votes' '>', 100);
})
->get();
By passing a closure containing extra where clauses to another where method, we can create
nested where clauses, the result can be seen in the SQL:
1
SELECT * FROM "users" WHERE "id" = ? OR ("age" > ? AND "votes" > ?)
neat huh?
And now for a more interesting feature! (I told you about how I loathe SQL right?) Dynamic
where clauses give you a really funky way of defining simple where clauses. Check this out..
1
<?php
2
3
where_size(5)-get();
Here we are specifying the field to compare in the method name, Fluent is so clever that it will
deal with it, no problem!
It will even understand AND and OR, check this out!
1
<?php
2
3
where_size_and_height(700, 400)->get();
<?php
2
3
4
5
DB::table('tasks')
->join('project', 'tasks.id', '=', 'project.task_id')
->get(array('task.name', 'project.name'));
51
We pass the name of the join table as the first parameter, and use the remaining three parameters
to perform an ON clause, similar to how we perform WHEREs.
We then pass the fields we want to return to the get() method as an array.
We can do a left_join() exactly the same way, in fact it takes the same parameters, easy huh?
Do you remember the nested where clauses? Well you can use a similar technique to add more
conditions to the ON clause of a join, lets take a looksy.
1
<?php
2
3
4
5
6
7
8
DB::table('tasks')
->join('project', function($join) {
$join->on('tasks.id', '=', 'project.task_id');
$join->or_on('tasks.author_id', '=', 'project.author_id');
})
->get(array('task.name', 'project.name'));
In this case, we pass a closure as the second parameter to the join() method, then use the on(),
or_on() and and_on() methods to set the conditions.
10.4 Ordering
Ordering is pretty important, you dont wanna waste resources doing that with PHP, you could
sure lots of nasty array_sort()ing, tons of loops, that wouldnt be any fun. Lets pass this
responsibility to fluent.
1
<?php
2
3
DB::table('shoes')->order_by('size', 'asc')->get();
Hmm shoes? Women are meant to think about shoes but thats all that came to mind.. Scarey.
Anyway its as easy as passing a field name, and either asc for acending, or desc for descending.
To sort on more columns, simply repeat the order_by() chain.
<?php
2
3
DB::table('shoes')->take(10)->get();
Now I want 10 shoes? I should be more worried.. But its clear, limiting is very simple!
52
<?php
2
3
DB::table('shoes')->skip(5)->get();
The we go, now we can skip() the first 5 results, easy as pie!
10.7 Aggregates
Sometimes its handy to run basic maths on queries, AVG, MIN, MAX, SUM, and COUNT are
used all the time to quickly get the result we want with SQL, and they are all available with the
Fluent Query Builder, lets take a look.
1
<?php
2
3
4
5
6
7
$val
$val
$val
$val
$val
=
=
=
=
=
DB::table('shoes')->avg('size');
DB::table('shoes')->min('size');
DB::table('shoes')->max('size');
DB::table('shoes')->sum('size');
DB::table('shoes')->count();
Simple! Dont forget that these are trigger methods, we dont need to add get() here. You are
also welcome to add conditions with where() or whatever you like!
10.8 Expressions
The methods we have been using so far escape and quote the parameters you provide automatically, but what if we need something really custom, what if we dont want anything else added?
For this we can use the DB::raw() method, heres an example :
1
<?php
2
3
In this query the NOW() will not be escaped or quotes, lots of freedom there, but dont forget that
spiderman quote, be responsible with this power.
53
<?php
2
3
4
DB::table('shoes')->increment('size');
DB::table('shoes')->decrement('size');
10.10 Insert
Finally, lets store some data. All this time we have been looking at reading data, this will be more
fun! Well its quite simple really, to insert a new row all we have to do is provide a key-value
array to the insert() method, which is a trigger method by the way!
1
<?php
2
3
4
5
6
7
DB::table('shoes')->insert(array(
'color'
=> 'hot pink',
'type'
=> 'heels',
'size'
=> '12'
));
Wait, lets grab the id thats created with this new row, it might be handy later? We can use
insert_get_id() with the same params for this.
1
<?php
2
3
4
5
6
7
$id = DB::table('shoes')->insert_get_id(array(
'color'
=> 'hot pink',
'type'
=> 'heels',
'size'
=> '12'
));
Thats my weekend pair, lets keep this between us we now have a nice hot pink pair of heels,
in size 12 in the shoes table of our database.
54
10.11 Update
Wait, did I say heels in that last section? They were hot pink skate shoes, if only we could go
back and fix our mistake, I could update the table and no one would see my shame. Oh we could
probably use the update() method, you see it takes an array with the same syntax as insert().
1
<?php
2
3
4
5
DB::table('shoes')->update(array(
'type'
=> 'skate shoes'
));
Hold on, we arent specifying a record here, I dont want to change all my records to skate shoes,
it would ruin my wonderful Laravel flip flops. Lets use a where() method and that $id we got
to narrow it down to the record we want. Chain time!
1
<?php
2
3
4
5
6
7
DB::table('shoes')
->where('id', '=', $id)
->update(array(
'type'
=> 'skate shoes'
));
10.12 Delete
To delete a row (please, not the shoes, they are innocent!) we can use the delete() method with
a where() clause, or simply pass it an id directly to delete a single row, lets see these methods
in action.
1
<?php
2
3
<?php
2
3
DB::table('shoes')->delete($id);
55
NO! Not the hot pink skate shoes, you have obviously learned too much, please keep the
responsibility and power thing in mind.. we dont want any more shoe massacres.
In the next chapter, we will be moving on from sho Fluent, and taking a look at Eloquent.
Eloquent allows us to treat our database rows as objects, and provides an elegant.. or eloquent
solution to handling relationships.
I would like to thank Max Schwanekamp for purchasing the book, and also Douglas Grubba who
had the following to say:
Keep up the great work Dayle! A wonderful resource. Thank you to the @laravel
team. @taylorotwell you are really changing the php world.
Thanks Doug! Im sure Taylor will also be pleased to hear that he is changing the PHP world,
one method at a time!
11 Eloquent ORM
An ORM is a really useful package, it stands for Object Relational Mapper, sounds pretty
complicated right? Lets break it down a little, (add bass beat) the mapper part, is because we
are mapping our PHP objects, or classes to database tables and rows. The Relational part will
become clear in the relationships section.
There are many ORM solutions out there, but none as Eloquent as well Eloquent. Eloquent
ships with Laravel, and can be used out of the box. For this portion I am going to assume you
set up your database, as described in the Migrations chapter, and that you are familiar with the
methods and chaining from the Fluent Query Builder chapter, we are going to build on these.
You see Eloquent is an alternative to using Fluent, but it shares many of the same methods, the
only difference is we are going to be interacting with Eloquent models are results, rather than
the stdObject we get back from Fluent, its going to make our code look even clearer. Lets dive
right in and checkout the Eloquent model.
<?php
2
3
4
5
6
Actually thats it.. no really, I am serious. You see, Eloquent trusts you, it knows that you have
already created a nice migration for the users table. It doesnt need you to tell it about the
fields that exist, its going to trust that you know them, you should, you wrote the migration and
made the table. Oh by the way, you did put an increments('id') in your table right? This is a
common practice, and Eloquent needs this to work.
Another thing you might have noticed about the model is that the class is called User and the
table is called users, this isnt a typo. Eloquent is so clever, that it can detect the plurals for the
English language. Our object is singular, so we define it as a User, but our database table users
will contain any number of users, so Laravel knows to look for a table with a plural of the object
name.
You may have picked up on the fact that it only detects plurals for the English language, what if
you use another language, or a certain plural doesnt work for you? Simply add the word, and
its plural version to the array in the application/config/strings.php file, now it will work as
expected!
Maybe you dont like having the table name as plural form? Not a problem, simply use the static
$table class attribute to specify another table name, for example..
1
<?php
56
Eloquent ORM
3
4
5
6
57
Right, typing that huge model definition must have worn you out (please note the sarcasm), lets
have a go at using our new model.
1
<?php
2
3
$user = User::find(1);
Wait hold on we have seen this before, do you remember find() from our Fluent chapter, it
brings back a single result by its primary key. You see Eloquent uses many of the methods used
by Fluent, this is really convenient because you can use a combination of both Database libraries
without forgetting which method is for what. Sweet!
For eloquent, simply use the objects name, and supply a static method, we dont need to use
DB::table() for this one.
You can use the result object in a similar way, the truth is you are now interacting with an
Eloquent object, but you couldnt really tell the difference at this point, lets get that users name.
1
<?php
2
3
echo $user->name;
<?php
2
3
$user = $user->to_array();
If you want to exclude certain fields from this array, you can add a $hidden static attribute to
your Eloquent model, containing an array of all the fields to exclude, for example :
1
<?php
2
3
4
5
6
Eloquent ORM
58
Say we want multiple results back? We can use the fancy all() method to bring back every
user, then we can have a sexy user party.
1
<?php
2
3
$users = User::all();
What we have now, is an array of user objects, we can loop through them to access each one
individually, simple as that.
1
<?php
2
3
4
5
6
Nice, its really swinging in here, quite a few guys though.. well lets increase our chances, and
get rid of the other guys. Then it really will be a sexy party!
1
<?php
2
3
Wahey, lots better! The eye-candy threshold went up significantly. You see we just used a
where() chain method, and get() just like we did with fluent, nothing new there, just increased
clarity.
I could cover all the query methods again for returning results, but I dont really need to, simply
flick back a chapter, and mentally replace the word Fluent with Eloquent, you will get the idea.
Instead, lets see what has changed. Creating and updating objects (rows) just got a whole lot
better!
1
<?php
2
3
4
5
6
7
8
$user->save();
Best not to invite Captain Sexypants to our party, we wont get any action with him around,
even his parrot has swagger.
Eloquent ORM
59
You see we simply create a new User object, set class attributes for the fields that exist (we dont
need to set the ID, Eloquent handles that) and save() the object, to write our changes to the
database. This is commonly known as the Active Record design pattern, its a really nice way
of interacting with our rows, by treating them the same as any other object in our application.
Its like the database and all that nasty SQL doesnt even exist!
If we already have a key-value array describing our friend Captain Sexypants then we can
either pass it as a constructor parameter to the new object, or use the mass-assignment method
fill() to add him to the database, check this out..
1
<?php
2
3
4
5
6
7
8
$user->save();
or
1
<?php
2
3
4
5
6
$arr = array(
'name' => 'Captain Sexypants',
'mojo' => '100%'
);
7
8
9
10
Please be careful not to let any extra information slip through when using mass-assignment, as
it could result in a potential security risk.
So what about updating a row? Its very similar, except we need to query for the user we want
to change first, lets see..
1
<?php
2
3
Here we use first() because we want to make sure we only get one object back, we cant change
the values on an array, we would have to loop through each one, and that would make a longer
example than we need!
Eloquent ORM
60
<?php
2
3
4
$user->mojo = '5%';
$user->save();
Well I couldnt take all his mojo, that wouldnt be fair. At least he can come to the party now.
So you see updating is performed exactly the same way as inserting, except we need to find the
object that we want to update first.
Do you remember using $table->timestamps() with in the migrations chapter to make
updated_at and created_at fields? Eloquent will update these automatically for you, inserting
a timestamp when an object is created, and updating the updated_at field every time you save, if
you would like to disable this feature simply add the $timestamps class attribute to your model
and set it to false.
1
<?php
2
3
4
5
6
11.2 Relationships
Relationships are beautiful. No I havent gone all soppy. I mean relationships between tables, in
Eloquent they are beautiful. None of that JOIN rubbish, we can define one-to-one, one-tomany and many-to-many just by adding some simple methods to our Eloquent Models, lets
jump right in, you will learn more with a code snippet in front of you.
On To One
Jumping right in..
1
<?php
2
3
4
5
6
7
8
9
Eloquent ORM
61
Lets go ahead and assume that we have made an invites table and an Invite model to contain
our sexy party invites.
Now we can retrieve a users (or party guest) invite with a clear expressive syntax, lets take a
peek:
1
<?php
2
3
$invite = User::find(1)->invite()->first();
Again we are using first() because we only want one result. You see by adding ->invite()->
to the chain, which is of course our relationship method name, we retrieve the Invite object
that is related to our user.
This relationship will execute two queries :
1
2
From the query, you will see that Eloquent is looking for user_id automatically as the foreign
key, so if we want to use this relationship, we will need to create a user_id integer field with
our migration, in the Invites table. What if we want to call our foreign key something else?
No problem, we simply pass a second parameter to the has_one() method (or other relationship
methods) to specify the new field name, for example.
1
<?php
2
3
4
5
6
7
8
9
but what about the inverse of this relationship, what if we have an Invite, but we want to know
who it belongs to, this is where the belongs_to() method comes in handy. Lets take a look at
the model.
1
<?php
2
3
4
5
6
7
8
9
Eloquent ORM
62
A similar syntax, but using belongs_to() instead, to point out that the foreign key, exists in this
table.
Now we can use..
1
<?php
2
3
$user = Invite::find(1)->user()->first();
Easy!
One To Many
What if we want to return many related items? Well as you may have guessed from the header,
theres a method for that. Lets take a look. ( I say that a lot dont I? Maybe it can be my
catchphrase. )
1
<?php
2
3
4
5
6
7
8
9
Again, you see that we are passing the object name in string format, with capitalization to the
has_many() method.
In this example, the hats table will need a user_id foreign key, and then we can use..
1
<?php
2
3
$hats = User::find(1)->hats()->get();
Note that we could also use a dynamic property with the same name, to retrieve the same results
with a shorter syntax, for example :
1
<?php
2
3
$hats = User::find(1)->hats;
Nicer still!
As before, you can pass another foreign key as a second parameter to use that instead, lets move
on!
Eloquent ORM
63
Many To Many
Here things get a little more complicated, but dont worry.. I am here to get you through this,
take my hand Wendy, lets imagine that we have two Eloquent models, User and Task, a user
may have many tasks, and a task may have many users, for this type of relation ship we will
need a third table.
This table is known by many names, a Pivot Table, a Lookup Table, an Intermediate table, or El
Pivote Grande.
Its simply a table with two integer fields user_id and task_id that links the two tables together,
forming a many-to-many relationships.
The table is named after both related tables in a plural form, in an alphabetical order, sounds
complicated but it looks simple, check it out:
tasks_users
<?php
2
3
4
5
6
7
8
9
<?php
2
3
4
5
$hat = Hat::find(1);
$user = User::find(1);
$user->hats()->insert($hat);
That looks a lot better, its like handing objects to each other, much cleaner than dealing with
those integer foreign keys directly.
64
Eloquent ORM
With has_many() relationships, you can pass an array of field-value pairs to the save() method
to insert or updated related models. For example:
1
<?php
2
3
4
5
6
$hat = array(
'name'
'style'
);
=> 'Dennis',
=> 'Fedora'
7
8
$user = User::find(1);
9
10
$user->hats()->save($hat);
Clean :)
When we are creating a new related item with a many-to-many relationship, if we use the
insert() method, Eloquent will not only create the new object, but also update the pivot table
with the new entry, for example :
1
<?php
2
3
4
5
6
$hat = array(
'name'
'style'
);
=> 'Dennis',
=> 'Fedora'
7
8
$user = User::find(1);
9
10
$user->hats()->insert($hat);
But what if the objects already exist, and we just want to create the relationship between them?
We can do this easily with the attach() by passing the $id (or the object) of the object to be
related, lets see the code.
1
<?php
2
3
$user->hats()->attach($hat_id);
<?php
2
3
$user->hats()->sync(array(4, 7, 8));
Eloquent ORM
65
<?php
2
3
$pivot = $user->hats()->pivot();
Now we have an array of result objects, just like any other query, but for those which relate the
users hats.
What if we want to retrieve the exact row that has been used to relate an object? Easy with the
pivot dynamic attribute, the official docs has a great example of this, and I am going to steal
it because I am a nasty person. Dont worry, I will make it look a bit different, kinda like with
your high school assignments?
1
<?php
2
3
$user = User::find(1);
4
5
6
7
8
Now we can access the created_at field on the pivot table row, to see when our hat was made.
Ok, Im getting pretty sick of hats, in fact I want to delete my hats, every last one of them.
Fortunately I know my user id, its number 7, lucky number 7. Lets do it right now, lets delete()
all of my hats.
1
<?php
2
3
User::find(7)->hats()->delete();
There done, cold head from now on, but its worth it now you know how to use the delete()
method.
Eloquent ORM
66
<?php
2
3
$users = User::all();
4
5
6
7
8
For every loop iteration, Eloquent has to perform another SQL query, to retrieve that users Hat
object, and find its size. Now this isnt going to be a huge problem on small data sets, but
with hundreds of rows it could drastically affect performance. With eager loading we can tell
Eloquent to run a SELECT * FROM hats; when retrieving the User object, so that we already
have all the data we need. That reduces the amount of strain to only two SQL queries. Much
better!
Lets see how we can tell Eloquent to eager load a relation:
1
<?php
2
3
$users = User::with('hat')->get();
There, now the hat relationship is eager loaded. If you want to eager load several relationships,
simply pass an array to the with() method. Its worth noting that the with() method is static,
and as such must always be at the start of the chain.
You can even eager load nested relationships, lets assume our Hat object has a hatstand()
relationship to let us know which stand its on, we can eager load both of the relationships
like this.
1
<?php
2
3
<?php
2
3
4
5
Eloquent ORM
67
<?php
2
3
4
5
6
We create a method with the name of the setter, prefixed with set_, pass it a variable which will
receive the field value. Now we can use set_attribute() to set a field to its new value, this lets
us modify the passed value anyway we like. The snippet above will cause the hashed_password
field to be updated with a hashed version of the supplied value when we call :
1
<?php
2
3
$user->password = "secret_panda_ninja";
Very useful!
Getters are the exact opposite, they can be used to adjust a value when it is being read, for
example :
1
<?php
2
3
4
5
6
<?php
2
3
echo $user->panda_name;
12 Events
Events are a way of letting other pieces of code, extend your applications in a neat way. Some
other applications refer to this type of extension as a Hook. If you are a PHP Guru you might
see some resemblances to the Observer / Observable design pattern.
Events may have any number of listeners, and firing them can return a varied number of
responses. I think the best way to learn will be to see this in action, lets take a closer look
at Events in Laravel.
<?php
2
3
$responses = Event::fire('dinner.time');
In this example, we trigger or fire the event dinner.time which alerts all of the listeners of
the event, that it is time to get your grub on. The $responses variable will contain an array of
responses that the listeners of the event will provide, more on that later.
We can also retrieve the first response from an event, rather than all of them. We simply call the
first() method instead of fire(), now we receive a single result like this.
1
<?php
2
3
$response = Event::first('dinner.time');
Its worth noting, that although we are only receiving one response, all of the events listeners will
be informed, so the event will be fired just as it was using the fire() method, but all responses
apart from the first, will be ignored.
The third option for firing an event is the until() method, this method will fire the event,
notifying each listener until the first response that is a NON-NULL value is returned. The
NON-NULL value is then passed to the $response variable.
1
<?php
2
3
$response = Event::until('dinner.time');
Well now that we know how to fire an event, lets have a look at the other end of the spectrum,
we need to know how to register ourselves as a listener. We dont want to miss our dinner!
68
Events
69
<?php
2
3
4
5
Event::listen('dinner.time', function() {
return 'thanks for the grub!';
});
If we now call $val = Event::first('dinner.time'); the value of $val will be thanks for
the grub!. Simple as that.
<?php
2
3
We can then add parameters to the closure in our listener to catch these values, like so :
1
<?php
2
3
4
5
70
Events
<?php
2
3
<?php
2
3
<?php
2
3
Event::listen('laravel.done', function($response){});
<?php
2
3
Event::listen('404', function(){});
<?php
2
3
4
5
6
7
Event::fire('myapp.new_user', array($u->id));
Events
71
As you can see, we pass the new users id value to the myapp.new_user event, so that all event
listeners are aware of which user has been created.
Now lets create an extension to our application, the extension should not interfere with the
existing code of the application, it could be an extra library, or a bundle (coming soon), anything
outside of the main application.
In our extension, we are going to add a prefix to the users name (this is somehow useful to our
extension). Lets do this by listening to the user event.
1
<?php
2
3
4
5
6
7
We create a listener, that receives the user id. Using this we can retrieve the new user from the
database, and apply the changes.
Now we have added some extra functionality to the application, without editing its core files. It
is the responsibility of the applications author, to insert Event triggers or fire() methods, within
areas of the application that are likely to be extended. Without these events, the applications
source would have to be modified.
13 Blade Templates
Laravels Blade templating engine, allows you to use very neat looking syntax to embed PHP
code within your views. It also includes a number of shortcuts that allow a cleaner use of existing
Laravel features. Blades templates are also cached by default, which makes them extremely fast!
As always, lets jump right in.
<?=$val?>
.. however there is still room for improvement. Lets have a look at how Blade would handle the
same echo statement.
1
{{ $val }}
Neat! The spacing between the brackets is optional, but I think it looks better with it there. You
see the contents of the double curly brackets is evaluated, and echoed out. You can use any PHP
you want in there, for example..
1
{{ 5 * time() }}
This snippet will work just as well. You see all Blade is doing, is converting {{ $val }} to <?php
echo $val; ?>. Be sure to consider this if you run into any problems with blade!
13.2 Logic
What about foreach() loops, I use loads of them! I use a lot of if and else too, blade simplifies
all of these conditional statements through the use of the magical @ sign, lets take a look.
72
Blade Templates
73
<?php
2
3
4
5
There, not only cleaner looking than all of those ugly PHP tags, but a lot quicker to write! What
about ifs and elseifs? Well if you are used to PHP alternate syntax, you will be able to guess
the result. Simply replace the <?php with @ and skip the : ?> all together! What we have left
is..
1
2
3
4
5
Very simple, here are the other operators you can use with Blade, they should look familiar :
1
<?php
2
3
4
5
and
1
<?php
2
3
4
5
6
7
That last one is a little special, its a foreach() loop, but with an extra @empty which will output
the result below if the supplied array is empty. Very handy, as this avoids adding an extra if
statement.
Blade Templates
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
74
<!DOCTYPE HTML>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<title>@yield('title')</title>
</head>
<body>
<div class="header">
<ul>
@section('navigation')
<li><a href="#">Home</a></li>
<li><a href="#">Blog</a></li>
@yield_section
</ul>
</div>
16
@yield('content')
17
18
19
20
</body>
</html>
Our main template uses the @yield() method to define a content region, that can be filled by
a view that uses this layout. Simply pass a string to the method to provide a nickname for that
content region, that will be used to identify it later.
The @section() and @yield_section define a content region, that contains some default data,
but can be replaced at a later date. Lets have a look at a view (page.blade.php) that makes use
of the template we have just created.
1
@layout('template')
2
3
4
5
@section('title')
Dayle's Webpage!
@endsection
6
7
8
9
10
@section('navigation')
@parent
<li><a href="#">About</a></li>
@endsection
11
12
13
14
15
@section('content')
<h1>Welcome!</h1>
<p>Welcome to Dayle's web page!</p>
@endsection
In this view we use the @layout() method to specify that we want to use a view named template
as our layout. Now we can use @section() and @endsection to replace yielded content regions,
with the code found between these two methods.
Blade Templates
75
In the case of the navigation section, you will notice that we have a @parent stub inside the
content area, Blade will replace this, with the content from the base template.
If we return..
1
return View::make('page');
From our route/action we can now see our page, wrapped within the layout template, like so..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE HTML>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<title>Dayle's Webpage!</title>
</head>
<body>
<div class="header">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">About</a></li>
</ul>
</div>
15
<h1>Welcome!</h1>
<p>Welcome to Dayle's web page!</p>
16
17
18
19
20
</body>
</html>
Great! We can also use as many templates as we want to, they are simply normal Blade views!
What if we want to provide the @section contents from our Action/Route? Simply call the
Section::inject() method with the section name, and a string representing the sections
contents, for it to be injected into the view.
1
2
3
return View::make('page');
5
6
}));
and thats all! Now you can use Blade to make your views look clean and efficient, your designer
will love you for it.
14 Authentication
Many applications will want a layer of Authentication. If you are writing a blog, you dont want
your readers to be able to post new topics, or if youre working with some sensitive data, you
dont want unauthorized users accessing it.
Fortunately Laravel has a simple, secure, and highly customizable Authentication class, lets take
a look at how we can interact with it.
14.1 Setup
Before we begin you are going to need to create a new table to store our user details, we can name
this table whatever we like, but if we name it users we wont have to change the Authentications
configuration file. Heres how to create a suitable table with the Schema Builder.
1
<?php
2
3
4
5
6
7
Schema::create('users', function($table) {
$table->increments('id');
$table->string('username', 128);
$table->string('password', 64);
});
You can add as many additional fields as you like, but this will get us going. Lets also create a
sample user that we can use to test the authentication process. First I should explain how the
Hash class works.
You can use the Hash class to hash a password using the highly secure bcrypt algorithm, its very
simple to use, here is an example.
1
<?php
2
3
$pass = Hash::make('my_password_string');
In the above snippet we create a bcrypt hash out of our password. By storing the hash in the
database instead of the plain text password, it offers our users some extra security. You will find
this is common practice with web applications.
If you would like to compare a hashed password with a value, simply use the check() method,
for example..
1
<?php
2
3
Hash::check('my_pass', $pass);
76
Authentication
77
This will return a boolean result, true on successful match, and false on failure. Now that we
know how to hash a password, we can create our sample user, I am going to call him Dexter,
you see I am watching the TV show Dexter while writing this chapter, its great to write with
background noise, try it with coding, it really works! Onwards to Dexter..
1
<?php
2
3
4
5
6
DB::table('users')->insert(array(
'username'
=> 'Dexter',
'password'
=> Hash::make('knife')
));
Now we must choose which of the default authentication drivers we wish to use, we have the
choice of eloquent or fluent.
The fluent driver will use Fluent to interact with the database, and return an object representing
the the user tables row when we call Auth::user(). The eloquent driver will return an Eloquent
model representing the user instead.
Configuration for authentication driver, table or object name, and field names can all be found
within application/config/auth.php.
1
<?php
2
3
return array(
5
6
7
8
9
10
11
12
);
Lets change driver to fluent to use the fluent query builder as the authentication driver, and
change the username config item to username so that we can log our users into our application
using their username rather than an email address.
1
<?php
2
3
return array(
4
5
6
7
Authentication
78
9
10
11
12
);
{{ Form::open('login') }}
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{{ Form::close() }}
That is a beautif..
Ssssh, that was a few chapters ago now, Im not into brain washing, you can let it go. Sure is a
beautiful form though! Lets create a nice route to show the form.
1
<?php
2
3
4
5
Route::get('login', function() {
return View::make('login');
});
Lets make a POST variant of this route, we can use that to handle when the login form is
submitted, that way we can use a single URL for both.
79
Authentication
<?php
2
3
4
5
Route::post('login', function() {
return 'login form sent';
});
Right lets make sure our routes work fine, actually I am pretty sure they will, but this is just a
habit of mine. If we visit http://localhost/login and enter some phony data, submit the form,
we should get login form sent.
<?php
2
3
Route::post('login', function() {
5
6
7
8
9
=> Input::get('username'),
=> Input::get('password')
10
11
});
Sweet! We have post data, lets put it to use. We will use the Auth::attempt() method to check
if the username and password can be used to login. The great thing about this method, is on
success it will automatically create our logged-in session for us! Mucho conveniento! (I never
took Spanish, sorry.).
1
<?php
2
3
Route::post('login', function() {
4
5
6
80
Authentication
'username'
'password'
7
8
=> Input::get('username'),
=> Input::get('password')
);
9
10
if ( Auth::attempt($userdata) )
{
// we are now logged in, go to home
return Redirect::to('home');
}
else
{
// auth failure! lets go back to the login
return Redirect::to('login')
->with('login_errors', true);
// pass any error notification you want
// i like to do it this way :)
}
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
});
Now if our authentication is successful, the login session is created, and we are redirected to
the home route. Perfect, but before we go any further, lets create a logout route so that we can
logout to perform future testing.
1
<?php
Route::get(logout, function() {
Auth::logout();
return Redirect::to('login');
1
2
3
});
Here we use the Auth::logout() method to destroy the login session, and head back to the login
page. We are now logged out.
Right, now that we have our login working perfectly lets create our super secret home page, add
a logout link, and welcome our currently logged in user.
1
<?php
2
3
4
5
6
7
Route::get('home', function() {
return View::make('home');
});
Authentication
81
8
9
10
11
12
13
14
<div class="header">
Welcome back, {{ Auth::user()->username }}!<br />
{{ HTML::link('logout', 'Logout') }}
</div>
15
16
17
18
19
20
<div class="content">
<h1>Squirrel Info</h1>
<p>This is our super red squirrel information page.</p>
<p>Be careful, the grey squirrels are watching.</p>
</div>
Now you can test our login loop.. Login, be greeted with the welcome page, logout. Repeat. Do
this at least 800 times to set your mind to rest. Dont worry, this is normal behavior, besides..
you get paid by the hour right PHP Guru?
You will notice that we use Auth::user() in the above example, this will return a Fluent database
result object representing the current logged in user. Very handy for finding its id, or echoing
out welcome information.
<?php
2
3
4
Route::filter('auth', function()
{
Authentication
5
6
82
});
Neat!
You see the Auth::guest() method? Its a nicely expressive method which returns true only
if the current request has no logged in user. Very handy! You can also use Auth::check() to
perform the opposite check, to see if a user is currently logged in. We know these methods do
exactly the same thing, but by providing clean expressive method names, using the right one
will appear much clearer within your source.
As you can see, if no user is logged in, the auth filter returns a redirect to the login page,
overwriting the view supplied by our route. All we need to do is attach this to our home route.
1
<?php
2
3
4
5
There we go, now the home route is protected, the undefined notices will never be seen, and
unauthorized squirr users will no longer be able to see the home page. Please remember not to
apply the auth filter to your login URI, you will experience a terrible loop!
14.5 Customization
I know what youre thinking. What if I dont want to use Eloquent or Fluent, this seems very
limited!
Please, this is Laravel. You should have learned this by now! Laravel allows you to create
custom classes known as Auth Drivers so that you can modify parameters or hook into
any authentication system you like. Simply create a new class. I like to put mine in
application/libraries so that they are autoloaded for me!
1
<?php
2
3
4
// application/libraries/myauth.php
class Myauth extends Laravel\Auth\Drivers\Driver {
5
6
7
8
9
10
11
12
Authentication
83
13
14
15
16
Your authentication driver must extend Laravel\Auth\Drivers\Driver and contain the two
methods listed above. The first method accepts the array of username and password and is
used to authenticate using your own method. On a successful authentication you should make
a call to the login() method of the parent to inform Laravel that the authentication worked, for
example..
1
<?php
2
3
4
5
6
8
9
if($result)
{
return $this->login($result->id, array_get($arguments, 'remember'));
}
10
11
12
13
14
return false;
15
16
The login method accepts an identifier (that can be used later to retrieve the user) and the value
of the remember key from our arguments array. On authentication failure the method should
always return false.
The retrieve() method is handed the identifier that you previously passed to the login()
method, you can use this to return an object that represents the current user. For example..
1
<?php
2
3
4
5
6
Great! Now we have a working authentication driver. Before we can use it we will need to
register it with the Auth class. Add the following code to your application/start.php.
Authentication
84
<?php
2
3
4
5
Auth::extend('myauth', function() {
return new Myauth();
});
Pass an identifier for your authentication driver as the first parameter to Auth::extend(), the
second parameter is a Closure that is used to return a new instance of the class.
All that is left to do is update your application/config/auth.php file to point to this new
authentication driver..
1
<?php
2
3
and now enjoy using your authentication system in the usual way!
Field
Type
id
title
body
author_id
created_at
updated_at
INTEGER
VARCHAR(128)
TEXT
INTEGER
DATETIME
DATETIME
Field
Type
id
INTEGER
Table : users
85
86
username
nickname
password
created_at
updated_at
VARCHAR(128)
VARCHAR(128)
VARCHAR(64)
DATETIME
DATETIME
Ok that looks good, we can use the author_id field on the Post object to reference the User
object which represents the posts author.
Right, to work!
Now our schema for up() along with default user account.
1
<?php
2
3
4
5
6
7
8
9
Schema::create('users', function($table) {
$table->increments('id');
$table->string('username', 128);
$table->string('nickname', 128);
$table->string('password', 64);
$table->timestamps();
});
10
11
12
13
14
15
DB::table('users')->insert(array(
'username'
=> 'admin',
'nickname'
=> 'Admin',
'password'
=> Hash::make('password')
));
<?php
2
3
Schema::drop('users');
87
Lets also create our posts migration, I bet you didnt see that coming?
1
<?php
2
3
4
5
6
7
8
9
Schema::create('posts', function($table) {
$table->increments('id');
$table->string('title', 128);
$table->text('body');
$table->integer('author_id');
$table->timestamps();
});
<?php
2
3
Schema::drop('posts');
<?php
2
3
return array(
5
6
7
8
9
);
88
<?php
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Nice and simple, we have our User object which has_many posts, and our Post object which
belongs_to a user.
15.4 Routes
Ok, we have our tables, we have models, and since we are now following my work flow lets
create placeholders for the routes we will need.
1
<?php
2
3
4
5
Route::get('/', function() {
// this is our list of posts
});
6
7
8
9
Route::get('view/(:num)', function($post) {
// this is our single view
});
10
11
12
13
14
Route::get('admin', function() {
// show the create new post form
});
15
16
17
89
Route::post('admin', function() {
// handle the create new post form
});
18
19
20
21
Route::get('login', function() {
// show the login form
});
22
23
24
25
Route::post('login', function() {
// handle the login form
});
26
27
28
29
Route::get('logout', function() {
// logout from the system
});
Right, those are done. As you can see I am using GET/POST to show and handle forms with the
same URI.
15.5 Views
Lets start by creating a blade layout as a wrapper for our application.
templates/main.blade.php
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE HTML>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<title>Wordpush</title>
{{ HTML::style('css/style.css') }}
</head>
<body>
<div class="header">
<h1>Wordpush</h1>
<h2>Code is Limmericks</h2>
</div>
13
<div class="content">
@yield('content')
</div>
14
15
16
17
18
</body>
</html>
As you can see we have a very simple HTML5 template, with a CSS style-sheet (which we will
not be covering, by all means use it to make your blog pretty.. but this is not a design book) and
a yielded content area, for our page content.
90
We are going to need a login form, so our post authors can create new entries. I am going to
steal this view from the last tutorial, and hack it a bit to work with blade layouts. This is actually
good practice, re-use anything you can and eventually you will have built up your own Laravel
development toolkit.
pages/login.blade.php
1
@layout('templates.main')
2
3
4
@section('content')
{{ Form::open('login') }}
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{{ Form::close() }}
@endsection
As you can see, our login form is using our newly created blade layout. Lets also create our
Create New Post form.
pages/new.blade.php
1
<?php
2
3
@layout('templates.main')
4
5
6
@section('content')
{{ Form::open('admin') }}
7
8
9
10
11
91
12
13
14
15
16
17
18
19
20
21
22
{{ Form::close() }}
@endsection
<?php
2
3
4
5
Route::get('login', function() {
return View::make('pages.login');
});
There, that wasnt so hard. Now lets handle the authentication in the POST route in the usual
way.
1
<?php
2
3
Route::post('login', function() {
$userdata = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
5
6
7
8
9
if ( Auth::attempt($userdata) )
{
return Redirect::to('admin');
}
else
{
return Redirect::to('login')
->with('login_errors', true);
}
10
11
12
13
14
15
16
17
18
19
});
92
Now we can login to our system, if you have any trouble understanding these topics, refer to the
previous chapters, we arent covering anything new here.
Lets create the logout route, so we can test the login process.
1
<?php
2
3
4
5
6
Route::get('logout', function() {
Auth::logout();
return Redirect::to('/');
});
Lets add a small profile section to the header of our main template. We can use this to login or
logout from the system.
1
2
3
4
5
6
7
<div class="header">
@if ( Auth::guest() )
{{ HTML::link('admin', 'Login') }}
@else
{{ HTML::link('logout', 'Logout') }}
@endif
<hr />
<h1>Wordpush</h1>
<h2>Code is Limmericks</h2>
9
10
11
</div>
Now to add the auth filter to both admin routes, you will notice that admin is the only route that
needs protecting, since we want people to be able to browse our blog, but not write anything.
1
<?php
2
3
4
5
6
7
8
9
Lets also attach the create new post form to the admin GET route while we are here. We should
also hand the current logged in user to this view, that way we can use the user objects id field
to identify the author.
93
<?php
2
3
4
5
6
Now that we have a handle on our currently logged in user, lets add that information to the
create new post view, to identify our author.
1
<?php
2
3
...
4
5
{{ Form::open('login') }}
7
8
9
10
11
12
13
14
...
We can now identify our author, and the create new post page is ready. We dont need to link
to it, we want it hidden. We can simply hit the URL /admin if we want to create a new post.
Lets handle a new post creation.
1
<?php
2
3
Route::post('admin', function() {
4
5
6
7
8
9
10
11
12
13
14
15
16
94
'body'
17
=> 'required'
);
18
19
20
21
22
if ( $v->fails() )
{
// redirect back to the form with
// errors, input and our currently
// logged in user
return Redirect::to('admin')
->with('user', Auth::user())
->with_errors($v)
->with_input();
}
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
});
Now we should be able to create some blog posts, go ahead! Write a few articles so we have
something to view in our list all posts view.
Speaking of which, lets get to work on that.
1
<?php
2
3
4
5
6
Route::get('/', function() {
// lets get our posts and eager load the
// author
$posts = Post::with('author')->all();
return View::make('pages.home')
->with('posts', $posts);
8
9
10
});
We also need a view to list all of our blog posts, here we go..
pages/home.blade.php
95
<?php
2
3
@layout('templates.main')
4
5
6
7
8
9
10
11
12
13
@section('content')
@foreach ($posts as $post)
<div class="post">
<h1>{{ HTML::link('view/'.$post->id, $post->title) }}</h1>
<p>{{ substr($post->body,0, 120).' [..]' }}</p>
<p>{{ HTML::link('view/'.$post->id, 'Read more →') }}</p>
</div>
@endforeach
@endsection
Finally we need a full view for our blog posts, lets call it..
pages/full.blade.php
1
<?php
2
3
@layout('templates.main')
4
5
6
7
8
9
10
11
@section('content')
<div class="post">
<h1>{{ HTML::link('view/'.$post->id, $post->title) }}</h1>
<p>{{ $post->body }}</p>
<p>{{ HTML::link('/', '← Back to index.') }}</p>
</div>
@endsection
Route::get('view/(:num)', function($post) {
$post = Post::find($post);
return View::make('pages.full')
->with('post', $post);
});
Now we have a fully working blog, with just the basics. Lets take a quick look at what we could
do to improve it. These improvements may come up in future chapters.
96
Post Slugs
We could create post slugs to use instead of post ids in our URLs, this will result in better search
engine optimization.
16 Unit Testing
Unit testing can be a very useful tool for a web developer, it can be used to check whether adding a
feature, or modifying the codebase in some way has accidentally altered another feature, causing
it to fail. Some developers even practice Test-Driven development, where tests are written before
the code, to ensure that the code being written meets all requirements.
Laravel provides the tests directory to contain all of your applications tests, and even adds a
helper command to Artisan, the CLI interface for running PHPUnit test cases.
Not only can the application be tested, but bundles can also contain their own test suites. In fact
Laravel has a bundle devoted to testing the core features of the framework, it can be found in
the Laravel tests github respository.
16.1 Installation
No were not going to cover the Laravel installation again!
Laravel uses the PHPUnit software to execute its tests, before we can use the unit testing features
of Laravel we will need to install this software.
Installation of PHPUnit can vary from operating system to operating system, therefore I think it
would be best to look at the official documentation for PHP Unit to find installation instructions.
You will find the installation page here.
<?php
2
3
// application/tests/example.test.php
4
5
6
7
8
9
10
11
12
13
14
/**
* Test that a given condition is met.
*
* @return void
*/
public function testSomethingIsTrue()
{
$this->assertTrue(true);
https://github.com/laravel/tests
http://www.phpunit.de/manual/current/en/installation.html
97
Unit Testing
98
15
16
17
As you can see we create our test cases in a file with the extension test.php, the name of the
class must start with the word Test and it must extend the class PHPUnit_Framework_TestCase
these are limitations set not by Laravel, but by the PHPUnit software.
A PHPUnit test case may contain any number of tests, as camel-cased actions, prefixed with the
word test. Our tests can contain a number of different assertions, that decide whether our tests
will pass or fail.
A full list of assertations can be found on the PHPUnit documentation website.
2
3
4
5
6
7
8
9
OK (1 test, 1 assertion)
With the OK part appearing in bright green to show us that the tests have passed.
Of course we knew that the test would succeed because we are using the assertTrue() method
to check the value true. There is no way it could fail.
Lets bully the test so that it will fail, we will simply change the parameter to false.
1
2
3
...
$this->assertTrue(false);
...
Unit Testing
99
2
3
4
5
6
7
8
9
10
11
12
1) TestExample::testSomethingIsTrue
Failed asserting that false is true.
13
14
15
/home/daylerees/www/laravel/develop/application/tests/example.test.php:12
/usr/bin/phpunit:46
16
17
18
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Now we have some bright red lines to indicate that the tests have failed, including some details
about why the test failed.
If we wanted to test a bundle, we would simply pass a parameter to the test command, for
example.
1
https://github.com/laravel/tests
17 Caching
Laravel offers a very simple to use Caching class, allowing you to easily cache anything you
need to, for however long you like. Confused? Lets take a look at it in action.
17.1 Setup
There are many ways to store your cached data, you must set a driver stating which method
you want to use in application/config/cache.php. The options are file, memcached, apc,
redis, and database. You may experience better performance with apc or memcached but I
am going to use file based caching for its simplicity to setup.
1
<?php
2
3
<?php
2
3
4
$data = 'complicated_generated_data';
Cache::put('mydata', $data, 10);
Lets pretend that $data wasnt just an assigned string, but the result of a complicated algorithm
that would take some time to process, we dont want to process this data all the time, so we keep
it in the cache.
The first parameter to the method is the key, a string used to identify the cached data. The second
parameter is the data itself, and the third is the amount of time in minutes, to cache to the data.
The forever() method takes only the first two parameters, and acts exactly as the name implies.
The data is cached forever.
100
Caching
101
<?php
2
3
$data = Cache::get('mydata');
By default, if the cached item does not exist, or has expired already, the method will return NULL.
However, you can pass an optional second parameter to provide an alternate default value.
1
<?php
2
3
You can also pass a closures as the second parameter, and the value returned by the closure will
be used if the cache data does not exist. The closure will only be executed if the key does not
exist.
<?php
2
3
4
5
6
7
if (! Cache::has('mydata'))
{
$data = 'complicated_generated_data';
Cache::put('mydata', $data, 10);
}
8
9
return $data;
However, you can use the remember() method as a much more elegant solution. The remember()
method will return the value if it exists in the cache, or it will store and return the value of the
second parameter for a defined length of time, for example..
1
<?php
2
3
4
5
Of course the closure will not be executed unless the key does not exist, or has expired.
Have fun using the Cache!
18 Autoloading Classes
With many frameworks, knowing where to put your files, and how to load class definitions can
be a tricky topic, however with Laravel there are no strict rules applied to the layout of your
application. Laravels auto loader is a clever library which simplifies the loading of classes with
various naming or sub-folder conventions. It is flexible enough to handle the addition of complex
libraries or packages with ease. Lets have a look at the functions we have available.
18.1 Mappings
Mappings are the simplest method of loading classes, you can pass the auto loader an array
of Class name to file location key-value pairs and Laravel will handle the rest. Its efficient
autoloader will only load the required class definition when the class is used. By default the
Autoloader mappings are set within the start.php file, you can however use the class from
anywhere, but the start.php file is a good choice due to it being loaded early. Lets take a look
at a mapping..
1
<?php
2
3
// application/start.php
4
5
6
7
8
Autoloader::map(array(
'Cloud'
'Tifa'
));
=> path('app').'libraries/ff/cloud.php',
=> path('app').'libraries/ff/tifa.php',
The path('app') is a handy helper method to retrieve the absolute path to your projects
application folder. You can also retrieve absolute paths to other folders using the path()
method, here is a short list.
Method
Directory
path(app)
path(sys)
path(bundle)
path(storage)
application
laravel
bundles
storage
In the mapping example, you see that we specify our Class name as the array index, and the file
and location as the value, now if we wish to use the Cloud class..
1
<?php
2
3
$c = new Cloud();
102
Autoloading Classes
103
Laravels autoloader will detect (php magic methods) that a class definition needs to be loaded,
it will look at the mapping definitions to see if our Class exists there, and proceed to include()
the source.
<?php
2
3
4
5
Autoloader::directories(array(
path('app').'smurfs'
));
Now all of our classes inside the application/smurfs directory will be auto loaded, so long as
their file name matches the lower-case of their Class name.
2
3
4
5
6
class Princess
{
// so pretty
}
Before we can use this convention, Laravel needs to know where our root namespace folder is.
We can help it find our files by using the namespaces() method of the Autoloader class, for
example..
1
<?php
2
3
4
5
Autoloader::namespaces(array(
'Paladin'
=> path('libraries').'paladin'
));
Autoloading Classes
104
As you can see we pass an array to the method. The array key represents the name of the root
namespace, in this case Paladin and the and array value is used to indicate the root folder that
is matched by this namespace, in my example application/libraries/paladin.
<?php
2
3
4
5
Autoloader::underscored(array(
'Paladin'
=> path('app').'jobs/pld'
));
and now the Class Paladin_Light_Knight will have its definition loaded from the file application/jobs/pld/light/knight.php.
So now that you know how to auto load your classes with Laravel, you will no longer have to
plaster your source code with include() statements!
I would like to say thanks to Enrique Lopez, who gets to break the character limit because he
was clever enough to comment bilingually. Gracias Enrique!
With Laravel I think what I want and not how to write it. I enjoy programming.
(Con Laravel pienso qu es lo que quiero y no como escribirlo. Me divierto
programando.)
19 Configuration
Laravel has many configuration files in application/config to tweak almost every feature that
the framework offers. Wouldnt it be great if you could create your own configuration files this
way? Well today is your lucky day, because you can!
<?php
2
3
// application/config/ourconfig.php
4
5
return array(
6
7
'size'
=> 6,
'eat'
=> true,
8
9
10
);
You can use comments to make your config files more descriptive, I like to use the style of the
comments Laravel provides, for example..
1
<?php
2
3
// application/config/ourconfig.php
4
5
return array(
/*
|-----------------------------| Size
|-----------------------------|
| This is the size of my thing.
|
*/
7
8
9
10
11
12
13
14
15
'size'
16
17
=> 6,
);
105
106
Configuration
Im sure you can come up with a better description! You will have noticed by now that Laravel
configuration files are key-value pairs, with the array index representing the key, and the value
its value.
The value of the setting can be any value or object that PHP supports, it can even be a closure.
By providing a closure you are making it easy for the user to change the configuration to enable
it to be loaded from another source, for example..
1
<?php
2
3
// application/config/ourconfig.php
4
5
return array(
/*
|-----------------------------| Size
|-----------------------------|
| This is the size of my thing.
|
*/
7
8
9
10
11
12
13
14
15
'size'
16
17
18
19
},
20
21
=> function() {
$size = file_get_contents('path/to/file.json');
$size = json_decode($size);
return $size;
);
Now our size configuration is read from the JSON contents of a file, simple!
<?php
2
3
$option = Config::get('ourconfig.size');
Simply pass a string to the method, with the name of the file a period (.) and the name of the
configuration key. The value will be returned. If your configuration file is in a subdirectory you
will need to use extra periods to indicate the subdirectories, for example..
Configuration
107
<?php
2
3
$option = Config::get('ourconfig.sub.directory.size');
Sometimes its useful to retrieve the entire configuration array, to do this simply specify the
filename without the option. To retrieve the entire configuration array from our file we would
use.
1
<?php
2
3
$option = Config::get('ourconfig');
<?php
2
3
Config::set('ourconfig.size', 7);
If a configuration item exists within a configuration file, it will be written in the runtime
configuration when you use set(), however it will not be overwritten in the configuration file
itself. If a configuration item doesnt exist, a call to the set() method will create it, but again
not within the configuration file.
Try to put as many configurable settings as possible from your application into configuration
files, it will make it much easier to configure if you have to move or redistribute the application.
<?php
$db = new Discoball(Discoball::SHINY);
$db->configure_shinyness('max');
$db->spin_speed('8900rpm');
Woah! Thats a lot of settings. Now it would soon get boring to have to instantiate and setup
our discoball every time we want to use it. Lets let the IoC container instantiate it for us, and
jump right in with a code sample.
I like to put this code into start.php, but you can put it anywhere you like, as long as your objects
are registered before you try to resolve them.
1
<?php
2
3
// application/start.php
4
5
IoC::register('discoball', function() {
6
7
8
9
108
109
$db->spin_speed('8900rpm');
10
11
12
13
14
});
We use the IoC::register() method to register our object with the controller. The first
parameter is a string that will be used to resolve the object later, I used the word discoball
as it made the most sense to me. The second parameter is a closure that we can use to instantiate
our object.
Inside the closure you will see the familiar discoball configuration code, and we will return the
configured discoball object from the closure.
Great! Our object is registered, and thats all there is to the Io just kidding. Lets have a look
at how we can use our registered object.
<?php
$db = IoC::resolve('discoball');
And thats it! Instead of creating and configuring a new instance of our discoball each time, we
make a call to the resolve() method, passing the string that identifies the object and the IoC
container will execute the closure we created in the first section, and return our instantiated and
configured discoball object.
Handy, and saves many lines of code!
You can register and resolve as many objects as you want, go ahead and try it. For now lets
move on to singletons.
20.3 Singletons
Resolving our discoball is useful, but what if our discoball was expensive on resources to
instantiate, or should only be instantiated once? The register method will not be useful in this
case, since the closure is executed with every call to resolve() and a new instance of the object
is returned each time. This is where the singleton design pattern comes in.
The singleton design pattern involves writing your classes in a certain way, so that they can be
called using a static method, and will always return the same instance of itself. This way the
class is instantiated only once.
110
For more information on the Singleton design pattern, I would suggest a quick Google search,
or check out the PHP API which has an article on the subject.
Singletons can be useful, but they require a certain class structure to be able to use them. The
IoC container has a singleton() method which makes the process a lot more simple, and does
not require any special kind of class. Lets register our discoball as a singleton instead..
1
2
<?php
// application/start.php
3
4
IoC::singleton('discoball', function() {
6
7
8
9
10
11
12
13
});
As you can see, the process is almost identical to registering an object, except that we use the
method singleton() which accepts the same parameters.
When we resolve our discoball, the closure will only be run the first time resolve() is called,
the resulting object will be stored, and any future calls to the resolve() method will return the
same object instance. For example..
1
<?php
2
3
4
5
6
7
8
9
Great! Its also worth noting that you can pass an already instantiated object as a second
parameter to the singleton() method, and it will be returned by all future requests to resolve()
for example..
1
<?php
2
3
4
111
5
6
7
In a future chapter we will discuss using the IoC container and dependency injection in
combination with unit testing.
Thanks to Andrew Smith and Julien Tant (AoSix) for buying the book. Julien had the following
to say..
Hey Dayle, thanks a lot for this book, the Laravel framework is just awesome ! If
any french guys read this, visit http://www.laravel.fr/ !
Thanks guys, and great work translating the tutorials to French!
Also thanks to Proger_XP for buying the book and translating my tutorials to Russian, which
are available at Laravel.ru. Great work!
21 Encryption
Sometimes you need to protect your important data. Laravel provides two different methods to
help you do that. One-way and two-way encryption. Lets take a look at these methods.
Lets take a look at how password hashing works with one way encryption.
1
<?php
2
3
$pass = Input::get('password');
Now we have retrieved the password from our create user form, but its in plain-text! Lets
hash it quickly so we can store it securely in our database.
1
<?php
2
3
$pass = Hash::make($pass);
We have used another of Laravels highly expressive methods, this time make()ing a new Hash.
Our $pass value will now contain a bcrypt encrypted version of our password, neat!
Lets say that our user has entered their password to login, and now we need to check to see if
its authentic before they can be logged into the system. We can simply compare our hash to the
value stored in the database with the check() method.
1
<?php
2
3
4
5
6
7
$pass = Input::get('password');
if ( Hash::check($pass, $user->password) )
{
// auth successful
}
112
Encryption
113
The check() method accepts two parameters, the plain-text value provided by your user, and
the hashed password that you have stored. It returns a boolean value to indicate whether the
true values match or not.
What if we want to decode our data at a later date? Lets two way encrypt it.
<?php
2
3
Now our dirty little secret has been AES-256 encrypted, and the result has been returned. This
would be of no use if we couldnt decrypt the secret at a later date. Lets look at how you can
decrypt an encrypted piece of data.
1
<?php
2
3
$decrypted_secret = Crypter::decrypt($secret);
Easy as that! Simply hand the encrypted string to the decrypt() and the decrypted result is
handed back.
Enjoy using the Crypter class to simulate the feeling of using your super secret decoder rings
you got that one time in a cereal box!
22 AJAX Content
Modern web applications dont have the time to be waiting around for the next HTTP request.
Javascript has changed the way we browse, we want our content to automatically update. We
want to post information without having to reload the page.
In the Laravel IRC channel we often get asked how to use Ajax alongside Laravel, which seems
confusing, because the answer is simply like any other HTTP request. Lets dive right in and
look at some Ajax requests using the framework. We are going to need to make some HTTP
requests through Javascript, this can get ugly so I have decided to use the jQuery Javascript
framework in these examples.
There we go, now we have a content area, defined in a <DIV> element with the id of content,
this is where we will load out future content. We also have a link with the id of load-content
which we can use as a trigger to load our new content into the <DIV> above.
Before we can see this view, we will need to define a route to load it, I am going to make it my
base route..
1
<?php
2
3
4
5
6
// application/routes.php
Route::get('/', function() {
return View::make('template');
});
114
AJAX Content
115
Now if we visit http://localhost we are greeted with our site template, but clicking on the
load content link isnt going to do a lot without some Javascript. Although we wouldnt need
Javascript if we didnt have something to load, lets create a new route and view for content that
is to be loaded into the content <DIV>.
First the view..
1
2
3
and a route to serve the content, note that we arent embedding the content within a template,
if we did that the template would be repeated twice when we AJAX load our new content.
1
<?php
2
3
4
5
6
// application/routes.php
Route::get('content', function() {
return View::make('content');
});
Great so now we have our main template, and we have a secondary route with some content to
load via AJAX, so lets get started with the Javascript.
AJAX Content
12
116
13
14
15
16
17
18
19
20
As you can see, I have referenced my Javascript files before the closing tag, so that the HTTP
requests to load them dont block the page loading. This is a good practice to stick to. Lets get
started and add some Javascript to our public/js/script.js file.
We also create a new BASE variable so that Javascript is aware of the base URL to our application,
we will need this later to create request URLs.
1
2
3
4
5
// public/js/script.js
jQuery(document).ready(function($) {
// perform javascript only when the document
// has been fully loaded
});
Here we are using the jQuery() object to get a handle on the current document, and adding a
ready() event with a closure to hold our code. By waiting for the document object to be ready()
we can be sure that all DOM objects have loaded, and that the jQuery library has been loaded.
You may see other examples written like this..
1
2
3
4
5
// public/js/script.js
$(document).ready(function() {
// perform javascript only when the document
// has been fully loaded
});
This is fine, but could lead to problems if other Javascript libraries chose to use the $ object at a
later date. My method uses the jQuery class, and hands the inner closure a $ which is reassigned
to the jQuery object. This prevents any collisions.
Lets get started on creating a click event for our content loader link, there are many ways to do
this with jQuery, I am going to use the .click() method. Here we go..
1
2
// public/js/script.js
$(document).ready(function() {
3
4
$('#load-content').click(function(e) {
117
AJAX Content
e.preventDefault();
})
6
7
8
});
Now we have a click event defined, with a callback closure. By providing an event parameter
called e to the inner closure, we can use the e.preventDefault(); method to prevent the default
click action from being performed. In this case the link will not act as a hyper-link. Now we
need to make another HTTP request to GET the new content, and load it into our #content area.
Lets use the jQuery .get() method to perform this task.
1
2
3
4
5
6
// public/js/script.js
$(document).ready(function() {
$('#load-content').click(function(e) {
// prevent the links default action
// from firing
e.preventDefault();
8
9
10
11
})
12
13
});
Remember the BASE attribute we set earlier? We can use it to build our request URL, and create
a callback method to catch the data that is returned. We will inject the response from our GET
request into the #content element using the .html() method.
That was a lot of hard work wasnt it? Well at least now we can see our hard work in action,
lets load up the application at http://localhost and click the load content link. Hopefully it
worked!
So as you can see, using AJAX with Laravel is the same as using any other framework or plain
PHP, just be sure you format the views for your AJAX routes in a suitable manner.
<?php
2
3
// application/routes.php
AJAX Content
4
5
6
118
Route::post('content', function() {
// deal with the post data..
});
By using the Route::post() method instead of get() our content route will now respond to our
POST request, lets get started on the Javascript.
1
2
3
4
5
6
7
8
We are using the POST method to post some data to the content route, we can receive the data
with Laravel in a similar manner to form processing using the Input class.
1
<?php
2
3
4
5
6
7
// application/routes.php
Route::post('content', function() {
echo Input::get('name');
// Dayle
echo Input::get('age');
// 27
});
Simple as that!
AJAX Content
119
<?php
2
3
4
// application/routes.php
Route::get('content', function() {
6
7
8
9
10
11
12
return Response::json($data);
13
14
15
});
Finally we return a response object, passing our data array to the json() method which is
JSON encoded for us. We can optionally pass a different status code other than 200 as a second
parameter.
<?php
2
3
4
// application/routes.php
Route::get('content', function() {
6
7
8
9
10
11
12
13
14
15
16
17
});
The Request::ajax() returns a boolean true if the request is an AJAX request, and boolean
false if not.
AJAX Content
120
I would like to say thanks to the following people for buying a copy of Code Happy, thanks!
William Manley
Nate Nolting
Jorijn Schrijvershof
Caleb Griffin
Florian Uhlrich
Stefano Giordano
Simon Edwards
Id also like to say thanks to everyone that sent kind emails about the book, thanks for all the
support!
23 Debugging Applications
Applications written using the Laravel framework are best experienced without bugs, however
we all know how easily they can arise when we have deadlines to meet, and angry bosses
standing over our shoulders.
PHP itself has a number of different methods of debugging, from simple var_dump()s, print_r()s, the famous die() and the advanced debugging features of the PHP xdebug extension. Im
not going to cover these basic methods in detail, because this is a book about Laravel, not the
basics of the PHP language. Instead lets have a look at the features that Laravel offers to help
us track down those mean little bugs.
Unhandled Exception
2
3
Message:
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#0 /Users/daylerees/www/panda/laravel/view.php(93): Laravel\View->path('pag\
e.panda')
#1 /Users/daylerees/www/panda/laravel/view.php(199): Laravel\View->__constr\
uct(' page.panda ', Array)
#2 /Users/daylerees/www/panda/application/routes.php(35): Laravel\View::mak\
e(' page.panda ')
#3 [internal function]: {closure}()
#4 /Users/daylerees/www/panda/laravel/routing/route.php(163): call_user_fun\
c_array(Object(Closure), Array)
#5 /Users/daylerees/www/panda/laravel/routing/route.php(124): Laravel\Routi\
ng\Route->response()
#6 /Users/daylerees/www/panda/laravel/laravel.php(125): Laravel\Routing\Rou\
te->call()
#7 /Users/daylerees/www/panda/public/index.php(34): require('/Users/daylere\
e...')
#8 {main}
121
Debugging Applications
122
This is the error that is shown if a requested view doesnt exist at run time. As you can see
we have an informative error message from Laravel, as well as the file in which the error was
encountered, and a line number. In addition we also have a stacktrace that shows the initial
error, following all the method calls through the View layer all the way down to the routing
system.
Most of the time you wont need the stacktrace, but it could prove useful for the more experienced
developers, for example when an error occurs within a complex library.
The ignore array contains a list of errors that are to be ignored by the error handler. Although
these errors will no longer be displayed when they are encountered, they will always be logged.
Keep this in mind when using the ignore array.
To add an error type to this array, add the PHP error type constant, or an integer value to the
array.
1
A full list of PHP error type constants can be found on the PHP API, however here are some of
the more useful ones.
E_ERROR This will match all fatal run time errors.
E_WARNING This constant will match all warning, or non fatal type errors.
E_PARSE This constant will match all parse time errors, or syntax errors.
E_NOTICE This constant will match all run time notices.
E_ALL This constant will match all of the above, except for E_STRICT errors.
1
The detail config option can be used to switch the detailed error reporting on or off. When
enabled (true) it will show the full error report along with stack trace as shown above. Disabling
this option (false) will cause the default error 500 page to be displayed instead.
Debugging Applications
123
If the log config option is set to true, the closure contained within the logger config option will
be executed with each error, and passed an exception object.
1
2
3
4
By default, the closure contained within the logger config option will write an entry to a log file
within the storage/logs. However, providing a closure has provided a great deal of flexibility,
allowing you to override the default logging method with anything you can think of. Perhaps
you would prefer to log to a database? Make it so number 1! Engage.
23.3 Logging
Being able to show errors, and log them to files is handy, but what if we want to log our own
custom information? The Laravel Log class contains two different methods for logging useful
information from your application. Lets take a look at these methods now.
The Log::write() method accepts a log type, and a string message to be written to the log file.
For example..
1
<?php
2
3
Will result in the following line being written to the log file.
1
The entry will of course be written to the active log file in the storage/logs directory in a file
named after the current day, for example 2011-02-05.log. This allows for the logs to be rotated
and avoid having log files that are huge!
You can also use a magic method to set the log type, for example..
1
<?php
2
3
Debugging Applications
124
<?php
2
3
Very useful!
Make use of all of the features you have learned in this chapter to diagnose your applications if
anything goes wrong!
I would like to thank the following wonderful people for buying a copy of the book!
Marc Carson
David Wosnitza AKA _druuuuuuuu
Mark van der Waarde from Alsjeblaft!
Joseph Wynn
Alexander Karisson
Victor Petrov
Josh Kennedy
Alexandru Bucur
24 The Future
I feel that the book has become all that you need to write a successful web application. However
I will continue to update the book for all future editions of Laravel, and if I find a topic that I
could cover in more detail, I will surely do so!
This book is a publish in progress book, since you have paid for it, you will be able to download
all future updates for free from Leanpub.com.
Thanks for buying the book!
Dayle.
125