phplaravelpaginationlaravel-livewire

I'm having an issue with my query when using pagination and offset in Livewire 3


I'm having trouble with my query when using pagination and offset in Livewire 3. My query is supposed to display the latest articles, but I want to offset 4 articles because I've already created a display of the 4 latest articles in the section above.

However, when I add ->offset(4), it doesn't work at all. Why is that? Or am I doing something wrong?

<?php

namespace App\Livewire\Web\Post;

use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class ArticleIndex extends Component
{
    use WithPagination;

    public $lang;
    public $dataCategories;
    #[Url('c')]
    public $filterCategory = null;
    #[Url('y')]
    public $filterTrending = null;
    public $filterSearch = null;

    public function mount()
    {
        $this->dataCategories = DB::table('taxonomy_terms')->where('taxonomy', 'article_categories')->get();
    }

    public function render()
    {
        $dataArticle = DB::table('entries')->where('collection', 'article')
            ->when($this->filterSearch, function ($query) {
                return $query->whereRaw("LOWER(JSON_UNQUOTE(JSON_EXTRACT(data, '$.title'))) LIKE ?", ['%' . strtolower($this->filterSearch) . '%']);
            })
            ->when($this->filterCategory, function ($query) {
                return $query->whereJsonContains('data->article_categories', \Str::slug($this->filterCategory));
            })
            ->where('site', $this->lang == "en" ? "english" : "indonesia")
            ->orderBy('date', 'desc')
            ->where('published', true)
            ->offset(4)
            ->paginate(5);
        return view('livewire.web.post.article-index', compact('dataArticle'));
    }

    public function search()
    {
        $this->resetPage();
        $this->filterSearch == $this->filterSearch;
    }

    public function updatedFilterCategory()
    {
        $this->resetPage();
    }
    public function updatedFilterYear()
    {
        $this->resetPage();
    }
}


Solution

  • ->offset(4)->paginate(5) this won't do what you expect, because paginate()always resets the SQL OFFSET. in simple term OFFSET(4) is immediately overwritten.

    Since you need to skip 4 articles, I would suggest this way

    $entries = DB::table('entries')
        ->where('collection','article')
        ->where('site', $this->lang == 'en' ? 'english' : 'indonesia')
        ->where('published', true)
        ->orderBy('date','desc')
        ->limit(4) # you can remove this if its matches the above conditions. (Ex: when you have more item to skip)
        ->get();
    
    # take IDs
    $entriesIds = $entries->pluck('id')->all();
    
    $dataArticle = DB::table('entries')
        ->where('collection','article')
        ->where('site', $this->lang == 'en' ? 'english' : 'indonesia')
        ->where('published', true)
        ->when($this->filterSearch, fn($q) => 
            $q->whereRaw("LOWER(JSON_UNQUOTE(JSON_EXTRACT(data,'$.title'))) LIKE ?", ['%'.strtolower($this->filterSearch).'%'])
        )
        ->when($this->filterCategory, fn($q) => 
            $q->whereJsonContains('data->article_categories', Str::slug($this->filterCategory))
        )
        ->whereNotIn('id', $entriesIds) # skipp in here
        ->orderBy('date','desc')
        ->paginate(5);