openstackid-resources/app/Http/Utils/Filters/Filter.php

389 lines
14 KiB
PHP

<?php namespace utils;
/**
* 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.
**/
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder;
/**
* Class Filter
* @package utils
*/
final class Filter
{
/**
* @var array
*/
private $filters = array();
/**
* @var array
*/
private $bindings = array();
public function __construct(array $filters = [])
{
$this->filters = $filters;
}
/**
* @param FilterElement $filter
* @return $this
*/
public function addFilterCondition(FilterElement $filter)
{
$this->filters[] = $filter;
return $this;
}
/**
* will return an array of filter elements, OR filters are returned on a sub array
* @param string $field
* @return null|FilterElement[]
*/
public function getFilter($field)
{
$res = [];
foreach ($this->filters as $filter) {
if ($filter instanceof FilterElement && $filter->getField() === $field) {
$res[] = $filter;
}
else if (is_array($filter)) {
// OR
$or_res = [];
foreach ($filter as $e) {
if ($e instanceof FilterElement && $e->getField() === $field) {
$or_res[] = $e;
}
}
if (count($or_res)) $res[] = $or_res;
}
}
return $res;
}
/**
* @param string $field
* @return null|FilterElement
*/
public function getUniqueFilter($field){
$res = $this->getFilter($field);
return count($res) == 1 ? $res[0]:null;
}
/**
* @param string $field
* @return bool
*/
public function hasFilter($field){
return count($this->getFilter($field)) > 0;
}
/**
* @param string $field
* @return null|FilterElement[]
*/
public function getFlatFilter($field)
{
$res = array();
foreach ($this->filters as $filter) {
if ($filter instanceof FilterElement && $filter->getField() === $field) {
$res[] = $filter;
}
else if (is_array($filter)) {
// OR
foreach ($filter as $e) {
if ($e instanceof FilterElement && $e->getField() === $field) {
$res[] = $e;
}
}
}
}
return $res;
}
/**
* @param Criteria $criteria
* @param array $mappings
* @return Criteria
*/
public function apply2Criteria(Criteria $criteria, array $mappings)
{
foreach ($this->filters as $filter) {
if ($filter instanceof FilterElement) {
if (isset($mappings[$filter->getField()])) {
$mapping = $mappings[$filter->getField()];
if ($mapping instanceof FilterMapping) {
continue;
}
$mapping = explode(':', $mapping);
$value = $filter->getValue();
if (count($mapping) > 1) {
$value = $this->convertValue($value, $mapping[1]);
}
$criteria->andWhere(Criteria::expr()->eq($mapping[0], $value));
}
} else if (is_array($filter)) {
// OR
foreach ($filter as $e) {
if ($e instanceof FilterElement && isset($mappings[$e->getField()])) {
$mapping = $mappings[$e->getField()];
if ($mapping instanceof FilterMapping) {
continue;
}
$mapping = explode(':', $mapping);
$value = $filter->getValue();
if (count($mapping) > 1) {
$value = $this->convertValue($value, $mapping[1]);
}
$criteria->orWhere(Criteria::expr()->eq($mapping[0], $value));
}
}
}
}
return $criteria;
}
/**
* @param QueryBuilder $query
* @param array $mappings
* @return $this
*/
public function apply2Query(QueryBuilder $query, array $mappings)
{
$param_prefix = "param_%s";
$param_idx = 1;
$bindings = [];
foreach ($this->filters as $filter) {
if ($filter instanceof FilterElement && isset($mappings[$filter->getField()])) {
$mapping = $mappings[$filter->getField()];
if ($mapping instanceof DoctrineJoinFilterMapping) {
$query = $mapping->apply($query, $filter);
continue;
}
if ($mapping instanceof DoctrineSwitchFilterMapping) {
$query = $mapping->apply($query, $filter);
continue;
}
if ($mapping instanceof DoctrineFilterMapping) {
$query = $mapping->apply($query, $filter);
continue;
}
else if(is_array($mapping)){
$condition = '';
foreach ($mapping as $mapping_or){
$mapping_or = explode(':', $mapping_or);
$value = $filter->getValue();
if (count($mapping_or) > 1) {
$value = $this->convertValue($value, $mapping_or[1]);
}
if(!empty($condition)) $condition .= ' OR ';
$bindings[sprintf($param_prefix, $param_idx)] = $value;
$condition .= sprintf("%s %s :%s", $mapping_or[0], $filter->getOperator(), sprintf($param_prefix, $param_idx));
++$param_idx;
}
$query->andWhere($condition);
}
else {
$mapping = explode(':', $mapping);
$value = $filter->getValue();
if (count($mapping) > 1) {
$value = $this->convertValue($value, $mapping[1]);
}
$bindings[sprintf($param_prefix, $param_idx)] = $value;
$query = $query->andWhere(sprintf("%s %s :%s", $mapping[0], $filter->getOperator(), sprintf($param_prefix, $param_idx)));
++$param_idx;
}
}
else if (is_array($filter)) {
// OR
$sub_or_query = '';
foreach ($filter as $e) {
if ($e instanceof FilterElement && isset($mappings[$e->getField()])) {
$mapping = $mappings[$e->getField()];
if ($mapping instanceof DoctrineJoinFilterMapping) {
$condition = $mapping->applyOr($query, $e);
if(!empty($sub_or_query)) $sub_or_query .= ' OR ';
$sub_or_query .= $condition;
continue;
}
if ($mapping instanceof DoctrineSwitchFilterMapping) {
$condition = $mapping->applyOr($query, $e);
if(!empty($sub_or_query)) $sub_or_query .= ' OR ';
$sub_or_query .= $condition;
continue;
}
if ($mapping instanceof DoctrineFilterMapping) {
$condition = $mapping->applyOr($query, $e);
if(!empty($sub_or_query)) $sub_or_query .= ' OR ';
$sub_or_query .= $condition;
continue;
}
else if(is_array($mapping)){
$condition = '';
foreach ($mapping as $mapping_or){
$mapping_or = explode(':', $mapping_or);
$value = $e->getValue();
if (count($mapping_or) > 1) {
$value = $this->convertValue($value, $mapping_or[1]);
}
if(!empty($condition)) $condition .= ' OR ';
$bindings[sprintf($param_prefix, $param_idx)] = $value;
$condition .= sprintf(" %s %s :%s ", $mapping_or[0], $e->getOperator(), sprintf($param_prefix, $param_idx));
++$param_idx;
}
if(!empty($sub_or_query)) $sub_or_query .= ' OR ';
$sub_or_query .= ' ( '.$condition.' ) ';
}
else {
$mapping = explode(':', $mapping);
$value = $e->getValue();
if (count($mapping) > 1) {
$value = $this->convertValue($value, $mapping[1]);
}
if(!empty($sub_or_query)) $sub_or_query .= ' OR ';
$bindings[sprintf($param_prefix, $param_idx)] = $value;
$sub_or_query .= sprintf(" %s %s :%s ", $mapping[0], $e->getOperator(), sprintf($param_prefix, $param_idx));
++$param_idx;
}
}
}
$query->andWhere($sub_or_query);
}
}
foreach($bindings as $param => $value)
$query->setParameter($param, $value);
return $this;
}
/**
* @param string $value
* @param string $original_format
* @return mixed
*/
private function convertValue($value, $original_format)
{
switch ($original_format) {
case 'datetime_epoch':
$datetime = new \DateTime("@$value");
return sprintf("%s", $datetime->format("Y-m-d H:i:s"));
break;
case 'json_int':
return intval($value);
break;
case 'json_string':
return sprintf("%s",$value);
break;
default:
return $value;
break;
}
}
/**
* @return array
*/
public function getSQLBindings()
{
return $this->bindings;
}
/**
* @param array $mappings
* @return string
*/
public function toRawSQL(array $mappings)
{
$sql = '';
$this->bindings = [];
foreach ($this->filters as $filter) {
if ($filter instanceof FilterElement) {
if (isset($mappings[$filter->getField()])) {
$mapping = $mappings[$filter->getField()];
$mapping = explode(':', $mapping);
$value = $filter->getValue();
$op = $filter->getOperator();
if (count($mapping) > 1) {
$filter->setValue($this->convertValue($value, $mapping[1]));
}
$cond = sprintf(' %s %s :%s', $mapping[0], $op, $filter->getField());
$this->bindings[$filter->getField()] = $filter->getValue();
if (!empty($sql)) $sql .= " AND ";
$sql .= $cond;
}
} else if (is_array($filter)) {
// OR
$sql .= " ( ";
$sql_or = '';
foreach ($filter as $e) {
if ($e instanceof FilterElement && isset($mappings[$e->getField()])) {
$mapping = $mappings[$e->getField()];
$mapping = explode(':', $mapping);
$value = $e->getValue();
$op = $e->getOperator();
if (count($mapping) > 1) {
$e->setValue($this->convertValue($value, $mapping[1]));
}
$cond = sprintf(" %s %s :%s", $mapping[0], $op, $e->getField());
$this->bindings[$e->getField()] = $e->getValue();
if (!empty($sql_or)) $sql_or .= " OR ";
$sql_or .= $cond;
}
}
$sql .= $sql_or . " ) ";
}
}
return $sql;
}
/**
* @param string $field
* @return array
*/
public function getFilterCollectionByField($field){
$list = [];
$filter = $this->getFilter($field);
if(is_array($filter)){
if(is_array($filter[0])){
foreach ($filter[0] as $filter_element)
$list[] = intval($filter_element->getValue());
}
else{
$list[] = intval($filter[0]->getValue());
}
}
return $list;
}
}