Anindit Karmakar
Anindit Karmakar

Reputation: 835

Laravel 4 eager loading

I have a User model, a Recipe model, and a Cookbook model.

A User can 'own' many recipes. (User -OneToMany- Recipe)

A user has 'only one' Cookbook. (User -OneToOne- Cookbook)

Recipes that a user owns belong to his Cookbook. One Recipe can belong to many Cookbook. (Recipe sharing) (Cookbook -ManyToMany- Recipe)

Many Users may LIKE Many Recipe. (User -ManyToMany- Recipe)

Many Users can follow Many Cookbook. (User -ManyToMany- Cookbook)

One User can have many friends who are Users (User -OneToMany- User)


What I want to do is load recipes for the currently logged in user.

I want to load the recipes owned by his friends and the recipes of all the cookbooks the logged in user is following.


class User extends Eloquent {
    public function friends() {
        return $this->belongsToMany('User', 'user_friends', 'user_id', 'friend_id');
    }

    public function cookbook() {
        return $this->hasOne('Cookbook', 'owner_id', 'id');
    }

    public function recipes() {
        return $this->hasMany('Recipe', 'owner_id', 'id');
    }

    public function followedCookbooks() {
        return $this->belongsToMany('Cookbook','cb_followers', 'follower_id', 'cb_id');
    }
}

class Recipe extends Eloquent() {
    public function owner() {
        return $this->belongsTo('User', 'owner_id', 'id');
    }

    public function cookbooks() {
        return $this->belongsToMany('Cookbook', 'cb_recipes', 'recipe_id', 'cb_id');
    }
}

class Cookbook extends Eloquent() {
    public function owner() {
        return $this->belongsTo('User', 'owner_id', 'id');
    }

    public function recipes() {
        return $this->belongsToMany('Recipe', 'cookbooks_recipes', 'cookbook_id', 'recipe_id');
    }

    public function followers() {
        return $this->belongsToMany('User', 'cb_followers', 'cb_id', 'follower_id');
    }
}

What I did is this:

$user = Auth::user();

$friends = $user->friends();
$cookbooks = $user->followedCookbooks();

$recipes = array();

foreach($friends as $friend) {
    $recipe = $friend->recipes();
    array_push($recipes, $recipe);
}

foreach($cookbooks as $cookbook) {
    $cbRecipes = $cookbook->recipes()
    foreach($cbRecipes as $cbRecipe) {
        array_push($recipes, $cbRecipe);
    }
}

But this method would run a lot of SQL queries. How can I use eager loading to reduce the number of queries?

Upvotes: 0

Views: 74

Answers (2)

Antoine Augusti
Antoine Augusti

Reputation: 1608

How about

$user = Auth::user();
$recipesFriends = $user->friends()->with('friends.recipes')->get();
$recipesCookbooks = $user->with('followedCookbooks')->with('followedCookbooks.recipes')->get();

If you want to go a bit further you can take a look at this answer: How to list out all items in a nested table in Laravel

Upvotes: 1

The Alpha
The Alpha

Reputation: 146191

You may try this:

$userData = Auth::user()->load('cookbook.recipes')
                        ->load('friends.cookbook.recipes');

If you want to load friends recipes in a different variable then you may try this:

$userData = Auth::user()->load('cookbook.recipes')
                        ->load('friends.cookbook.recipes');
$friendsData = $userData->friends;

Upvotes: 0

Related Questions