Skip to content
Advertisement

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 AppModels;

use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;

class Forum extends Model {
    use HasFactory;

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

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

Post.php

<?php
namespace AppModels;

use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;

class Post extends Model {
    use HasFactory;

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

    /**
     * Get the post's user
     * @return IlluminateDatabaseEloquentRelationsBelongsTo
     */
    public function user() {
        return $this->belongsTo(User::class);
    }
}

User.php

<?php
namespace AppModels;

use IlluminateContractsAuthMustVerifyEmail;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateNotificationsNotifiable;

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 IlluminateDatabaseEloquentRelationsHasMany
     */
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

Here I retrieve the forum posts with the users.

ForumService.php

<?php
namespace AppServices;

use AppModelsForum;

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 AppServices;

use AppModelsForum;

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);
    }
}

Advertisement

Answer

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.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement