Skip to content

Instantly share code, notes, and snippets.

@Gargron
Created March 27, 2012 21:41
Show Gist options
  • Save Gargron/2220600 to your computer and use it in GitHub Desktop.
Save Gargron/2220600 to your computer and use it in GitHub Desktop.
PHP Sorter abstraction
<?php namespace Sorter;
class Sorter
{
/**
* Apply sorting logic to a given DB query. Look-up the model's rules to allow/disallow and alias sorting types
*
* @param $sort_by string Sorting subject
* @param $direction integer 1 or -1
* @param $query string
* @param $model string
* @return string
*/
public static function apply($sort_by, $direction, $query, $model)
{
$rules = self::load_rules($model);
$direction = $direction == -1 ? -1 : 1;
if(array_key_exists($sort_by, $rules))
{
return self::inject($query, $rules[$sort_by], $direction);
}
else
{
if(! empty($rules))
{
reset($rules);
return self::inject($query, current($rules), $direction);
}
else
{
return str_replace(':sort', '', $query);
}
}
}
/**
* Replaces :sort in original query string with the generated sorting query
*
* @param $query string
* @param $column string
* @param $direction integer
* @return string
*/
private static function inject($query, $column, $direction)
{
return str_replace(':sort', 'ORDER BY ' . $column . ' ' . ($direction == -1 ? 'DESC' : 'ASC'), $query);
}
/**
* Load (static) rules and aliases from a model, return an empty array if none exist
*
* @param $model string
* @return array
*/
private static function load_rules($model)
{
$rules = $model::$rules;
if(! $rules)
$rules = array();
return $rules;
}
}
@Gargron
Copy link
Author

Gargron commented Mar 28, 2012

Example implementation:

<?php

class Post extends Eloquent
{
    public static $sort_rules = array(
        'age' => 'posts.created_at',
    );

    public static function all($sort = 'age', $direction = -1, $offset = 0, $limit = 20)
    {
        return DB::query(
            Sorter\Sorter::apply($sort, $direction, "SELECT posts.*, users.name FROM posts LEFT JOIN users ON users.id = posts.user_id :sort LIMIT ?, ?", "Post"),
            array($offset, $limit)
        );
    }
}

(With Eloquent, naming your own function all is not advisable because of conflicts and whatnot, but for exemplary reason and because it looks good I use it here)

And therefore, in a controller/router, here in Laravel:

<?php

Route::get('posts', function()
{
    # /posts?sort=age&dir=1
    return View::make('posts.list', array(
        'posts' => Post::all(Input::get('sort', 'age'), Input::get('dir', -1)),
    ));
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment