Jun 03, 2013
Table of contents:
A critical aspect to think about at the outset of a project is how the various components of your application will be related. Getting this right at the start will save a lot of headaches later on down the line when you realise you didn’t make the right structural decisions.
As I covered in Setting up your first Laravel 4 Model, an important characteristic of Models are the defined rules of how objects interact with each other. I’ve briefly touched upon how to define Model relationships already, and so today I’m going to take a much deeper dive into the various types of Model relationships and how to create them in Laravel 4.
When I’m starting a big project like this, I like to take a step back and try to map out all of the key resources of the application. By first defining the main objects at their most basic level, I feel like I have a better understanding of how to plan how the application should be constructed.
Domain modelling is a good exercise to go through when starting a project like this.
This article is going to broadly introduce Model relationships, and then I’m going to create the Twitter follower model for Cribbb.
So let’s get started!
Before I get into creating the Model relationships of Cribbb, first I want to give a brief overview of the four different types of relationships. It’s important to understand the differences between the types of relationships and understand under what conditions they are appropriate. Choosing the wrong type of relationship can mean you end up with an application that is either insufficient or has redundant data.
A One To One relationship is the most basic relationship you can get. This is essentially where a single record in one table is related to a single record in another table.
For example, A User has only one Library card number, and a Library card number can only be assigned to a single User.
A One To Many relationship is where a single entity has many related entities of the same type. This is where a single record is related to many records in another table through a Foreign Key. A Foreign key is simply an additional column that indicates which record this record is related to in the other table.
For example, a User has many Posts, but a Post can only be created by a single User.
So the table structure for this relationship would be:
users id name
posts id title user_id
Each table has an auto-incrementing Primary Keyid
, and the Posts table also has a Foreign Keyuser_id
to indicate which User created this particular post.
Many To Many relationships are where many objects can relate to many other objects. A Many To Many relationship is much more complicated than a One To Many relationship and therefore requires an additional table to record the relationship.
Say for example, within your social application, you have groups relating to certain interests. A User can belong to many Groups and a Group can have many Users.
The table structure for this relationship would be:
users id name
groups id name
group_user id group_id user_id
The group_user
table simply records the relationship between the two models. When a User joins a Group a new relationship is created, and when the User leaves that Group, the relationship record is destroyed. The table that joins the two objects is known as a Pivot Table. It is convention to name the Pivot Table using the two members of the relationship in alphabetical order, separated with an underscore. You don’t have to name your Pivot Tables this way, but by following the convention you create database tables that are self documenting and their purpose is obvious.
An interesting example of a Many To Many relationship is the way in which Twitter’s follower model works. A User follows many users and is followed by many users. In this example, you are creating a relationship between two of the same objects rather than two different objects and so the table structure would look like this:
user id name
user_follows id user_id follower_id
This actually only requires two tables because you a relating two objects of the same type. In order to record the relationship you just place the User who took the action in the user_id
column and the other user in the follower_id
column. Then if the other user decides to follow back, you can create the inverse of the relationship by adding another record but switching the roles.
And finally Polymorphic relationships allow a Model to belong to more than one other Model through a single association.
For example, within a social application, a User might be able to leave a comment on a post, or an image, or a status or any number of other objects. A comment is still just a comment, no matter what it is associated with.
A Polymorphic relationship for comments in a social application could look like this:
posts id body
photos id path
status id text
comments id comment timestamp commentable_id commentable_type
In this structure, the commentable_id
and the commentable_type
simply stores the id and the model that this comment belongs to. This means when you are interacting with comments, the ORM will automatically know what model instance it should return to you.
For example, if you searched for the comment with an id of 356, and this particular comment was associated with a photo, the ORM would return a Photo object of the photo that the comment was left on, automatically.
So now that you have an understanding of the different types of relationships, we can start looking at what type of relationships will exist in Cribbb.
As I mentioned above, domain modelling is where you map out all of the key concepts of the software. Usually I like to make rough sketches, list all of the important objects and how each thing is related. This is important because it forces you to have an understanding of the entire project from the outset. The more dark areas you can uncover at this point, the better decisions you will be able to make. It is also very important when working with a team. You need to ensure that everyone is on the same page, everyone is using the same vocabulary and everyone understands how each component will work within the system.
It’s important to go through this process before any code is written. This should be an entirely non-technical process. Just because you find yourself comfortable working in code, does not mean you should neglect this process. Resist the temptation to just jump in feet first.
I find a good way to do domain modelling is simply to describe each component as a paragraph or a couple of sentences. If it is too complicated to describe as prose, then it probably needs rethinking.
Cribbb is going to be a social application and so Users will be a critical component. Users can follow many other Users and a User can have many followers. User’s can create many Posts and a User can belong to many groups (Cliques). User’s can post many statuses.
A Post must be created by a User. A Post can have many comments. A Post must belong to a Clique.
A Clique have many Users. A Clique have many Posts.
I’m not going to go into any more detail than that. I think premature planning can be a very detrimental process for a software application and so I’m going to keep things very simple. If you are going through this process for a much more complicated application I would of course do more planning at the outset, but for Cribbb, I think this is enough.
I already have a User Model and a Post Model with the relationship set up from a previous tutorial. So therefore I need to add the following:
User following This will be used to allow Users to follow each other.
Cliques Cliques will be like groups. A group is where Users can form together around certain topics. Cliques can have many posts.
Clique membership Users have a relationship with the Cliques by becoming a member.
Comments Posts are the only things that will have comments at this stage, but I’m going to make this a polymorphic relationship because I think this is likely going to expand to encompass other commentable things in the future.
Finally now that I have a clearer set of objectives, I can get down to creating the User following functionality.
To create the User following functionality first I need to create a migration. If you need a reminder about migrations in Laravel, take a look at my previous tutorial, Laravel 4 Migrations. With this being a weird type of relationship between two of the same objects, I’m going to name the table user_follows
.
To create the Migration, I will simply run the following command from Terminal:
$ php artisan migrate:make create_user_follows_table -create -table=user_follows
This will create an empty migration file. All you have to do is add the columns for user_id
and follow_id
. Your migration should look like this:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserFollowsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create("user_follows", function (Blueprint $table) {
$table->increments("id");
$table->integer("user_id");
$table->integer("follow_id");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop("user_follows");
}
}
Run the migration to create the database table:
$ php artisan migrate
Next in the User.php
model, add the following method to define the relationship:
/**
* User following relationship
*/
public function follow()
{
return $this->belongsToMany('User', 'user_follows', 'user_id', 'follow_id');
}
And the following method to define the inverse:
/**
* User followers relationship
*/
public function followers()
{
return $this->belongsToMany('User', 'user_follows', 'follow_id', 'user_id');
}
The second argument of the belongsToMany()
method allows you to define a table name that does not follow the normal convention and the third and forth arguments allow you to overwrite the conventional associated keys.
As a quick ghetto way of testing this and showing how the theory actually plays out, you can make a route to hit that will test creating user relationships.
Open up your routes.php
file and copy the follow:
Route::get("/user", function () {
// Create User 1
$user1 = new User();
$user1->username = "philipbrown";
$user1->email = "name@domain.com";
$user1->password = "password";
$user1->password_confirmation = "password";
$user1->save();
// Create User 2
$user2 = new User();
$user2->username = "jack";
$user2->email = "jack@twitter.com";
$user2->password = "squareup";
$user2->password_confirmation = "squareup";
$user2->save();
// Make User 1 follow User 2
$user1->follow()->save($user2);
// Create User 3
$user3 = new User();
$user3->username = "ev";
$user3->email = "ev@twitter.com";
$user3->password = "pyralabs";
$user3->password_confirmation = "pyralabs";
$user3->save();
// Make User 1 follow User 3
$user1->follow()->save($user3);
// Find User 1
$philip = User::find(1);
// Display who User 1 is following
foreach ($philip->follow as $user) {
echo $user->username . "<br>";
}
// Find User 2
$jack = User::find(2);
// Display who is following User 2
foreach ($jack->followers as $user) {
echo $user->username . "<br>";
}
});
Hopefully that should be a pretty clear example of how the following and follower relationships work in Cribbb.
Originally I was only going to dedicate one post to Model relationships, but it turns out there is much more ground to cover than I initially thought.
This is a pretty important aspect of creating a web application so I don’t want to skate over the details or leave any important things out. I hate it when I follow a tutorial but the author leaves out critical bits, so I’m going to continue this topic next week.
In next week’s post I will walk through creating the other relationships and writing tests.
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.