Csatlakozz a Slack chatre
Szalai Barna / 1 éve

Cache-elt oldal lapozás LengthAwarePaginator-ral

Az alap lapozó megoldás a Laravel-ben sok terhet levesz a vállunkról, mert nagyon egyszerűen használható: az Eloquent lekérdezésünket nem get() -el fejezzük be hanem paginate() metódussal, melynek paraméterként megadjuk az oldalanként megjelenő pl. cikkek számát. Ez esetben minden egyes lapozáskor az adatbázishoz nyúl a programunk, ami nem erőforrás kímélő megoldás. Lehetőségünk van egyedi lapozást létrehozni, amivel megoldható, hogy az egyes oldalak elemei egy cache bejegyzésbe kerüljenek, így máris gyorsabb lesz a programunk.

A célunk a következő:

1. minden lapozott oldal cache-elve legyen
2. Bootstrap 4 -et használunk a lapozó gombok designjához
3. módosítjuk a beégetett ‘page’ szót az uri-ban, ‘oldal’-ra

Ahhoz, hogy a listázott cikkeink minden oldala cache-elt legyen, egyedi lapozást kell létrehoznunk. Ehhez a LenghtAwarePaginator lesz segítségünkre.

Létrehozunk egy konstanst, amelyben az oldalanként megjelenő cikkek számát tároljuk el. Ezt több helyen fogjuk használni kódunkban. Tegyük egy olyan fájlba, ahol biztos lefut ez a kód a rendszer indulásakor.

define(“ITEMS_PER_PAGE”, 9);

A controller kódja:

namespace App\Http\Controllers;

use App\Models\News;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\Cache\Repository as Cache;

class NewsController extends Controller
{
    public function index(News $news, Cache $cache, Request $request)
    {
        $cache->flush();

        $page = $request->has('oldal') ? $request->query('oldal') : 1;

        $key = md5('page'.$page.'.'.ITEMS_PER_PAGE);

        if ($cache->has($key)) {

            $data = $cache->get($key);

        } else {

            $data = $news->getByPage($page);

            $cache->put($key, $data, 60); 
        }

        $paginator = new LengthAwarePaginator($data->items, $data->totalItems, ITEMS_PER_PAGE);

        $paginator->setPath('hirek');

        $paginator->setPageName('oldal');

        return view('frontend.hirek')->with(['news' => $paginator]);
    }
}

A $key változó értéke minden oldalnál egyedi lesz, ez lesz a cache kulcs neve, és a $page változó mindig része az összeépített hash-nek. Ha ez a kulcs megtalálható a cache-ben, akkor abból tölti be az aktuális oldal cikkeit, ha pedig nincs, akkor a modellből töltjük be.

A modell kódja (App\Models\News):

public function getByPage($page)
{
    $results = new \StdClass();
    $results->page = $page;
    $results->limit = ITEMS_PER_PAGE;
    $results->totalItems = static::where('status', 1)->where('enabled', 1)->count();
 
    $news = static::where('status', 1)
        ->where('enabled', 1)
        ->latest()
        ->skip(ITEMS_PER_PAGE * ($page - 1))
        ->take(ITEMS_PER_PAGE)
        ->get();
    $results->items = $news;
 
    return $results;
}

A getByPage() metódusban tulajdonképpen összeépítünk egy Paginator objektumot.

Ez után meg kell adnunk, hogy Bootstrap 4 layout-ot szeretnénk a lapozóhoz, ehhez a sablont át kell másoltatnunk egy olyan mappába, ahol azt szerkeszteni tudjuk, vagy csak hogy elérhető legyen hogy hivatkozzunk rá.

php artisan vendor:publish --tag=laravel-pagination

A view fájlunkban megadjuk a linkek megjelenítésénél, hogy melyik sablont használjuk:

{{ $news->links('vendor.pagination.bootstrap-4') }}

Ezzel még nem vagyunk kész. Sajnos az oldalszám jelölése rendszerünbe be van égetve, tehát alapból /?page=1 módon fog kinézni az URI-nk. Mi ezt szeretnénk: /hirek?oldal=2.
Azzal, hogy beállítottuk setPath() és setPageName() segítségével a paramétereket, a kirajzolt lapozó nem fog még jól működni.

Hozzunk létre egy új Service Provider-t :

php artisan make:provider PaginationServiceProvider

Adjuk hozzá az app.php -hoz:

App\Providers\PaginationServiceProvider::class,

A boot metódusba beírt kód valójában felülírja a lapozó működését, és a beégetett “page” helyett az általunk megadott névvel fog dolgozni, így az aktív státusz beállítása is működni fog, ami jelzi melyik oldalon állunk, továbbá a többi lapozó gomb is jól fog már működni.

namespace App\Providers;

use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\ServiceProvider;

class PaginationServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        LengthAwarePaginator::currentPageResolver(function()
        {
            return $this->app['request']->input('oldal');
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        
    }
}

 

 Vissza a cikkekhez