Forked from heroicpixels/gist:f70fd94d8d4d5158ba0f
Last active
August 8, 2016 17:57
-
-
Save keyurshah/fdcaf19d220830d1a683 to your computer and use it in GitHub Desktop.
#laravel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Filterable { | |
public $model; | |
public $options; | |
public function __construct($model) { | |
$this->model = $model; | |
} | |
public function resetFilterableOptions() { | |
$this->options = array( | |
'bools' => array('and' => 'where', 'or' => 'orWhere'), | |
'callbacks' => array(), | |
'columns' => array(), | |
'defaultOperator' => '=', | |
'defaultWhere' => 'where', | |
'filters' => array(), | |
'orderby' => 'orderby', | |
'order' => 'order', | |
'operators' => array('=', '<', '>', '!=', 'like'), | |
'qstring' => array() | |
); | |
return $this; | |
} | |
public function setColumns($columns, $append = true) { | |
if ( is_null($this->options) ) { | |
$this->resetFilterableOptions(); | |
} | |
if ( count(array_filter(array_keys($columns), 'is_string')) == 0 ) { | |
// Numeric indexes, so build new associative index array | |
$columns = array_combine($columns, $columns); | |
} | |
if ( !$append ) { | |
// Overwrite data | |
$this->options['columns'] = array(); | |
} | |
foreach ( $columns as $k => $v ) { | |
// Strip off callbacks | |
if ( is_callable($v) ) { | |
$this->options['callbacks'][] = $v; | |
unset($columns[$k]); | |
} | |
} | |
$this->options['columns'] = array_merge($this->options['columns'], $columns); | |
return $this; | |
} | |
public function setQuerystring(array $str = array(), $append = true, $default = true) { | |
if ( is_null($this->options) ) { | |
$this->resetFilterableOptions(); | |
} | |
if ( sizeof($str) == 0 && $default ) { | |
// Default to PHP query string | |
parse_str($_SERVER['QUERY_STRING'], $this->options['qstring']); | |
} else { | |
$this->options['qstring'] = $str; | |
} | |
if ( sizeof($this->options['qstring']) > 0 ) { | |
if ( !$append ) { | |
// Overwrite data | |
$this->options['filters'] = array(); | |
} | |
foreach ( $this->options['qstring'] as $k => $v ) { | |
if ( $v == '' ) { | |
continue; | |
} | |
$thisColumn = isset($this->options['columns'][$k]) ? $this->options['columns'][$k] : false; | |
if ( $thisColumn ) { | |
// Query string part matches column (or alias) | |
$this->options['filters'][$thisColumn]['val'] = $v; | |
// Evaluate boolean parameter in query string | |
$thisBoolData = isset($this->options['qstring']['bool'][$k]) ? $this->options['qstring']['bool'][$k] : false; | |
$thisBoolAvailable = $thisBoolData && isset($this->options['bools'][$thisBoolData]) ? $this->options['bools'][$thisBoolData] : false; | |
if ( $thisBoolData && $thisBoolAvailable ) { | |
$this->options['filters'][$thisColumn]['boolean'] = $thisBoolAvailable; | |
} else { | |
$this->options['filters'][$thisColumn]['boolean'] = $this->options['defaultWhere']; | |
} | |
// Evaluate operator parameters in the query string | |
if ( isset($this->options['qstring']['operator'][$k]) && in_array($this->options['qstring']['operator'][$k], $this->options['operators']) ) { | |
$this->options['filters'][$thisColumn]['operator'] = $this->options['qstring']['operator'][$k]; | |
} else { | |
// Default operator | |
$this->options['filters'][$thisColumn]['operator'] = $this->options['defaultOperator']; | |
} | |
} | |
} | |
} | |
return $this; | |
} | |
public function filterColumns($columns = array(), $validate = false) { | |
if ( sizeof($columns) > 0 ) { | |
// Set columns that can be filtered | |
$this->setColumns($columns); | |
} | |
// Validate columns | |
if ( $validate ) { | |
$this->validateColumns(); | |
} | |
// Ensure that query string is parsed at least once | |
if ( sizeof($this->options['filters']) == 0 ) { | |
$this->setQuerystring(); | |
} | |
// Apply conditions to Eloquent query object | |
if ( sizeof($this->options['filters']) > 0 ) { | |
foreach ( $this->options['filters'] as $k => $v ) { | |
$where = $v['boolean']; | |
if ( is_array($v['val']) ) { | |
if ( isset($v['val']['start']) && isset($v['val']['end']) ) { | |
// BETWEEN a AND b | |
$this->model->whereBetween($k, array($v['val']['start'], $v['val']['end'])); | |
} else { | |
// a = b OR c = d OR... | |
$this->model->{$where}(function($q) use ($k, $v) | |
{ | |
foreach ( $v['val'] as $key => $val ) { | |
$q->orWhere($k, $v['operator'], $val); | |
} | |
}); | |
} | |
} else { | |
// a = b | |
$this->model->{$where}($k, $v['operator'], $v['val']); | |
} | |
} | |
} | |
// Apply callbacks | |
if ( sizeof($this->options['callbacks']) > 0 ) { | |
foreach ( $this->options['callbacks'] as $v ) { | |
$v($this->model); | |
} | |
} | |
// Sorting | |
if ( isset($this->options['qstring'][$this->options['orderby']]) && isset($this->options['columns'][$this->options['qstring'][$this->options['orderby']]]) ) { | |
$order = isset($this->options['qstring'][$this->options['order']]) ? $this->options['qstring'][$this->options['order']] : 'asc'; | |
$this->model->orderBy($this->options['columns'][$this->options['qstring'][$this->options['orderby']]], $order); | |
} | |
return $this->model; | |
} | |
/** | |
* | |
* Validate the specified columns against the table's actual columns. | |
* | |
* @return $this | |
*/ | |
public function validateColumns() { | |
if ( class_exists('\\Doctrine\\DBAL\\Driver\\PDOMySql\\Driver') ) { | |
$columns = DB::connection()->getDoctrineSchemaManager()->listTableColumns($this->getTable()); | |
foreach ( $columns as $column ) { | |
$name = $column->getName(); | |
$columns[$name] = $name; | |
} | |
$this->options['columns'] = array_intersect($this->options['columns'], $columns); | |
return $this; | |
} | |
die('You must have Doctrine installed in order to validate columns'); | |
} | |
public function __call($name, $arguments) { | |
$retrieval = in_array($name, array('all', 'find', 'findOrFail', 'first', 'get', 'lists', 'paginate')); | |
$this->model = call_user_func_array(array($this->model, $name), $arguments); | |
if ( $retrieval ) { | |
return $this->model; | |
} else { | |
return $this; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment