Laravel eloquent - One to many relationships

Allister picture Allister · Oct 17, 2012 · Viewed 14.6k times · Source

I have just got started with laravel v3 and am trying to wrap my head around eloquent's One-To-Many relationships by creating a blog, I have posts that have a many to one relationship with categories (Each Post is linked to a category).

I have the following tables with the following fields:

posts: id, title, body, date_created, category_id

categories: id, name

I have the following two models:

class Category extends Eloquent 
{
    public function posts()
    {
        return $this->has_many('Post');
    }
}

class Post extends Eloquent 
{
    public function categories()
    {
        return $this->belongs_to('Category');
    }
}

I figured out how to get all posts by passing in a category id:

category::find(2)->posts()->get())

I just need help on finding out how to get all posts, and get their corrisponding categories. So at the end of the day in the view I can output something like this:

{$post->title} -  Category: {$post->category->name}

Thanks for any help!

Answer

William Cahill-Manley picture William Cahill-Manley · Oct 17, 2012

I hope you will find these tips useful.

On the post model rename the categories function to category. A belongs_to relation is singular, so this post has one and only one category.

Relations also have a short hand, this shorthand syntax is useful because it is cleaner to use and the results are cached. Heres an example:

$category = Category::find(1);
foreach($category->posts as post) {
    echo $post->title;
}

Now an example of how to get all the posts with their related categories:

$posts = Post::all();
foreach($posts as $post) {
    echo $post->category->name;
}

Now one thing you will quickly notice when doing this second example is the number of queries increase for each post you have. This is called the N+1 effect. Example, if you have 5 posts, one query will be executed to get those posts. Then in the loop we are executing a query to get the category. This results in 6 total queries.

To solve this problem, use eager loading, which reduces those 6 queries in our example down to 2.

$posts = Post::with('category')->all();
foreach($posts as $post) {
    echo $post->category->name;
}

I hope that helps!