Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
899 views
in Technique[技术] by (71.8m points)

php - Laravel 4.1: How to paginate eloquent eager relationship?

There was question about old L3 eager loaded paginations, not using eloquent. But i want to use eloquent to get eager loaded relationship with pagination.

Main model: Topic that has one to many relationship with Posts, So that one Topic has many Posts. I get all data with this function:

public function findById($id)
{
    return $this->topic->with('posts', 'posts.user', 'posts.user.profile')
                       ->find($id);
}

And later I make loop to display all results, but they are not paginated:

@foreach($topic->posts as $post)
... unpaginated content ...
@endforeach

So, i could make a workaround and select separately all posts that has $id of topic and use ->paginate() instead of ->get() and would got paginated $pots,

  1. but is there possibility to use eager loaded relationship posts that is paginated ? And how can it be done ?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To clarify something: paginating eager-loaded relationships is somewhat of a misconception. The point of eager loading is to retrieve all relationships in as few queries as you can. If you want to retrieve 10 topics, all of which have 35 posts, you will only need two queries. Sweet!

That said, paginating an eager-loaded relationship is not going to work. Consider two scenarios when eager loading happens:

  1. You want to retrieve and list topics, and maybe list the first five posts for each topic. Great! Eager loading is perfect. Now, you wouldn't want to paginate the eager-loaded posts on a page like this, so it doesn't matter.

  2. You load a single topic, and you want to paginate the posts for that topic. Great! Relatively easy to do. However, if you've already eager-loaded all posts belonging to this topic, you've just potentially retrieved a lot of extra resources that you don't need. Therefore eager loading is actually hurting you.

That said, there are two potential solutions:

Option 1: Create a custom accessor that paginates the Eloquent relationship.

/**
 * Paginated posts accessor. Access via $topic->posts_paginated
 * 
 * @return IlluminatePaginationPaginator
 */
public function getPostsPaginatedAttribute()
{
    return $this->posts()->paginate(10);
}

Pros: Paginates very easily; does not interfere with normal posts relationship.
Cons: Eager loading posts will not affect this accessor; running it will create two additional queries on top of the eager loaded query.

Option 2: Paginate the posts Collection returned by the eager-loaded relationship.

/**
 * Paginated posts accessor. Access via $topic->posts_paginated
 * 
 * @return IlluminatePaginationPaginator
 */
public function getPostsPaginatedAttribute()
{
    $posts = $this->posts;

    // Note that you will need to slice the correct array elements yourself.
    // The paginator class will not do that for you.

    return Paginator::make($posts, $posts->count(), 10);
}

Pros: Uses the eager-loaded relationship; creates no additional queries.
Cons: Must retrieve ALL elements regardless of current page (slow); have to build the current-page elements manually.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...