简体   繁体   中英

Add Pagination to relationship and get the relationship's relationship - Laravel

I am building a forum website using Laravel and Vue.

I have three tables: forums, posts, and users. One forum can have multiple posts, each post has a user who created the post.

When the user clicks on one forum, I want to display the latest 10 posts to this forum with the paginate method.

Forum.php

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Forum extends Model {
    use HasFactory;

    protected $table = 'forums';
    protected $guarded = [];

     /**
      * Get the forum posts
      * @return \Illuminate\Database\Eloquent\Relations\HasMany
      */
    public function posts() {
        return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
    }
}

Post.php

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model {
    use HasFactory;

    protected $table = 'posts';
    protected $guarded = [];

    /**
     * Get the post's user
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user() {
        return $this->belongsTo(User::class);
    }
}

User.php

<?php
namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable {
    use HasFactory, Notifiable;

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * Get the user posts
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

Here I retrieve the forum posts with the users.

ForumService.php

<?php
namespace App\Services;

use App\Models\Forum;

class ForumService {
    public static function getForumPosts($forumId) {
        $forum = Forum::with('posts.user')->find($forumId);
        dd($forum);
    }
}

However, I want to retrieve only 10 posts and get each post's user, so how do I do that in a relationship? The posts are paginated, but how to I get now the posting user? Because the dot syntax is applying to the user, therefore I paginate the user, not the posts.

ForumService.php

<?php
namespace App\Services;

use App\Models\Forum;

class ForumService {
    public static function getForumPosts($forumId) {
        $forum = Forum::with(
            [
                'posts' => function ($query) { // How do I get the post user?
                    return $query->paginate(10);
                }
            ]
        )->find($forumId);
        dd($forum);
    }
}

Just add the with method inside the query scope of the function you have created.

 $forum = Forum::with(
            [
                'posts' => function ($query) {
                    // returns posts with user  
                    return $query->with('user')->paginate(10);
                }
            ]
        )->find($forumId);

Now you can access the first user with $forum->posts[0]->user which will not query to the database but will prefetch the users and populate it in paginator collection.

As you have already the id of the forum you can only retrieve posts which belongs to that Forum and paginate them like this

 public static function getForumPosts($forumId) {
    return Forum::find($forumId)->posts()->paginate(10);
}

If you want to eager load Post creator you can perform that like this

public static function getForumPosts($forumId) {
    return Forum::find($forumId)->posts()->with(['user'])->paginate(10);
}

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