Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,37 @@ This query when posted will create the following MongoDB query:

Note that to use this you will need to install and configure `jenssegers/mongodb`.

## Building a query with additional rules from custom method.

You can use methods on your model for filtering.

To use this feature pass a second array with the following format to QueryBuilderParser().
```php
array(NAME_OF_FIELD => CLASS.METHOD.DB-FIELD)
```

* NAME_OF_FIELD = The name like in the first array
* CLASS = The Class you wish to use
* METHOD = The method to call on the given class
* DB_FIELD = Field to use for filtering (has to exist as a column and on the model)

Example Call with two normal fields (name, email) and an extra field "active":
```php
$qbp = new QueryBuilderParser(
array('name', 'email'),
array("active" => "\App\User.isActive.id")
);
```

which uses a method "isActive" on the User Class in the namespace \App.
It compares the value of your rule to the DB_FIELD on the model, so you have to have a parameter in this method.
```php
public static function isActive($user_id)
{
return true;
}
```

# Integration examples

## Integrating with jQuery Datatables
Expand Down
34 changes: 30 additions & 4 deletions src/QueryBuilderParser/QBPFunctions.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,17 +241,43 @@ private function getRuleValue(stdClass $rule)
}

/**
* Check that a given field is in the allowed list if set.
* Check that a given field is in the allowed lists if set.
*
* @param $fields
* @param $field
* @param $extra_fields
* @throws QBParseException
*/
private function ensureFieldIsAllowed($fields, $field)
private function ensureFieldIsAllowed($fields, $field, $extra_fields)
{
if (is_array($fields) && !in_array($field, $fields)) {
throw new QBParseException("Field ({$field}) does not exist in fields list");
if((is_array($fields) && !in_array($field, $fields))){
if($extra_fields){
if((is_array($extra_fields) && !array_key_exists($field, $extra_fields))){
throw new QBParseException("Field ({$field}) does not exist in fields list");
}
}else{
throw new QBParseException("Field ({$field}) does not exist in fields list");
}
}
}

/**
* Checks if a given field is in the normal or the extra list.
*
* @param $fields
* @param $field
* @param $extra_fields
* @return Bool
*/
private function fieldInNormalList($field, $extra_fields)
{
$ret = true;

if ((is_array($extra_fields)) && array_key_exists($field, $extra_fields)) {
$ret = false;
}

return $ret;
}

/**
Expand Down
86 changes: 70 additions & 16 deletions src/QueryBuilderParser/QueryBuilderParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ class QueryBuilderParser

/**
* @param array $fields a list of all the fields that are allowed to be filtered by the QueryBuilder
* @param array $extra_fields a list of all the extra fields that are allowed to be filtered by the (extended) QueryBuilder
* It has the following format: array(NAME_OF_FIELD => CLASS.METHOD.DB-FIELD)
* Where NAME_OF_FIELD = The name like in $fields array for checking the submitted query
* CLASS = The Model of the Instance in the App\ namespace
* METHOD = The method to call on the given class
* DB_FIELD = Field to use for filtering (has to exist as a column and on the model)
* Example Call with two normal fields (name, email) and an extra field "active":
* new QueryBuilderParser(['name', 'email'], ["active" => "User.isActive.id"]);
*/
public function __construct(array $fields = null)
public function __construct(array $fields = null, array $extra_fields = null)
{
$this->fields = $fields;
$this->extra_fields = $extra_fields;
}

/**
Expand Down Expand Up @@ -239,21 +248,66 @@ protected function makeQuery(Builder $query, stdClass $rule, $queryCondition = '
*/
protected function convertIncomingQBtoQuery(Builder $query, stdClass $rule, $value, $queryCondition = 'AND')
{
/*
* Convert the Operator (LIKE/NOT LIKE/GREATER THAN) given to us by QueryBuilder
* into on one that we can use inside the SQL query
*/
$sqlOperator = $this->operator_sql[$rule->operator];
$operator = $sqlOperator['operator'];
$condition = strtolower($queryCondition);
if($this->fieldInNormalList($rule->field, $this->extra_fields)){
/*
* Convert the Operator (LIKE/NOT LIKE/GREATER THAN) given to us by QueryBuilder
* into on one that we can use inside the SQL query
*/
$sqlOperator = $this->operator_sql[$rule->operator];
$operator = $sqlOperator['operator'];
$condition = strtolower($queryCondition);

if ($this->operatorRequiresArray($operator)) {
return $this->makeQueryWhenArray($query, $rule, $sqlOperator, $value, $condition);
} elseif ($this->operatorIsNull($operator)) {
return $this->makeQueryWhenNull($query, $rule, $sqlOperator, $condition);
}

if ($this->operatorRequiresArray($operator)) {
return $this->makeQueryWhenArray($query, $rule, $sqlOperator, $value, $condition);
} elseif ($this->operatorIsNull($operator)) {
return $this->makeQueryWhenNull($query, $rule, $sqlOperator, $condition);
}
return $query->where($rule->field, $sqlOperator['operator'], $value, $condition);
}else{
$instances = $query->get();

$field_data = explode(".", $this->extra_fields[$rule->field]);
$class = $field_data[0];
$method = $field_data[1];
$instance_member = $field_data[2];

if($query && $query->count() > 0){
$instance_valids = [];
$value = str_replace("%", "", $value);

foreach ($instances as $instance){
$instance_value = call_user_func_array([$class, $method], [$instance->$instance_member]);

if(
($rule->operator == 'equal' && $instance_value == $value) ||
($rule->operator == 'not_equal' && $instance_value != $value) ||
($rule->operator == 'in' && is_array($value) && in_array($instance_value, $value)) ||
($rule->operator == 'not_in' && is_array($value) && !in_array($instance_value, $value)) ||
($rule->operator == 'less' && $instance_value < $value) ||
($rule->operator == 'less_or_equal' && $instance_value <= $value) ||
($rule->operator == 'greater' && $instance_value > $value) ||
($rule->operator == 'greater_or_equal' && $instance_value >= $value) ||
($rule->operator == 'between' && $instance_value >= $value[0] && $instance_value <= $value[1]) ||
($rule->operator == 'not_between' && !($instance_value >= $value[0] && $instance_value <= $value[1])) ||
($rule->operator == 'begins_with' && substr($instance_value, 0, strlen($value) ) === $value) ||
($rule->operator == 'not_begins_with' && !substr($instance_value, 0, strlen($value) ) === $value) ||
($rule->operator == 'contains' && strpos($instance_value, $value) !== false) ||
($rule->operator == 'not_contains' && strpos($instance_value, $value) == false) ||
($rule->operator == 'ends_with' && substr($instance_value, -strlen($value)) == $value) ||
($rule->operator == 'not_ends_with' && !substr($instance_value, -strlen($value)) == $value) ||
($rule->operator == 'is_empty' && $instance_value == "") ||
($rule->operator == 'is_not_empty' && $instance_value != "") ||
($rule->operator == 'is_null' && !$instance_value) ||
($rule->operator == 'is_not_null' && $instance_value)
){
array_push($instance_valids, $instance->$instance_member);
}
}

return $query->where($rule->field, $sqlOperator['operator'], $value, $condition);
return $query->whereIn($instance_member, $instance_valids);
}
}
}

/**
Expand All @@ -274,9 +328,9 @@ protected function getValueForQueryFromRule(stdClass $rule)
$value = $this->getRuleValue($rule);

/*
* The field must exist in our list.
* The field must exist in our lists.
*/
$this->ensureFieldIsAllowed($this->fields, $rule->field);
$this->ensureFieldIsAllowed($this->fields, $rule->field, $this->extra_fields);

/*
* If the SQL Operator is set not to have a value, make sure that we set the value to null.
Expand Down