May 13, 2013
Table of contents:
Model-View-Controller (MVC) is a very common design pattern in modern web applications. The wide usage and acceptance of the design pattern means that many of the most popular web frameworks are built around this architecture.
Laravel 4 is one such framework that uses the MVC design pattern to cleanly separate the various aspects of a web application.
In this post we’re going to look at what exactly is a Model, what are the three crucial components of Business Logic, and how to set up your first Model in Laravel 4.
So what exactly is a Model? If we’re going to be building this entire application on Models, first we need to understand exactly what they are.
A Model should contain all of the Business Logic of your application. Or in other words, how the application interacts with the database.
Business Logic is essentially:
So for example, Users will be an important object within Cribbb because it is a social application.
So as you can see, that is basically how Models work in MVC applications. Essentially each important thing in the application will probably need a Model. You will probably need to validate the data that is used in your Models, and any logic that relates Models to one another should be dealt with here.
User authentication is a requirement in just about every modern web application. Instead of forcing you to write your own User Model, Laravel 4 actually comes with a User Model straight out of the box.
So if you go into the app/models
directory, you should find the User.php
file. All of your models should go into this folder and they should be named following the same convention. So say for example, you had a Model for Posts in your application, the Model file would be app/models/Post.php
.
As a side note, you don’t have to follow this convention, there are ways around it, but I really don’t know why you would.
Anyway, if you open up the User model, you will see a fairly basic Model boilerplate.
So as I mentioned above, every Model should represent a table in the database. In order to interact with the database, we will need to extend the Model from Eloquent
. Eloquent is an ActiveRecord implementation that comes with Laravel.
Each Model extends Eloquent and so it inherits all of Eloquent’s methods for interacting with the database:
class User extends Eloquent
{
}
You will also notice that the default User Model implements two interfaces:
implements UserInterface, RemindableInterface
I’m not going to cover interfaces or the remindable features that are built into Laravel’s User model today as I will talk about them more extensively in a later tutorial.
The next thing you will notice is the protected property $table
:
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
As you can probably guess, this is simply declaring the name of the table that this model refers to. By default you don’t need to set this property as Laravel follows the convention of configuration mantra. This basically means, if you call your model User, then Laravel will assume that your table name is users. Setting the $table
property is useful when you want to give a table a name that does not follow this convention.
The $hidden
property allows you to hide certain columns when returning an instance of the Model:
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = array('password');
This is simply an array of column names. This is useful when you want to return details of the user over a JSON API for example. You wouldn’t want to display the user’s password.
Next we need to protect against mass assignment. When you pass an array of data to the Model, the data is automatically mass assigned to the right columns. This is handy because it makes things a lot easier, but it also presents quite a serious security concern. For example, you wouldn’t want the a user to be able to change their user id as this should set automatically when the user is created and it should never change.
To protect against mass assignment, we need to specify which of the columns can be mass assigned. To do this, we need to set the $fillable
property.
protected $fillable = array('username', 'email');
This ensures only these fields can be mass assigned.
You can also set the $guarded
property which prevents the listed columns from mass assignment. For example:
protected $guarded = array('id', 'password');
And finally, the model comes with three simple methods for returning specific data items from the Model:
/**
* Get the unique identifier for the user.
*
* @return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* @return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* @return string
*/
public function getReminderEmail()
{
return $this->email;
}
All good applications require validating data at some point. Users are prone to make mistakes or enter incorrect data, and so you need to ensure that you enforce that only correct data is allowed to enter your system.
Laravel 4 comes with a fantastic Validation package that makes creating and enforcing validation rules incredibly easy.
However, Laravel 4 does not enforce that you put your validation in your Models. A common bad practice is to place validation in the controller. This is bad because you are more than likely going to have to repeat that validation in multiple places throughout your application.
A much better place for your Validation is inside your Model because all interactions with the database must go through the Model, and so you will only need to write your rules once.
Due to Laravel 4 not enforcing where you put your Validation logic, I’m going to use an excellent package called Ardent to handle all of that. Ardent allows you to create self-validating Models. This basically means, your Models will validate themselves whenever you interact with them so you don’t have to write validation logic.
Ardent is a Composer package so we can install it by simply adding it to the composer.json
file.
Add the following line:
{
"require": {
"laravelbook/ardent": "dev-master"
}
}
And then run the following to update your project:
$ composer update
In order to use Ardent, first we need to change where the User Model extends from.
In User.php
you will need to update the following two lines:
// Add this line
use LaravelBook\Ardent\Ardent;
// Update this line
class User extends Ardent implements UserInterface, RemindableInterface {
Don’t worry though, all of Eloquent’s methods are still available through Ardent because Ardent is a direct decadent from Eloquent.
The next thing we need to do is to create a set of validation rules for each of the fields of the Model.
/**
* Ardent validation rules
*/
public static $rules = array(
'username' => 'required|between:4,16',
'email' => 'required|email',
'password' => 'required|alpha_num|min:8|confirmed',
'password_confirmation' => 'required|alpha_num|min:8',
);
Ardent leverages Laravel’s Validation class to create these easy to use validation rules. The validation rules for your model are simply stored as a public static array. As you can see from the values of the array, each rule is separated with a pipe.
For a full list of available validation rules, see this section of the documentation.
As I mentioned in the description of Ardent, all of your models will be “self validating”. This means your models will automatically reject input that does not pass your validation rules, without you actually having to do anything:
For example, the following will fail because I’m not supplying a password confirmation:
$user = new User();
$user->username = "philipbrown";
$user->email = "name@domain.com";
$user->password = "deadgiveaway";
$user->save(); // returns false
However, the following will save successfully:
$user = new User();
$user->username = "philipbrown";
$user->email = "name@domain.com";
$user->password = "deadgiveaway";
$user->password_confirmation = "deadgiveaway";
$user->save(); // returns true
Notice how you don’t have to validate any of the data yourself? If the validation fails, the model will simply not save.
We don’t really want to save the password_confirmation
data as this is just used for validation. To tell Ardent to just get rid of the redundant data like confirmation fields, we need to add the following line to the User model.
public $autoPurgeRedundantAttributes = true;
To quickly set up an example of all of this, we can simply define a new route that we can hit to see it in action.
Open app/routes.php
and copy the following code:
Route::get("/user", function () {
$user = new User();
$user->username = "philipbrown";
$user->email = "name@domain.com";
$user->password = "deadgiveaway";
$user->password_confirmation = "deadgiveaway";
var_dump($user->save());
});
This will simply create a new route that you can hit in the browser. When you go to /user, Laravel will automatically create a new user and attempt to save it to the database. If the user is saved correctly, you should see boolean true
outputted to the screen.
Save your routes.php
and run the following command in Terminal to quickly set up the server:
$ php artisan serve
Now go to https://localhost:8000/user to see your validation in action.
That was a very quick introduction to validating your Models in Laravel 4. I’ll be writing a much more in-depth article on the nitty gritty details of validation in the coming weeks.
The third and final characteristic of a model is that they hold the information that describes how business objects interact with one another.
Describing the relationship of two models is as easy as creating a new method.
Add the following method to your User.php
Model.
/**
* Post relationship
*/
public function posts()
{
return $this->hasMany('Post');
}
This extremely simple method is all you need to write in order to say a user has many posts.
Now of course, you will need to create the Post Model in order for this to work. I’m not going to go over creating the Post migration and model. Instead refer back to my Laravel 4 Migrations tutorial. For my Post model, I’m simply creating a body
column and a user_id
column. Here is the migration command that I ran.
php artisan generate:migration create_posts_table -fields="body:text, user_id:integer"
So your basic Post Model should look like this:
class Post extends Eloquent
{
protected $fillable = ["body"];
public function user()
{
return $this->belongsTo("User");
}
}
Notice how I have set the inverse of the relationship in the user()
method. This is simply saying that each post belongs to a user.
Next, create a new test route in your app/routes.php
and paste the following:
// Create a new Post
$post = new Post(["body" => "Yada yada yada"]);
// Grab User 1
$user = User::find(1);
// Save the Post
$user->posts()->save($post);
Now if you look in the posts table in your database, you should see that the post has saved and the user_id
has automatically been assigned to the user’s id.
That was a very quick overview of creating relationships in your Laravel Models. Again, I will cover each of these areas in more detail as we add some complexity to Cribbb. To read more about Laravel Model relationships, have a look at the documentation.
That was a quick overview of how to create Laravel Models. Hopefully you should have a firm understanding of the three important aspects of business logic that should be dealt with within your Models.
As I’ve mentioned a couple of times in this post, in future tutorials I will be going into much more depth on some of the intricacies of how Models work in web applications.
The observant amongst you will have noticed that I haven’t strictly followed Test Driven Development. However, don’t worry, I will be covering how to write Model tests using PHPUnit next week!
This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.
Come back next Monday as I look at how to write automated tests for your Models!