binggle's avatar

Pagination in Many-to-Many Relationship.

getting pagination of many to many relationship ??

hi I have two models, Cat ( category) / Video

It is many to many relationship..

One Cat has many to many Videos.

I want to use pagination when getting videos of category.

Models..

class Cat extends Model
{
    public function videos()
    {
        return $this->belongsToMany( Video::class, 'cat_video' );
    }
}

class Video extends Model
{
    public function cats()
    {
        return $this->belongsToMany( Cat::class, 'cat_video' );
    }
}

in controller / Component whatever....


function show(){
    $cat = Cat::where('id', $this->cat_id)
            ->withCount( 'videos');

    if( $this->sortField == 'visits'  ){
        $cat= $cat->with( [ 'videos'=> function( $q ) use($sortDirection) {
            $q->orderBy('visits', $sortDirection);
        }] );
    } elseif( $this->sortField == 'recent' ) {
        $cat= $cat->with( [ 'videos'=> function( $q ) use($sortDirection) {
            $q->orderBy('created_at', $sortDirection);
        }] );
    } 
    
    $cat->first();
    return view('livewire.cat-show', [ 'cat'=>$cat ]);
}

in View


@foreach ($cat->videos as $item)
    <div>{{ $item->title }}</div>
@endforeach


<div>
    {{ $cat->videos()->links() }}
    {{--  error --}} 
    {{ $cat->videos->links() }} 
    {{--  error again --}}

</div>

How can I paginate videos corresponding with category ?

0 likes
2 replies
kylemilloy's avatar
Level 17

EDIT

Actually after looking at your code some more this is the wrong way to go about it...you're only showing a single cat on a page then you don't need to get the videos by the relation and it's easier if you just do:

// controller

// could also use Cat::find($this->cat_id); or route model binding to make your life easier...
$cat = Cat::where('id', $this->cat_id)->first();

$videos = Video::where('cat_id', $this->cat_id)
	->orderBy(function($query) {
	    if ($this->sortField === 'visits' || $this->sortField === 'recent') {
                $q->orderBy($this->sortField, $sortDirection);
            }
	})
	->paginate();

return view('livewire.cat-show', compact('cat', 'videos'));

Then there's no need to do $cat->first() and instead of accessing videos through $cat you just directly hit $videos

ORIGINAL POST

Well...you're not calling paginate() on the relationship in show for starters

function show()
{
    $cat = Cat::where('id', $this->cat_id)
        ->with(['videos' => function ($q) use ($sortDirection) {
            if ($this->sortField === 'visits' || $this->sortField === 'recent') {
                $q->orderBy($this->sortField, $sortDirection);
            }

            $q->paginate();
        }])
	->get();

    return view('livewire.cat-show', ['cat' => $cat]);
}

This should do the trick for you however I don't see where you're setting $sortDirection in this show call.

Because you're using a paginator you don't need to use withCount() as the paginator will have the total number of items.

1 like
binggle's avatar

You great..

Yes.

I should have called 'videos' separate..

And I guess there is no another way with one query.

I just repeat your code for later.


$cat = Cat::where('id', $this->cat_id)->first();

$videos = Video::where('cat_id', $this->cat_id)
	->orderBy(function($query) {
	    if ($this->sortField === 'visits' || $this->sortField === 'recent') {
                $q->orderBy($this->sortField, $sortDirection);
            }
	})
	->paginate();

return view('livewire.cat-show', compact('cat', 'videos'));


Please or to participate in this conversation.