增加Expression类及相关方法

This commit is contained in:
thinkphp
2018-04-12 09:25:46 +08:00
parent 5d3c891a39
commit 8ae0fdef46
8 changed files with 169 additions and 19 deletions

View File

@@ -1093,7 +1093,7 @@ class Request
public function filterExp(&$value)
{
// 过滤查询特殊字符
if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {
if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOT EXISTS|NOTEXISTS|EXISTS|NOT NULL|NOTNULL|NULL|BETWEEN TIME|NOT BETWEEN TIME|NOTBETWEEN TIME|NOTIN|NOT IN|IN)$/i', $value)) {
$value .= ' ';
}
// TODO 其他安全过滤

View File

@@ -99,8 +99,11 @@ abstract class Builder
$result = [];
foreach ($data as $key => $val) {
$item = $this->parseKey($key, $options);
if (is_object($val) && method_exists($val, '__toString')) {
$item = $this->parseKey($key, $options, true);
if ($val instanceof Expression) {
$result[$item] = $val->getValue();
continue;
} elseif (is_object($val) && method_exists($val, '__toString')) {
// 对象数据写入
$val = $val->__toString();
}
@@ -143,7 +146,7 @@ abstract class Builder
* @param array $options
* @return string
*/
protected function parseKey($key, $options = [])
protected function parseKey($key, $options = [], $strict = false)
{
return $key;
}
@@ -184,10 +187,12 @@ abstract class Builder
// 支持 'field1'=>'field2' 这样的字段别名定义
$array = [];
foreach ($fields as $key => $field) {
if (!is_numeric($key)) {
$array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options);
if ($field instanceof Expression) {
$array[] = $field->getValue();
} elseif (!is_numeric($key)) {
$array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options, true);
} else {
$array[] = $this->parseKey($field, $options);
$array[] = $this->parseKey($field, $options, true);
}
}
$fieldsStr = implode(',', $array);
@@ -264,6 +269,10 @@ abstract class Builder
foreach ($where as $key => $val) {
$str = [];
foreach ($val as $field => $value) {
if ($value instanceof Expression) {
$str[] = ' ' . $logic . ' ( ' . $value->getValue() . ' )';
continue;
}
if ($value instanceof \Closure) {
// 使用闭包查询
$query = new Query($this->connection);
@@ -305,7 +314,7 @@ abstract class Builder
protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)
{
// 字段分析
$key = $field ? $this->parseKey($field, $options) : '';
$key = $field ? $this->parseKey($field, $options, true) : '';
// 查询规则和条件
if (!is_array($val)) {
@@ -344,7 +353,9 @@ abstract class Builder
$bindName = md5($bindName);
}
if (is_object($value) && method_exists($value, '__toString')) {
if ($value instanceof Expression) {
} elseif (is_object($value) && method_exists($value, '__toString')) {
// 对象数据写入
$value = $value->__toString();
}
@@ -556,7 +567,9 @@ abstract class Builder
if (is_array($order)) {
$array = [];
foreach ($order as $key => $val) {
if (is_numeric($key)) {
if ($val instanceof Expression) {
$array[] = $val->getValue();
} elseif (is_numeric($key)) {
if ('[rand]' == $val) {
if (method_exists($this, 'parseRand')) {
$array[] = $this->parseRand();

View File

@@ -0,0 +1,48 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace think\db;
class Expression
{
/**
* 查询表达式
*
* @var string
*/
protected $value;
/**
* 创建一个查询表达式
*
* @param string $value
* @return void
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* 获取表达式
*
* @return string
*/
public function getValue()
{
return $this->value;
}
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -800,6 +800,24 @@ class Query
return $this;
}
/**
* 表达式方式指定查询字段
* @access public
* @param string $field 字段名
* @param array $bind 参数绑定
* @return $this
*/
public function fieldRaw($field, array $bind = [])
{
$this->options['field'][] = $this->raw($field);
if ($bind) {
$this->bind($bind);
}
return $this;
}
/**
* 设置数据
* @access public
@@ -862,6 +880,17 @@ class Query
return $this;
}
/**
* 使用表达式设置数据
* @access public
* @param mixed $value 表达式
* @return Expression
*/
public function raw($value)
{
return new Expression($value);
}
/**
* 指定JOIN查询字段
* @access public
@@ -975,6 +1004,37 @@ class Query
return $this;
}
/**
* 指定表达式查询条件
* @access public
* @param string $where 查询条件
* @param array $bind 参数绑定
* @param string $logic 查询逻辑 and or xor
* @return $this
*/
public function whereRaw($where, $bind = [], $logic = 'AND')
{
$this->options['where'][$logic][] = $this->raw($where);
if ($bind) {
$this->bind($bind);
}
return $this;
}
/**
* 指定表达式查询条件 OR
* @access public
* @param string $where 查询条件
* @param array $bind 参数绑定
* @return $this
*/
public function whereOrRaw($where, $bind = [])
{
return $this->whereRaw($where, $bind, 'OR');
}
/**
* 指定Null查询条件
* @access public
@@ -1163,7 +1223,9 @@ class Query
$field = $this->options['via'] . '.' . $field;
}
if ($strict) {
if ($field instanceof Expression) {
return $this->whereRaw($field, is_array($op) ? $op : []);
} elseif ($strict) {
// 使用严格模式查询
$where[$field] = [$op, $condition];
@@ -1451,6 +1513,24 @@ class Query
return $this;
}
/**
* 表达式方式指定Field排序
* @access public
* @param string $field 排序字段
* @param array $bind 参数绑定
* @return $this
*/
public function orderRaw($field, array $bind = [])
{
$this->options['order'][] = $this->raw($field);
if ($bind) {
$this->bind($bind);
}
return $this;
}
/**
* 查询缓存
* @access public

View File

@@ -86,13 +86,16 @@ class Mysql extends Builder
* @param array $options
* @return string
*/
protected function parseKey($key, $options = [])
protected function parseKey($key, $options = [], $strict = false)
{
if (is_int($key)) {
return $key;
}
$key = trim($key);
if (strpos($key, '$.') && false === strpos($key, '(')) {
// JSON字段支持
list($field, $name) = explode('$.', $key);
$key = 'json_extract(' . $field . ', \'$.' . $name . '\')';
return 'json_extract(' . $field . ', \'$.' . $name . '\')';
} elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
list($table, $key) = explode('.', $key, 2);
if ('__TABLE__' == $table) {
@@ -102,7 +105,7 @@ class Mysql extends Builder
$table = $options['alias'][$table];
}
}
if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
if ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
$key = '`' . $key . '`';
}
if (isset($table)) {

View File

@@ -48,7 +48,7 @@ class Pgsql extends Builder
* @param array $options
* @return string
*/
protected function parseKey($key, $options = [])
protected function parseKey($key, $options = [], $strict = false)
{
$key = trim($key);
if (strpos($key, '$.') && false === strpos($key, '(')) {

View File

@@ -56,7 +56,7 @@ class Sqlite extends Builder
* @param array $options
* @return string
*/
protected function parseKey($key, $options = [])
protected function parseKey($key, $options = [], $strict = false)
{
$key = trim($key);
if (strpos($key, '.')) {

View File

@@ -12,6 +12,7 @@
namespace think\db\builder;
use think\db\Builder;
use think\db\Expression;
/**
* Sqlsrv数据库驱动
@@ -37,7 +38,9 @@ class Sqlsrv extends Builder
if (is_array($order)) {
$array = [];
foreach ($order as $key => $val) {
if (is_numeric($key)) {
if ($val instanceof Expression) {
$array[] = $val->getValue();
} elseif (is_numeric($key)) {
if (false === strpos($val, '(')) {
$array[] = $this->parseKey($val, $options);
} elseif ('[rand]' == $val) {
@@ -72,8 +75,11 @@ class Sqlsrv extends Builder
* @param array $options
* @return string
*/
protected function parseKey($key, $options = [])
protected function parseKey($key, $options = [], $strict = false)
{
if (is_int($key)) {
return $key;
}
$key = trim($key);
if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) {
list($table, $key) = explode('.', $key, 2);
@@ -84,7 +90,7 @@ class Sqlsrv extends Builder
$table = $options['alias'][$table];
}
}
if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
if ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
$key = '[' . $key . ']';
}
if (isset($table)) {