Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Simple Pagination Laravel Package

ashleydawson/simple-pagination

Framework-agnostic pagination library for PHP. Provide callbacks to count total items and fetch a slice (offset/length), and it returns a Pagination object with items plus page metadata and ranges. Works with arrays, DB lists, Doctrine, Solr, and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require ashleydawson/simple-pagination
    
  2. Basic Setup:

    use AshleyDawson\SimplePagination\Paginator;
    
    $paginator = new Paginator();
    $paginator->setItemsPerPage(10);
    $paginator->setPagesInRange(5);
    
  3. Define Callbacks:

    $items = ['item1', 'item2', ..., 'itemN'];
    
    $paginator->setItemTotalCallback(function () use ($items) {
        return count($items);
    });
    
    $paginator->setSliceCallback(function ($offset, $length) use ($items) {
        return array_slice($items, $offset, $length);
    });
    
  4. Paginate and Use:

    $pagination = $paginator->paginate((int) request('page', 1));
    
    // Render items
    foreach ($pagination->getItems() as $item) {
        echo $item;
    }
    
    // Render pagination links
    foreach ($pagination->getPages() as $page) {
        echo '<a href="?page=' . $page . '">' . $page . '</a> ';
    }
    

First Use Case

Replace Laravel’s built-in pagination (e.g., App\Models\Post::paginate(10)) with this package for custom data sources (e.g., external APIs, non-Eloquent collections, or complex queries). Example:

$paginator = new Paginator();
$paginator->setItemsPerPage(15);

// Custom API data fetch
$paginator->setItemTotalCallback(function () {
    return $this->apiClient->countItems();
});

$paginator->setSliceCallback(function ($offset, $length) {
    return $this->apiClient->fetchItems($offset, $length);
});

$pagination = $paginator->paginate(request('page'));

Implementation Patterns

Workflows

  1. Array Pagination: Use for in-memory collections (e.g., cached results, filtered arrays).

    $array = [1, 2, 3, ..., 100];
    $paginator->setSliceCallback(fn($offset, $length) => array_slice($array, $offset, $length));
    
  2. Database Pagination: Replace LIMIT/OFFSET with this package for flexible pagination (e.g., dynamic itemsPerPage).

    $paginator->setSliceCallback(function ($offset, $length) {
        return DB::table('posts')
            ->orderBy('created_at')
            ->skip($offset)
            ->take($length)
            ->get();
    });
    
  3. API/External Data: Wrap third-party APIs (e.g., Stripe, Elasticsearch) with callbacks.

    $paginator->setItemTotalCallback(function () {
        return $this->stripe->countCustomers();
    });
    $paginator->setSliceCallback(function ($offset, $length) {
        return $this->stripe->listCustomers($offset, $length);
    });
    
  4. Dynamic Configuration: Use constructor or fluent methods to reconfigure per request (e.g., admin vs. user views).

    $adminPaginator = new Paginator([
        'itemsPerPage' => 50,
        'pagesInRange' => 10,
    ]);
    

Integration Tips

  • Laravel Request Binding: Bind pagination parameters to a DTO or Form Request:

    public function rules() {
        return ['page' => 'sometimes|integer|min:1'];
    }
    

    Then use request('page') in paginate().

  • Blade Integration: Create a reusable pagination view:

    @component('pagination', ['pages' => $pagination->getPages()])
        @slot('first') <a href="?page=1">First</a> @endslot
        @slot('prev') <a href="?page={{ $pagination->getPreviousPageNumber() }}">Prev</a> @endslot
    @endcomponent
    
  • Caching: Cache the Pagination object or its metadata for performance:

    $cacheKey = "pagination_{$request->page}";
    $pagination = Cache::remember($cacheKey, now()->addHours(1), function () use ($paginator) {
        return $paginator->paginate(request('page'));
    });
    
  • Testing: Mock callbacks for unit tests:

    $paginator->setItemTotalCallback(fn() => 100);
    $paginator->setSliceCallback(fn($offset, $length) => ['item1', 'item2']);
    $this->assertEquals(['item1', 'item2'], $paginator->paginate(1)->getItems());
    

Gotchas and Tips

Pitfalls

  1. Offset Calculation:

    • Issue: array_slice with large offsets can be slow or fail.
    • Fix: Use array_chunk for pre-sliced arrays or optimize database queries with LIMIT/OFFSET.
  2. Callback Scope:

    • Issue: Closures lose context if not bound with use.
    • Fix: Always use use ($var) or bind methods to the class:
      $paginator->setSliceCallback([$this, 'sliceItems']);
      
  3. Metadata Overwrite:

    • Issue: setMeta() overwrites existing metadata.
    • Fix: Merge metadata:
      $pagination->setMeta(array_merge($pagination->getMeta(), ['new_key' => 'value']));
      
  4. Page Range Edge Cases:

    • Issue: pagesInRange may exclude the first/last page if misconfigured.
    • Fix: Test with totalNumberOfPages < pagesInRange and adjust logic.
  5. Iterator Return Types:

    • Issue: Callbacks returning Iterator or Generator may not work as expected in older PHP versions.
    • Fix: Ensure PHP 7.1+ and test with:
      $paginator->setSliceCallback(function () {
          yield 'item1';
          yield 'item2';
      });
      

Debugging

  • Verify Callbacks: Log callback outputs to debug:

    $paginator->setItemTotalCallback(function () {
        $count = count($items);
        Log::debug("Total items: {$count}");
        return $count;
    });
    
  • Check Pagination Object: Dump the entire object to inspect metadata:

    dd($pagination->toArray());
    
  • Edge Cases: Test with:

    • Empty collections (setItemTotalCallback(fn() => 0)).
    • Single-page results (itemsPerPage >= totalItems).
    • Large offsets (e.g., page=1000).

Extension Points

  1. Custom Pagination Views: Extend the Pagination class to add methods like getUrl($page):

    class CustomPagination extends \AshleyDawson\SimplePagination\Pagination {
        public function getUrl($page) {
            return route('items.index', ['page' => $page]);
        }
    }
    
  2. Pre/Post Query Logic: Use setBeforeQueryCallback/setAfterQueryCallback for:

    • Logging.
    • Caching.
    • Modifying the Pagination object dynamically:
      $paginator->setAfterQueryCallback(function (Paginator $paginator, Pagination $pagination) {
          $pagination->setMeta(['timestamp' => now()->toIso8601String()]);
      });
      
  3. Integration with Laravel: Create a macro for Eloquent collections:

    Collection::macro('simplePaginate', function ($perPage) {
        $paginator = new Paginator();
        $paginator->setItemsPerPage($perPage);
        $paginator->setItemTotalCallback(fn() => $this->count());
        $paginator->setSliceCallback(fn($offset, $length) => $this->slice($offset, $length));
        return $paginator->paginate(request('page', 1));
    });
    

    Usage:

    $posts = Post::query()->simplePaginate(15);
    
  4. Localization: Override page labels (e.g., "Previous" → "Anterior") by extending the Pagination class and modifying the getPages() logic.

  5. Performance: For large datasets, avoid OFFSET in databases (use keyset pagination instead) and cache the Pagination object:

    $cacheKey = "pagination_{$request->page}_{$request->sort}";
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky