mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-05-09 03:52:15 +09:00
Finish work on condition parsing
This commit is contained in:
parent
6eca8736c1
commit
db13d110b8
2 changed files with 154 additions and 51 deletions
|
|
@ -5,7 +5,7 @@ namespace Rhymix\Framework\Parsers\DBQuery;
|
||||||
/**
|
/**
|
||||||
* Query class.
|
* Query class.
|
||||||
*/
|
*/
|
||||||
class Query
|
class Query extends VariableBase
|
||||||
{
|
{
|
||||||
public $name;
|
public $name;
|
||||||
public $alias;
|
public $alias;
|
||||||
|
|
@ -89,9 +89,9 @@ class Query
|
||||||
if ($column instanceof self)
|
if ($column instanceof self)
|
||||||
{
|
{
|
||||||
$subquery = $column->getQueryString($this->_prefix, $this->_args);
|
$subquery = $column->getQueryString($this->_prefix, $this->_args);
|
||||||
foreach ($column->getQueryParams() as $key => $val)
|
foreach ($column->getQueryParams() as $param)
|
||||||
{
|
{
|
||||||
$this->_params[$key] = $val;
|
$this->_params[] = $param;
|
||||||
}
|
}
|
||||||
$columns[] = sprintf('(%s) AS %s', $subquery, self::quoteName($column->alias));
|
$columns[] = sprintf('(%s) AS %s', $subquery, self::quoteName($column->alias));
|
||||||
}
|
}
|
||||||
|
|
@ -114,28 +114,31 @@ class Query
|
||||||
if ($table instanceof self)
|
if ($table instanceof self)
|
||||||
{
|
{
|
||||||
$subquery = $table->getQueryString($this->_prefix, $this->_args);
|
$subquery = $table->getQueryString($this->_prefix, $this->_args);
|
||||||
foreach ($table->getQueryParams() as $key => $val)
|
foreach ($table->getQueryParams() as $param)
|
||||||
{
|
{
|
||||||
$this->_params[$key] = $val;
|
$this->_params[] = $param;
|
||||||
}
|
}
|
||||||
$tables[] = sprintf('(%s) AS `%s`', $subquery, $table->alias);
|
$tables[] = (count($tables) ? ', ' : '') . sprintf('(%s) AS `%s`', $subquery, $table->alias);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$tabledef = self::quoteName($table->name) . ($table->alias ? (' AS `' . $table->alias . '`') : '');
|
$tabledef = self::quoteName($table->name) . ($table->alias ? (' AS `' . $table->alias . '`') : '');
|
||||||
if ($table->join_type)
|
if ($table->join_type)
|
||||||
{
|
{
|
||||||
$tabledef = $table->join_type . ' ' . $tabledef;
|
|
||||||
$join_where = $this->_arrangeConditions($table->join_conditions);
|
$join_where = $this->_arrangeConditions($table->join_conditions);
|
||||||
if ($join_where !== '')
|
if ($join_where !== '')
|
||||||
{
|
{
|
||||||
$tabledef = $tabledef . ' ON ' . $join_where;
|
$tabledef = $tabledef . ' ON ' . $join_where;
|
||||||
}
|
}
|
||||||
|
$tables[] = ' ' . $table->join_type . ' ' . $tabledef;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tables[] = (count($tables) ? ', ' : '') . $tabledef;
|
||||||
}
|
}
|
||||||
$tables[] = $tabledef;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$result .= ' FROM ' . implode(', ', $tables);
|
$result .= ' FROM ' . implode('', $tables);
|
||||||
|
|
||||||
// Compose the conditions.
|
// Compose the conditions.
|
||||||
if (count($this->conditions))
|
if (count($this->conditions))
|
||||||
|
|
@ -172,29 +175,31 @@ class Query
|
||||||
// Subquery
|
// Subquery
|
||||||
if ($condition instanceof self)
|
if ($condition instanceof self)
|
||||||
{
|
{
|
||||||
// TODO
|
$condition_string = $this->_parseCondition($condition);
|
||||||
|
if ($condition_string !== '')
|
||||||
|
{
|
||||||
|
$result .= ($result === '' ? '' : (' ' . $condition->pipe . ' ')) . $condition_string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Condition group
|
// Condition group
|
||||||
elseif ($condition instanceof ConditionGroup)
|
elseif ($condition instanceof ConditionGroup)
|
||||||
{
|
{
|
||||||
$condition_string = $this->_arrangeConditions($condition->conditions);
|
$condition_string = $this->_arrangeConditions($condition->conditions);
|
||||||
if ($condition_string === '')
|
if ($condition_string !== '')
|
||||||
{
|
{
|
||||||
continue;
|
$result .= ($result === '' ? '' : (' ' . $condition->pipe . ' ')) . '(' . $condition_string . ')';
|
||||||
}
|
}
|
||||||
$result .= ($result === '' ? '' : (' ' . $condition->pipe . ' ')) . '(' . $condition_string . ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple condition
|
// Simple condition
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$condition_string = $this->_parseCondition($condition);
|
$condition_string = $this->_parseCondition($condition);
|
||||||
if ($condition_string === '')
|
if ($condition_string !== '')
|
||||||
{
|
{
|
||||||
continue;
|
$result .= ($result === '' ? '' : (' ' . $condition->pipe . ' ')) . $condition_string;
|
||||||
}
|
}
|
||||||
$result .= ($result === '' ? '' : (' ' . $condition->pipe . ' ')) . $condition_string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,12 +213,12 @@ class Query
|
||||||
* @param object $condition
|
* @param object $condition
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function _parseCondition(Condition $condition): string
|
protected function _parseCondition(VariableBase $condition): string
|
||||||
{
|
{
|
||||||
list($where, $params) = $condition->getQueryStringAndParams($this->_args);
|
list($where, $params) = $condition->getQueryStringAndParams($this->_args, $this->_prefix);
|
||||||
foreach ($params as $key => $val)
|
foreach ($params as $param)
|
||||||
{
|
{
|
||||||
$this->_params[$key] = $val;
|
$this->_params[] = $param;
|
||||||
}
|
}
|
||||||
return $where;
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@ class VariableBase
|
||||||
* Convert an operator into real SQL.
|
* Convert an operator into real SQL.
|
||||||
*
|
*
|
||||||
* @param array $args
|
* @param array $args
|
||||||
|
* @param string $prefix
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getQueryStringAndParams(array $args): array
|
public function getQueryStringAndParams(array $args, string $prefix = ''): array
|
||||||
{
|
{
|
||||||
// Return if this method is called on an invalid child class.
|
// Return if this method is called on an invalid child class.
|
||||||
if (!isset($this->column) || !isset($this->operation))
|
if (!isset($this->column) || !isset($this->operation))
|
||||||
|
|
@ -27,15 +28,26 @@ class VariableBase
|
||||||
throw new \Rhymix\Framework\Exceptions\QueryError('Invalid invocation of getQueryStringAndParams()');
|
throw new \Rhymix\Framework\Exceptions\QueryError('Invalid invocation of getQueryStringAndParams()');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialze the return values.
|
||||||
|
$where = '';
|
||||||
|
$params = array();
|
||||||
|
|
||||||
// Process the variable or default value.
|
// Process the variable or default value.
|
||||||
if ($this->var && isset($args[$this->var]) && !empty($args[$this->var]))
|
if ($this->var && isset($args[$this->var]) && (!is_array($args[$this->var]) || count($args[$this->var]) > 1 || $args[$this->var] !== ['']))
|
||||||
{
|
{
|
||||||
$this->filterValue($args[$this->var]);
|
$this->filterValue($args[$this->var]);
|
||||||
|
$is_expression = false;
|
||||||
$value = $args[$this->var];
|
$value = $args[$this->var];
|
||||||
}
|
}
|
||||||
elseif ($this->default !== null)
|
elseif ($this->default !== null)
|
||||||
{
|
{
|
||||||
$value = $this->getDefaultValue();
|
list($is_expression, $value) = $this->getDefaultValue();
|
||||||
|
}
|
||||||
|
elseif ($this instanceof Query)
|
||||||
|
{
|
||||||
|
$is_expression = true;
|
||||||
|
$value = '(' . $this->getQueryString($prefix, $args) . ') AS ' . Query::quoteName($this->alias);
|
||||||
|
$params = $this->getQueryParams();
|
||||||
}
|
}
|
||||||
elseif ($this->not_null)
|
elseif ($this->not_null)
|
||||||
{
|
{
|
||||||
|
|
@ -43,13 +55,11 @@ class VariableBase
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return ['', []];
|
return [$where, $params];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quote the column name.
|
// Quote the column name.
|
||||||
$column = Query::quoteName($this->column);
|
$column = Query::quoteName($this->column);
|
||||||
$where = '';
|
|
||||||
$params = array();
|
|
||||||
|
|
||||||
// Prepare the target value.
|
// Prepare the target value.
|
||||||
$list_ops = array('in' => true, 'notin' => true, 'not_in' => true, 'between' => true);
|
$list_ops = array('in' => true, 'notin' => true, 'not_in' => true, 'between' => true);
|
||||||
|
|
@ -62,36 +72,93 @@ class VariableBase
|
||||||
switch ($this->operation)
|
switch ($this->operation)
|
||||||
{
|
{
|
||||||
case 'equal':
|
case 'equal':
|
||||||
$where = sprintf('%s = ?', $column);
|
$where = sprintf('%s = %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = $value;
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'notequal':
|
||||||
|
case 'not_equal':
|
||||||
|
$where = sprintf('%s != %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'more':
|
||||||
|
case 'gte':
|
||||||
|
$where = sprintf('%s >= %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'excess':
|
||||||
|
case 'gt';
|
||||||
|
$where = sprintf('%s > %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'less':
|
||||||
|
case 'lte':
|
||||||
|
$where = sprintf('%s <= %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'below':
|
||||||
|
case 'lt';
|
||||||
|
$where = sprintf('%s < %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'regexp';
|
||||||
|
$where = sprintf('%s REGEXP %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
|
break;
|
||||||
|
case 'notregexp';
|
||||||
|
case 'not_regexp';
|
||||||
|
$where = sprintf('%s NOT REGEXP %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = $value;
|
||||||
break;
|
break;
|
||||||
case 'like':
|
case 'like':
|
||||||
$where = sprintf('%s LIKE ?', $column);
|
$where = sprintf('%s LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = '%' . $value . '%';
|
if (!$is_expression) $params[] = '%' . $value . '%';
|
||||||
break;
|
break;
|
||||||
case 'like_prefix':
|
case 'like_prefix':
|
||||||
case 'like_head':
|
case 'like_head':
|
||||||
$where = sprintf('%s LIKE ?', $column);
|
$where = sprintf('%s LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = $value . '%';
|
if (!$is_expression) $params[] = $value . '%';
|
||||||
break;
|
break;
|
||||||
case 'like_suffix':
|
case 'like_suffix':
|
||||||
case 'like_tail':
|
case 'like_tail':
|
||||||
$where = sprintf('%s LIKE ?', $column);
|
$where = sprintf('%s LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = '%' . $value;
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
break;
|
break;
|
||||||
case 'notlike':
|
case 'notlike':
|
||||||
$where = sprintf('%s NOT LIKE ?', $column);
|
$where = sprintf('%s NOT LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = '%' . $value . '%';
|
if (!$is_expression) $params[] = '%' . $value . '%';
|
||||||
break;
|
break;
|
||||||
case 'notlike_prefix':
|
case 'notlike_prefix':
|
||||||
case 'notlike_head':
|
case 'notlike_head':
|
||||||
$where = sprintf('%s NOT LIKE ?', $column);
|
$where = sprintf('%s NOT LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = $value . '%';
|
if (!$is_expression) $params[] = $value . '%';
|
||||||
break;
|
break;
|
||||||
case 'notlike_suffix':
|
case 'notlike_suffix':
|
||||||
case 'notlike_tail':
|
case 'notlike_tail':
|
||||||
$where = sprintf('%s NOT LIKE ?', $column);
|
$where = sprintf('%s NOT LIKE %s', $column, $is_expression ? $value : '?');
|
||||||
$params[] = '%' . $value;
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
|
break;
|
||||||
|
case 'and':
|
||||||
|
$where = sprintf('%s & %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
|
break;
|
||||||
|
case 'or':
|
||||||
|
$where = sprintf('%s | %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
|
break;
|
||||||
|
case 'xor':
|
||||||
|
$where = sprintf('%s ^ %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
|
break;
|
||||||
|
case 'not':
|
||||||
|
$where = sprintf('%s ~ %s', $column, $is_expression ? $value : '?');
|
||||||
|
if (!$is_expression) $params[] = '%' . $value;
|
||||||
|
break;
|
||||||
|
case 'null':
|
||||||
|
$where = sprintf('%s IS NULL', $column);
|
||||||
|
break;
|
||||||
|
case 'notnull':
|
||||||
|
case 'not_null':
|
||||||
|
$where = sprintf('%s IS NOT NULL', $column);
|
||||||
break;
|
break;
|
||||||
case 'in':
|
case 'in':
|
||||||
$count = count($value);
|
$count = count($value);
|
||||||
|
|
@ -119,6 +186,37 @@ class VariableBase
|
||||||
$params[] = $item;
|
$params[] = $item;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'notbetween':
|
||||||
|
case 'not_between':
|
||||||
|
$where = sprintf('%s NOT BETWEEN ? AND ?', $column);
|
||||||
|
foreach ($value as $item)
|
||||||
|
{
|
||||||
|
$params[] = $item;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'search':
|
||||||
|
$keywords = preg_split('/[\s,]+/', $value, 10, \PREG_SPLIT_NO_EMPTY);
|
||||||
|
$conditions = array();
|
||||||
|
$placeholders = implode(', ', array_fill(0, count($keywords), '?'));
|
||||||
|
foreach ($keywords as $item)
|
||||||
|
{
|
||||||
|
if (substr($item, 0, 1) === '-')
|
||||||
|
{
|
||||||
|
$conditions[] = sprintf('%s NOT LIKE ?', $column);
|
||||||
|
$item = substr($item, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$conditions[] = sprintf('%s LIKE ?', $column);
|
||||||
|
}
|
||||||
|
$params[] = '%' . str_replace(['\\', '_', '%'], ['\\\\', '\_', '\%'], $item) . '%';
|
||||||
|
}
|
||||||
|
$conditions = implode(' AND ', $conditions);
|
||||||
|
$where = count($keywords) === 1 ? $conditions : "($conditions)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$where = sprintf('%s = ?', $column);
|
||||||
|
$params[] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the complete condition and parameters.
|
// Return the complete condition and parameters.
|
||||||
|
|
@ -128,32 +226,32 @@ class VariableBase
|
||||||
/**
|
/**
|
||||||
* Get the default value of this variable.
|
* Get the default value of this variable.
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getDefaultValue()
|
public function getDefaultValue()
|
||||||
{
|
{
|
||||||
// If the default value is a column name, escape it.
|
// If the default value is a column name, escape it.
|
||||||
if (preg_match('/^[a-z0-9_]+(?:\.[a-z0-9_]+)+$/', $this->default))
|
if (preg_match('/^[a-z0-9_]+(?:\.[a-z0-9_]+)+$/', $this->default))
|
||||||
{
|
{
|
||||||
return Query::quoteName($this->default);
|
return [true, Query::quoteName($this->default)];
|
||||||
}
|
}
|
||||||
elseif (isset($this->column) && preg_match('/_srl$/', $this->column) && !ctype_digit($this->default))
|
elseif (isset($this->column) && preg_match('/_srl$/', $this->column) && !ctype_digit($this->default))
|
||||||
{
|
{
|
||||||
return Query::quoteName($this->default);
|
return [true, Query::quoteName($this->default)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the default value is a function shortcut, return an appropriate value.
|
// If the default value is a function shortcut, return an appropriate value.
|
||||||
switch ($this->default)
|
switch ($this->default)
|
||||||
{
|
{
|
||||||
case 'ipaddress()':
|
case 'ipaddress()':
|
||||||
return "'" . \RX_CLIENT_IP . "'";
|
return [false, \RX_CLIENT_IP];
|
||||||
case 'unixtime()':
|
case 'unixtime()':
|
||||||
return time();
|
return [false, time()];
|
||||||
case 'curdate()':
|
case 'curdate()':
|
||||||
case 'date()':
|
case 'date()':
|
||||||
return "'" . date('YmdHis') . "'";
|
return [false, date('YmdHis')];
|
||||||
case 'sequence()':
|
case 'sequence()':
|
||||||
return getNextSequence();
|
return [false, getNextSequence()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the default value is a calculation based on the current value, return a query string.
|
// If the default value is a calculation based on the current value, return a query string.
|
||||||
|
|
@ -162,16 +260,16 @@ class VariableBase
|
||||||
switch ($matches[1])
|
switch ($matches[1])
|
||||||
{
|
{
|
||||||
case 'plus':
|
case 'plus':
|
||||||
return sprintf('%s + %d', Query::quoteName($this->column), $matches[2]);
|
return [true, sprintf('%s + %d', Query::quoteName($this->column), $matches[2])];
|
||||||
case 'minus':
|
case 'minus':
|
||||||
return sprintf('%s - %d', Query::quoteName($this->column), $matches[2]);
|
return [true, sprintf('%s - %d', Query::quoteName($this->column), $matches[2])];
|
||||||
case 'multiply':
|
case 'multiply':
|
||||||
return sprintf('%s * %d', Query::quoteName($this->column), $matches[2]);
|
return [true, sprintf('%s * %d', Query::quoteName($this->column), $matches[2])];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, just return the literal value.
|
// Otherwise, just return the literal value.
|
||||||
return $this->default;
|
return [false, $this->default];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue