简体   繁体   中英

How to index returned array by key with eager loading in Laravel Eloquent?

I'm working on a side project in which we are trying to implement a "like" functionality for user's posts. We are using Laravel's ORM and we would like to use eager loading to make things easier, I'll outline the issue below. Some information first, the Post.php Model contains this:

public function likes()
{
    return $this->hasMany('App\Models\PostLike', 'post_id', 'post_id');
}

The PostController.php implementing the API call to load the posts and their likes looked like:

$posts = Post::with("likes")->where("group_id", "=", $group_id)->get();

An example JSON response from the posts API might look like this:

[
    {
        "post_id":1,
        "group_id":1,
        "author_id":1,
        "text":"Some text here.",
        "created_at":"2015-08-13 00:15:08",
        "updated_at":"2015-08-13 00:15:08",
        "likes":[
            {"post_id":1,"user_id":1,"updated_at":"2015-08-14 03:05:48"}
        ]
    }
]

The issue with this is that the "likes" are not indexed by the user_id, so you have to search through the array to determine if a user has liked the post or not, it would be much easier to have it indexed by the unique user_id key. That would yield something like:

[
    {
        "post_id":1,
        "group_id":1,
        "author_id":1,
        "text":"Some text here.",
        "created_at":"2015-08-13 00:15:08",
        "updated_at":"2015-08-13 00:15:08",
        "likes":{
            "1": {"post_id":1,"user_id":1,"updated_at":"2015-08-14 03:05:48"}
        }
    }
]

So the ultimate question is how do we index the eager loading response by one of the columns it returns?

In order to achieve that, you'll need to add extra post-processing step to your code that would index the array by id . This is very easy using Collection 's helper method keyBy() .

What you need is a accessor that would load the relation if needed and reindex the array. This accessor can be used in different scenarios, even without eagerly loading the relation, that's why it needs to handle relation loading if needed.

Adding that method to your Post model should do the trick:

public function getLikesAttribute() {
  return $this->getRelationValue('likes')->keyBy('user_id');
}

Custom accessors take priority above relation definitions in cases like that, when botu likes() and getLikesAttribute() exist. That's why your accessor will be called when you do $post->likes and will reindex the table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM