Skip to content

Commit

Permalink
updates QueryBulderTrait to handle Complex Where expressions from Req…
Browse files Browse the repository at this point in the history
…uestParserTrait construction
  • Loading branch information
phpboyscout committed Nov 24, 2015
1 parent e90123d commit f15b132
Showing 1 changed file with 140 additions and 108 deletions.
248 changes: 140 additions & 108 deletions src/ZucchiDoctrine/Query/QueryBuilderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,131 +37,163 @@ protected function addWhere($qb, $where)
{
// process the $where
if (is_string($where)) {
// straight DQL string
// @todo: test and provide security for straight DQL string
$qb->andWhere($where);

} elseif (is_array($where) && count($where)) {
// create where expression
$whereExp = $qb->expr()->andx();
$params = array();

$params = array(); // initialise container to store params

$whereExp = $this->getParts($qb, $where, $params);

// index for the parameters
$i = 0;
// only add where expression if actually has parts
if (count($whereExp->getParts())) {
$qb->where($whereExp);
}

// loop through all the clauses supplied
foreach ($where as $col => $val) {

if ((is_array($val) && (!isset($val['value']) || (is_string($val['value']) && strlen($val['value']) == 0))) ||
(is_string($val) && (!$val || strlen($val) == 0))
){
// skip if invalid value;
continue;
}

// check if we've been provided with an operator as well as a value
if (!is_array($val)) {
$operator = Expr\Comparison::EQ;
$val = $val;
} elseif (count($val) == 1) {
$operator = Expr\Comparison::EQ;
$val = end($val);
} else {
$operator = isset($val['operator']) ? $val['operator'] : Expr\Comparison::EQ;
$val = array_key_exists('value', $val) ? $val['value'] : array();

}

// set the alias to the default
$alias = $this->alias;
// set the params from the where clause above
$qb->setParameters($params);
}

return $this;
}

// if col relates to a relation i.e. Role.id
// then perform a join and set up the alias and column names
if (strpos($col, '.') !== false) {
$parts = explode('.', $col);
$col = array_pop($parts);
$par = $this->alias;

foreach ($parts AS $rel) {
$alias = strtolower($rel);
$jt = new Expr\Join(Expr\Join::LEFT_JOIN, $par . '.' . $rel, $alias);
if (!strpos($qb->getDql(), $jt->__toString()) !== false) {
$qb->leftJoin($par . '.' . $rel, $alias);
}
$par = $alias;

protected function getParts($qb, $where, &$params = array())
{
if (array_key_exists('mode', $where) && $where['mode'] == 'or') {
$whereExp = $qb->expr()->orX();
} else {
$whereExp = $qb->expr()->andX();
}
unset($where['mode']); // unset to allow flat iteration for simpler structures

// index for the parameters
$i = count($params);

if (array_key_exists('expressions', $where)) {
foreach($where['expressions'] as $expression) {
$part = $this->getParts($qb, $expression, $params);
$whereExp->add($part);
}
unset($where['expressions']); // unset to allow flat iteration for simpler structures
}

// set fields to iterate over if no fields property assume using remaining elements in $where
$fields = (array_key_exists('fields', $where)) ? $where['fields'] : $where;

// loop through all the clauses supplied
foreach ($fields as $col => $val) {

if ((is_array($val) && (!isset($val['value']) || (is_string($val['value']) && strlen($val['value']) == 0))) ||
(is_string($val) && (!$val || strlen($val) == 0))
){
// skip if invalid value;
continue;
}

// check if we've been provided with an operator as well as a value
if (!is_array($val)) {
$operator = Expr\Comparison::EQ;
$val = $val;
} elseif (count($val) == 1) {
$operator = Expr\Comparison::EQ;
$val = end($val);
} else {
$operator = isset($val['operator']) ? $val['operator'] : Expr\Comparison::EQ;
$val = array_key_exists('value', $val) ? $val['value'] : array();

}

// set the alias to the default
$alias = $this->alias;

// if col relates to a relation i.e. Role.id
// then perform a join and set up the alias and column names
if (strpos($col, '.') !== false) {
$parts = explode('.', $col);
$col = array_pop($parts);
$par = $this->alias;

foreach ($parts AS $rel) {
$alias = strtolower($rel);
$jt = new Expr\Join(Expr\Join::LEFT_JOIN, $par . '.' . $rel, $alias);
if (!strpos($qb->getDql(), $jt->__toString()) !== false) {
$qb->leftJoin($par . '.' . $rel, $alias);
}
$par = $alias;
}
}

if ($val instanceof Expr\Base) {
$whereExp->add($val);
} else {
// process sets a little differently
if (!is_array($val)) {
$val = array($val);
}
switch ($operator) {
case 'regexp':
$whereExp->add("REGEXP(" . $alias . '.' . $col . ",'" . $val[0] . "') = 1");
break;
case 'between':
if (count($val) == 2) {
// $value should now be an array with 2 values
$expr = new Expr();
$from = (is_int($val[0])) ? $val[0] : "'" . $val[0] . "'";
$to = (is_int($val[1])) ? $val[1] : "'" . $val[1] . "'";

$stmt = $expr->between($alias . '.' . $col, $from, $to);
$whereExp->add($stmt);
}
break;
case 'is':
if ($val instanceof Expr\Base) {
$whereExp->add($val);
} else {
// process sets a little differently
if (!is_array($val)) {
$val = array($val);
}
switch (strtolower($operator)) {
case 'regexp':
$whereExp->add("REGEXP(" . $alias . '.' . $col . ",'" . $val[0] . "') = 1");
break;
case 'between':
if (count($val) == 2) {
// $value should now be an array with 2 values
$expr = new Expr();
$method = 'is' . ucfirst($val[0]);
if (method_exists($expr, $method)) {
$stmt = $expr->{$method}($alias . '.' . $col);
$whereExp->add($stmt);
}
break;
default:
// this holds the subquery for this field, each component being an OR
$subWhereExp = $qb->expr()->orX();

foreach ($val as $value) {
if ($value == null) {
$cmpValue = 'NULL';
} else {
$cmpValue = '?' . $i;

// wrap LIKE values
if ($operator == 'like') {
$value = '%' . trim($value, '%') . '%';
}

// add the parameter value into the parameters stack
$params[$i] = $value;
$i++;
$from = (is_int($val[0])) ? $val[0] : "'" . $val[0] . "'";
$to = (is_int($val[1])) ? $val[1] : "'" . $val[1] . "'";

$stmt = $expr->between($alias . '.' . $col, $from, $to);
$whereExp->add($stmt);
}
break;
case 'is':
$expr = new Expr();
$method = 'is' . ucfirst($val[0]);
if (method_exists($expr, $method)) {
$stmt = $expr->{$method}($alias . '.' . $col);
$whereExp->add($stmt);
}
break;
default:
// this holds the subquery for this field, each component being an OR
$subWhereExp = $qb->expr()->orX();

foreach ($val as $value) {
if ($value == null) {
$cmpValue = 'NULL';
} else {
$cmpValue = '?' . $i;

// wrap IN/NOT IN values with parenthesis
if ($operator == 'in' || $operator == 'not in') {
$cmpValue = '(' . trim($cmpValue, ')') . ')';
}

$comparison = new Expr\Comparison($alias . '.' . $col, $operator, $cmpValue);
$subWhereExp->add($comparison);
// wrap LIKE values
if ($operator == 'like') {
$value = '%' . trim($value, '%') . '%';
}

// add the parameter value into the parameters stack
$params[$i] = $value;
$i++;
}

// add in the subquery as an AND
$whereExp->add($subWhereExp);
break;
$comparison = new Expr\Comparison($alias . '.' . $col, $operator, $cmpValue);
$subWhereExp->add($comparison);
}

// add in the subquery as an AND
$whereExp->add($subWhereExp);
break;

}
}
}

// only add where expression if actually has parts
if (count($whereExp->getParts())) {
$qb->where($whereExp);
}

// set the params from the where clause above
$qb->setParameters($params);
}

return $this;

return $whereExp;

}

/**
Expand Down

0 comments on commit f15b132

Please sign in to comment.