cult3

Working with Pagination in Laravel 4

Feb 24, 2014

Table of contents:

  1. The theory behind pagination
  2. Using the paginate method
  3. Manually creating pagination
  4. Working with Pagination in your Views
  5. Caching
  6. Infinite scrolling pagination
  7. Conclusion

I think it is a reasonable assumption to say that just about every web application that manages data will need pagination at some point in it’s life.

Pagination is an excellent solution to the problem of information overload. I think just about every user, no matter what their ability or understanding of how interfaces work, will intuitively understand how pagination works.

But creating pagination from scratch can be a right nightmare. There’s a lot of boiler plate code that you need to write to load results from a database and generate that little list of page numbers at the bottom of a page.

Fortunately pagination is just one of the many things that Laravel can make easier for us. Rolling your own pagination would be a nightmare and not using pagination is a crime against your users and your database.

In this tutorial I’m going to be looking at how to implement pagination in your Laravel 4 application.

The theory behind pagination

Before I get into the nitty gritty of creating pagination with Laravel, first I’ll briefly cover how pagination works.

Pagination is basically a way to break up a large collection of results over a number of pages. In the early days of building an application you will probably not need pagination. However once you get a large amount of data in your database, pagination becomes very important. Trying to load every result from a table when you have hundreds of thousands of rows will hammer your database and provide a terrible user experience for your users.

Pagination works by selecting a specific chunk of results from the database to display to the user. The total number of results is calculated and then split between pages depending on how many results you want to return on a page. To select the given chunk of results for any particular page you take the page number and multiple it by how many results to you want to return.

This makes paging through thousands of results a much better experience because you limit the amount of results to fetch from the database and you can calculate which results you want to return from the current page number.

Hopefully that makes sense.

Using the paginate method

As I mentioned in the introduction to this post, Laravel can actually handle pagination for us. The Laravel Query Builder has a paginate method that accepts the number of results to display on a page. Everything else is handled for you.

For example, using Eloquent you would write something like this:

$users = User::paginate(50);

Or using the Query Builder you would write:

$users = DB::table("users")->paginate(50);

This will return you an instance of Illuminate\Pagination\Paginator. This Paginator class has a number of useful methods for working with and displaying your pagination. I’ll cover that later in this article.

Manually creating pagination

Using the paginate method directly on an Eloquent model or on the Query Builder is an excellent solution for small projects. You can instantly have pagination up and running without having to write any extra code.

But for bigger projects I prefer to manually create the pagination by passing my results to Laravel’s Paginator class. When using the Repository Pattern you wouldn’t want to tie yourself to using Eloquent because in the future if you want to use a different Pagination service, you will be free to swap it out without having to rewrite a lot of code. Instead, you should return only the data that you need to build the pagination and then manually create it. By making this separation we also make it easier to work with cache or any number of other services you want to implement between your database and your application.

Laravel’s Paginator class allows us to manually create a pagination instance by using the make method:

$users = Paginator::make($items, $totalItems, $perPage);

So as you can see, we can achieve the same result by passing the results from the database, the count of the total results and how may results we want to display on a page to the make method.

To return this data you would create a new method on your Repository like this:

/**
 * Get results by page
 *
 * @param int $page
 * @param int $limit
 * @return StdClass
 */
public function getByPage($page = 1, $limit = 10)
{
    $results = StdClass;
    $results->page = $page;
    $results->limit = $limit;
    $results->totalItems = 0;
    $results->items = array();

    $users = $this->model->skip($limit * ($page - 1))->take($limit)->get();

    $results->totalItems = $this->model->count();
    $results->items = $users->all();

    return $results;
}

In this method I will pass the current page number and the required number of items to return. If no arguments are passed to the method it will use some sensible defaults.

Next I build a new object with what I’m going to need to feed to the Paginator class.

Next I perform the query to select the required results from the database. In the code above $this->model is an injected instance of the Eloquent model that I want to work with. To select the correct results I simply need to skip the number of results based upon the current page number and then limit the returned results based on my specified limit.

Next I will grab the total count of the table and return the object from the method.

Now in your Controller you can call the getByPage method and and pass the results to the Paginator class. For example, here is my index method for my UserController:

/**
 * Index
 *
 * @return View
 */
public function index()
{
    $page = Input::get('page', 1);

    $data = $this->user->getByPage($page, 50);

    $users = Paginator::make($data->items, $data->totalItems, 50);

    return View::make('users', compact('users'));
}

First I grab the page number from the query string. If this is the first page (and therefore the page number is not set) it will just default to 1.

Next I call the getByPage method on the Repository and pass the $page and the number of results to display. You could of course make the number of results to display dynamic too.

Next I create the $users by passing the returned data from the getByPage method into the Paginator.

And finally I will return the View.

Working with Pagination in your Views

Now that you have your data as an instance of Laravel’s Paginator class we can pass it to the View to display the results.

<ul>
  @foreach ($users as $user)
  <li>{{ $user->name }}</li>
  @endforeach
</ul>

{{ $users->links() }}

To display the items in the Paginator, you can iterate over them in exactly the same way as if this was a Collection that was returned from Eloquent.

To display the pagination links at the bottom of the page you can use the $users->links() method. This automatically generates the markup required to display the pagination options. Out of the box this will work perfectly with Bootstrap.

If you would like to use your own partial to display the pagination links, you can pass the name of the partial as an argument to the links method:

{{ $users->links('partials._paginator') }}

The Paginator class has a number of useful methods for creating your own pagination display. This includes:

  • getCurrentPage
  • getLastPage
  • getPerPage
  • getTotal
  • getFrom
  • getTo
  • count

For details of each method, check out the source.

Caching

If you have been following along with this series you will know that adding a method to our caching infrastructure is really easy.

/**
 * Feed
 *
 * @param int $id
 * @return Illuminate\Database\Eloquent\Collection
 */
public function getByPage($page = 1, $limit = 10)
{
    $key = md5('page'.$page.'.'.$limit);

    if ($this->cache->has($key)) {
        return $this->cache->get($key);
    }

    $pagination = $this->user->getByPage($page, $limit);

    $this->cache->put($key, $pagination);

    return $pagination;
}

As with previous articles, first create a unique key to represent the pagination result. Next check to see if the key is available in the cache. If the cache does have the result we are looking for we can simply return it. If it doesn’t we can go down a layer to the repository to pull the results, save it in the cache and return the results from the method.

Infinite scrolling pagination

Many websites and web applications do not utilise pagination and choose instead to load new results into the View using Ajax. Behind the scenes the exact same code is being used to generate this user experience.

Laravel’s Paginator class implements JsonableInterface and has a toJson method. This means you can set up a route to return the pagination as JSON so you can consume it using Ajax to create an infinite scrolling interface.

The returned JSON will have a number of items of meta data to make working with the returned data easier. This includes total, current_page, last_page, from, and to.

This means you can set up your Repository, Caching and Controller to use pagination using the traditional method, but easily make the switch to infinite scrolling once you start to refine your user experience and user interface design.

Conclusion

Pagination is a basic requirement of web application user interfaces. It’s really painful for both the user and the database when a developer has not used pagination on a data intensive page of a website.

I don’t think they are many arguments against pagination. It is a common user interface design pattern and with the rise of Ajaxified websites, the infinite scrolling pattern offers a fantastic user experience when consuming a lot of data.

I love how easy Laravel makes implementing pagination in your web applications. Laravel has taken a common requirement that would take a day to implement, and instead provides you with a couple of methods that you can simply add to your existing code.

Pagination is not something that has to be reinvented for each project and so it makes total sense to implement it in this way.

I want to give another shout out to Chris Fidao’s Implementing Laravel book. Once again the inspiration for this post was drawn from reading Chris’ excellent writing. If you are looking to learn more about these types of patterns for building web applications, I highly recommend grabbing yourself a copy of Chris’ book!

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.