Laravel (3) Pagination Sorting & Filtering
Asked Answered
W

1

5

I have a list of all the "servers" in my "servers" table returned in my view with pagination. I have been struggling to figure out how to get sorting (asc & desc if possible) and filtering (searching within results) working.

Here is my controller code:

 $servers = Server::paginate(5);
 return View::make('servers.list')
            ->with('game', '')
            ->with('servers', $servers);

Here is my view code for the sorting:

<ul class="nav">
     <li class="active"><a href="#"><i class="icon-angle-down"></i>{{ Lang::line('servers.rank')->get() }}</a></li>
     <li><a href="#">{{ Lang::line('servers.date')->get() }}</a></li>
     <li><a href="#">{{ Lang::line('servers.language')->get() }}</a></li>
     <li><a href="#">{{ Lang::line('servers.uptime')->get() }}</a></li>
     <li>{{ HTML::link(URL::full() .'?sort=votes', Lang::line('servers.votes')->get()) }}     </li>
</ul>

I would like for the sorting to be done via simple anchor links and clicking on Votes or Rank or Date will return data with that sorting. Clicking on the same sorting anchor which is currently selected will reverse the direction of the sort.

I also have a bunch of "filter" options such as categories and integer ranges which when applied would "filter"/search the table and return the results with the same sorting as selected before the filter.

Is all/any of this possible with the pagination class? If not what might be the way I go about this? Not really sure the best way when using laravel.

Widen answered 5/3, 2013 at 3:19 Comment(0)
C
12

This is easy to do in laravel thanks to the great pagination and input class. Try this in your views:

Example View

Cleaned up view

<form action="" method="get" id="filter">

    Show <select name="game_id">
            <option value="">All</option>
        <?php foreach ($games as $game):?>
            <option value="<?=$game->id?>" <?=($game->id == Input::get('game_id')) ? 'selected="selected"' : null?>><?=$game->name?></option>
        <?php endforeach;?>
    </select>

    Show <select name="server_id">
            <option value="">All</option>
        <?php foreach ($servers as $server):?>
            <option value="<?=$server->id?>" <?=($server->id == Input::get('server_id')) ? 'selected="selected"' : null?>><?=$server->name?></option>
        <?php endforeach;?>
    </select>

    <input type="submit" value="Filter" rel="filter">

</form>

<hr>

<?php if (count($servers) > 0):?>

    <?=$pagination?>

    <table>
        <tr>
            <th><a href="<?=URL::to('servers?sort=id'.$querystr)?>">ID</a></th>
            <th><a href="<?=URL::to('servers?sort=rank'.$querystr)?>">RANK</a></th>
            <th><a href="<?=URL::to('servers?sort=date'.$querystr)?>">DATE</a></th>
            <th><a href="<?=URL::to('servers?sort=language'.$querystr)?>">LANGUAGE</a></th>
            <th><a href="<?=URL::to('servers?sort=uptime'.$querystr)?>">UP TIME</a></th>
            <th><a href="<?=URL::to('servers?sort=votes'.$querystr)?>">VOTES</a></th>
        </tr>
        <tr>
            <td>
                ...
            </td>
        </tr>
    </table>

    <?=$pagination?>

<?php else:?>
    <h2>No results found.</h2>
<?php endif;?>

Example Controller

public function get_action()
{
    // CACHE SORTING INPUTS
    $allowed = array('rank', 'date', 'language', 'uptime', 'votes'); // add allowable columns to search on
    $sort = in_array(Input::get('sort'), $allowed) ? Input::get('sort') : 'id'; // if user type in the url a column that doesnt exist app will default to id
    $order = Input::get('order') === 'asc' ? 'asc' : 'desc'; // default desc

    $servers = Server::order_by($sort, $order);

    // FILTERS
    $game = null;
    $server = null;

    if (Input::has('game_id')) {
        $servers = $servers->where('game_id', Input::get('game_id'));
        $game = '&game_id='.Input::get('game_id');
    }
    if (Input::has('server_id')) {
        $servers = $servers->where('server_id', Input::get('server_id'));
        $server = '&server_id='.Input::get('server_id');
    }

    // PAGINATION
    $servers = $servers->paginate(5);

    $pagination = $servers->appends(
        array(
            'game_id'       => Input::get('game_id'),
            'server_id' => Input::get('server_id'),
            'sort'      => Input::get('sort'),
            'order'     => Input::get('order')
        ))->links();

    return View::make(servers.list)->with(
        array(
            'game'          => null,
            'servers'       => $servers,
            'pagination'    => $pagination,
            'querystr'      => '&order='.(Input::get('order') == 'asc' || null ? 'desc' : 'asc').$game.$server
        ));
}
Conlin answered 5/3, 2013 at 5:37 Comment(3)
Thanks for taking the time to write out all this, it was extremely helpful and appreciated! Just wondering, if you were allowing multiple filters such as multiple selects but users could opt whichever ones to use, how would you handle that in the controller? Is there a more efficient way than checking each type on wether there was input by the user? Perhaps something like an array of all Input items?Widen
Yea I agree it was messy. I cleaned up the view. As far as I know you have to check for user input or you would be querying for results that you dont want. Ultimately you could build a lot of this into the model, or make a wrapper class so you could use it elsewhere. Wrapper class is something Ive wanted to make, there actually might be one available.Conlin
And you call this "simple"? :) I found it much more simple in CakePHP with just a line Paginator->sort('myField') I wish it was that simple in Laravel too!Kenelm

© 2022 - 2024 — McMap. All rights reserved.