128 lines
4.4 KiB
PHP
128 lines
4.4 KiB
PHP
<?php namespace utils;
|
|
use models\exceptions\ValidationException;
|
|
|
|
/**
|
|
* Copyright 2015 OpenStack Foundation
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
**/
|
|
final class FilterParser
|
|
{
|
|
/**
|
|
* @param mixed $filters
|
|
* @param array $allowed_fields
|
|
* @throws FilterParserException
|
|
* @return Filter
|
|
*/
|
|
public static function parse($filters, $allowed_fields = array())
|
|
{
|
|
$res = [];
|
|
$matches = [];
|
|
|
|
if (!is_array($filters))
|
|
$filters = array($filters);
|
|
|
|
foreach ($filters as $filter) // parse AND filters
|
|
{
|
|
|
|
$f = null;
|
|
// parse OR filters
|
|
$or_filters = explode(',', $filter);
|
|
|
|
if (count($or_filters) > 1) {
|
|
$f = [];
|
|
foreach ($or_filters as $of) {
|
|
|
|
//single filter
|
|
preg_match('/[=<>][=>@]{0,1}/', $of, $matches);
|
|
|
|
if (count($matches) != 1)
|
|
throw new FilterParserException(sprintf("invalid OR filter format %s (should be [:FIELD_NAME:OPERAND:VALUE])", $of));
|
|
|
|
$op = $matches[0];
|
|
$operands = explode($op, $of);
|
|
$field = $operands[0];
|
|
$value = $operands[1];
|
|
|
|
if (!isset($allowed_fields[$field])){
|
|
throw new FilterParserException(sprintf("filter by field %s is not allowed", $field));
|
|
}
|
|
if (!in_array($op, $allowed_fields[$field])){
|
|
throw new FilterParserException(sprintf("%s op is not allowed for filter by field %s",$op, $field));
|
|
}
|
|
|
|
$f_or = self::buildFilter($field, $op, $value);
|
|
if (!is_null($f_or))
|
|
$f[] = $f_or;
|
|
}
|
|
} else {
|
|
//single filter
|
|
preg_match('/[=<>][=>@]{0,1}/', $filter, $matches);
|
|
|
|
if (count($matches) != 1)
|
|
throw new FilterParserException(sprintf("invalid filter format %s (should be [:FIELD_NAME:OPERAND:VALUE])", $filter));
|
|
|
|
$op = $matches[0];
|
|
$operands = explode($op, $filter);
|
|
$field = $operands[0];
|
|
$value = $operands[1];
|
|
|
|
if (!isset($allowed_fields[$field])){
|
|
throw new FilterParserException(sprintf("filter by field %s is not allowed", $field));
|
|
}
|
|
if (!in_array($op, $allowed_fields[$field])){
|
|
throw new FilterParserException(sprintf("%s op is not allowed for filter by field %s",$op, $field));
|
|
}
|
|
|
|
$f = self::buildFilter($field, $op, $value);
|
|
}
|
|
|
|
if (!is_null($f))
|
|
$res[] = $f;
|
|
}
|
|
return new Filter($res);
|
|
}
|
|
|
|
/**
|
|
* Factory Method
|
|
*
|
|
* @param string $field
|
|
* @param string $op
|
|
* @param string $value
|
|
* @return FilterElement|null
|
|
*/
|
|
public static function buildFilter($field, $op, $value)
|
|
{
|
|
switch ($op) {
|
|
case '==':
|
|
return FilterElement::makeEqual($field, $value);
|
|
break;
|
|
case '=@':
|
|
return FilterElement::makeLike($field, $value);
|
|
break;
|
|
case '>':
|
|
return FilterElement::makeGreather($field, $value);
|
|
break;
|
|
case '>=':
|
|
return FilterElement::makeGreatherOrEqual($field, $value);
|
|
break;
|
|
case '<':
|
|
return FilterElement::makeLower($field, $value);
|
|
break;
|
|
case '<=':
|
|
return FilterElement::makeLowerOrEqual($field, $value);
|
|
break;
|
|
case '<>':
|
|
return FilterElement::makeNotEqual($field, $value);
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
} |