From 3a6802216ef8e94d42701d18a3d62da09e984dbe Mon Sep 17 00:00:00 2001 From: molong Date: Wed, 14 Sep 2016 13:39:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E6=A0=B8=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/library/think/Model.php | 3 ++ core/library/think/Request.php | 28 +++++++++++ core/library/think/Route.php | 27 ++++++----- core/library/think/db/Builder.php | 60 +++++++++++++++++++----- core/library/think/db/Connection.php | 12 +++-- core/library/think/log/driver/File.php | 2 +- core/library/think/model/Merge.php | 16 +++---- core/library/think/response/Redirect.php | 18 +++++++ core/library/traits/model/SoftDelete.php | 13 +++-- 9 files changed, 136 insertions(+), 43 deletions(-) diff --git a/core/library/think/Model.php b/core/library/think/Model.php index 98eacc8a..f1c91582 100644 --- a/core/library/think/Model.php +++ b/core/library/think/Model.php @@ -326,6 +326,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $value = date($format, $_SERVER['REQUEST_TIME']); break; case 'timestamp': + case 'int': $value = $_SERVER['REQUEST_TIME']; break; } @@ -1067,6 +1068,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } elseif ($data instanceof \Closure) { call_user_func_array($data, [ & $query]); $data = null; + } elseif (is_null($data)) { + return 0; } $resultSet = $query->select($data); $count = 0; diff --git a/core/library/think/Request.php b/core/library/think/Request.php index c34a4b14..a73b4fa5 100644 --- a/core/library/think/Request.php +++ b/core/library/think/Request.php @@ -115,6 +115,8 @@ class Request protected $filter; // Hook扩展方法 protected static $hook = []; + // 绑定的属性 + protected $bind = []; /** * 架构函数 @@ -1436,4 +1438,30 @@ class Request Session::set($name, $token); return $token; } + + /** + * 设置当前请求绑定的对象实例 + * @access public + * @param string $name 绑定的对象标识 + * @param mixed $obj 绑定的对象实例 + * @return mixed + */ + public function bind($name, $obj = null) + { + if (is_array($name)) { + $this->bind = array_merge($this->bind, $name); + } else { + $this->bind[$name] = $obj; + } + } + + public function __set($name, $value) + { + $this->bind[$name] = $value; + } + + public function __get($name) + { + return isset($this->bind[$name]) ? $this->bind[$name] : null; + } } diff --git a/core/library/think/Route.php b/core/library/think/Route.php index dfbb5b81..8e37bfc0 100644 --- a/core/library/think/Route.php +++ b/core/library/think/Route.php @@ -32,10 +32,10 @@ class Route 'HEAD' => [], 'OPTIONS' => [], '*' => [], - 'map' => [], 'alias' => [], 'domain' => [], 'pattern' => [], + 'name' => [], ]; // REST路由操作方法定义 @@ -63,8 +63,6 @@ class Route private static $bind = []; // 当前分组信息 private static $group = []; - // 路由命名标识(用于快速URL生成) - private static $name = []; // 当前子域名绑定 private static $domainBind; private static $domainRule; @@ -137,19 +135,22 @@ class Route } /** - * 设置路由绑定 + * 设置或者获取路由标识 * @access public * @param string|array $name 路由命名标识 数组表示批量设置 + * @param array $value 路由地址及变量信息 * @return array */ - public static function name($name = '') + public static function name($name = '', $value = null) { if (is_array($name)) { - return self::$name = $name; + return self::$rules['name'] = $name; } elseif ('' === $name) { - return self::$name; + return self::$rules['name']; + } elseif (!is_null($value)) { + self::$rules['name'][$name][] = $value; } else { - return isset(self::$name[$name]) ? self::$name[$name] : null; + return isset(self::$rules['name'][$name]) ? self::$rules['name'][$name] : null; } } @@ -304,7 +305,7 @@ class Route } $vars = self::parseVar($rule); if (isset($name)) { - self::$name[$name][] = [$rule, $vars, self::$domain]; + self::name($name, [$rule, $vars, self::$domain]); } if ($group) { if ('*' != $type) { @@ -424,7 +425,7 @@ class Route $vars = self::parseVar($key); $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns]; // 设置路由标识 - self::$name[$route][] = [$key, $vars, self::$domain]; + self::name($route, [$key, $vars, self::$domain]); } self::$rules['*'][$name] = ['rule' => $item, 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern]; } @@ -683,7 +684,7 @@ class Route return true === $rules ? self::$rules : self::$rules[$rules]; } else { $rules = self::$rules; - unset($rules['pattern'], $rules['alias'], $rules['domain']); + unset($rules['pattern'], $rules['alias'], $rules['domain'], $rules['name']); return $rules; } } @@ -1177,7 +1178,7 @@ class Route self::parseUrlParams(empty($path) ? '' : implode('/', $path)); // 封装路由 $route = [$module, $controller, $action]; - if (isset(self::$name[implode($depr, $route)])) { + if (isset(self::$rules['name'][implode($depr, $route)])) { throw new HttpException(404, 'invalid request:' . $url); } } @@ -1367,7 +1368,7 @@ class Route $bind[$key] = $result; } } - $matches = array_merge($matches, $bind); + Request::instance()->bind($bind); } // 解析额外参数 diff --git a/core/library/think/db/Builder.php b/core/library/think/db/Builder.php index 8fa87d39..7a531e62 100644 --- a/core/library/think/db/Builder.php +++ b/core/library/think/db/Builder.php @@ -222,6 +222,7 @@ abstract class Builder } $whereStr = ''; + $binds = $this->query->getFieldsBind($options); foreach ($where as $key => $val) { $str = []; foreach ($val as $field => $value) { @@ -235,7 +236,7 @@ abstract class Builder $array = explode('|', $field); $item = []; foreach ($array as $k) { - $item[] = $this->parseWhereItem($k, $value, '', $options); + $item[] = $this->parseWhereItem($k, $value, '', $options, $binds); } $str[] = ' ' . $key . ' ( ' . implode(' OR ', $item) . ' )'; } elseif (strpos($field, '&')) { @@ -243,13 +244,13 @@ abstract class Builder $array = explode('&', $field); $item = []; foreach ($array as $k) { - $item[] = $this->parseWhereItem($k, $value, '', $options); + $item[] = $this->parseWhereItem($k, $value, '', $options, $binds); } $str[] = ' ' . $key . ' ( ' . implode(' AND ', $item) . ' )'; } else { // 对字段使用表达式查询 $field = is_string($field) ? $field : ''; - $str[] = ' ' . $key . ' ' . $this->parseWhereItem($field, $value, $key, $options); + $str[] = ' ' . $key . ' ' . $this->parseWhereItem($field, $value, $key, $options, $binds); } } @@ -259,7 +260,7 @@ abstract class Builder } // where子单元分析 - protected function parseWhereItem($field, $val, $rule = '', $options = []) + protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null) { // 字段分析 $key = $field ? $this->parseKey($field) : ''; @@ -279,8 +280,9 @@ abstract class Builder } else { array_push($val, $item); } - foreach ($val as $item) { - $str[] = $this->parseWhereItem($key, $item, $rule, $options); + foreach ($val as $k => $item) { + $bindName = 'where_' . str_replace('.', '_', $field) . '_' . $k; + $str[] = $this->parseWhereItem($field, $item, $rule, $options, $binds, $bindName); } return '( ' . implode(' ' . $rule . ' ', $str) . ' )'; } @@ -294,6 +296,14 @@ abstract class Builder throw new Exception('where express error:' . $exp); } } + $bindName = $bindName ?: 'where_' . str_replace('.', '_', $field); + $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR; + if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) { + if (strpos($value, ':') !== 0 || !$this->query->isBind(substr($value, 1))) { + $this->query->bind($bindName, $value, $bindType); + $value = ':' . $bindName; + } + } $whereStr = ''; if (in_array($exp, ['=', '<>', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE'])) { @@ -311,13 +321,34 @@ abstract class Builder $whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value); } else { $value = is_array($value) ? $value : explode(',', $value); - $zone = implode(',', $this->parseValue($value, $field)); + if (array_key_exists($field, $binds)) { + $bind = []; + $array = []; + foreach ($value as $k => $v) { + $bind[$bindName . '_in_' . $k] = [$v, $bindType]; + $array[] = ':' . $bindName . '_in_' . $k; + } + $this->query->bind($bind); + $zone = implode(',', $array); + } else { + $zone = implode(',', $this->parseValue($value, $field)); + } $whereStr .= $key . ' ' . $exp . ' (' . $zone . ')'; } } elseif (in_array($exp, ['NOT BETWEEN', 'BETWEEN'])) { // BETWEEN 查询 $data = is_array($value) ? $value : explode(',', $value); - $whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($data[0], $field) . ' AND ' . $this->parseValue($data[1], $field); + if (array_key_exists($field, $binds)) { + $bind = [ + $bindName . '_between_1' => [$data[0], $bindType], + $bindName . '_between_2' => [$data[1], $bindType], + ]; + $this->query->bind($bind); + $between = ':' . $bindName . '_between_1' . ' AND :' . $bindName . '_between_2'; + } else { + $between = $this->parseValue($data[0], $field) . ' AND ' . $this->parseValue($data[1], $field); + } + $whereStr .= $key . ' ' . $exp . ' ' . $between; } elseif (in_array($exp, ['NOT EXISTS', 'EXISTS'])) { // EXISTS 查询 if ($value instanceof \Closure) { @@ -326,12 +357,13 @@ abstract class Builder $whereStr .= $exp . ' (' . $value . ')'; } } elseif (in_array($exp, ['< TIME', '> TIME', '<= TIME', '>= TIME'])) { - $whereStr .= $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($value, $field, $options); + $whereStr .= $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($value, $field, $options, $bindName, $bindType); } elseif (in_array($exp, ['BETWEEN TIME', 'NOT BETWEEN TIME'])) { if (is_string($value)) { $value = explode(',', $value); } - $whereStr .= $key . ' ' . substr($exp, 0, -4) . $this->parseDateTime($value[0], $field, $options) . ' AND ' . $this->parseDateTime($value[1], $field, $options); + + $whereStr .= $key . ' ' . substr($exp, 0, -4) . $this->parseDateTime($value[0], $field, $options, $bindName . '_between_1', $bindType) . ' AND ' . $this->parseDateTime($value[1], $field, $options, $bindName . '_between_2', $bindType); } return $whereStr; } @@ -350,9 +382,11 @@ abstract class Builder * @param string $value * @param string $key * @param array $options + * @param string $bindName + * @param integer $bindType * @return string */ - protected function parseDateTime($value, $key, $options = []) + protected function parseDateTime($value, $key, $options = [], $bindName = null, $bindType = null) { // 获取时间字段类型 $type = $this->query->getFieldsType($options); @@ -369,7 +403,9 @@ abstract class Builder $value = date('Y-m-d', $value); } } - return is_int($value) ? $value : $this->connection->quote($value); + $bindName = $bindName ?: $key; + $this->query->bind($bindName, $value, $bindType); + return ':' . $bindName; } /** diff --git a/core/library/think/db/Connection.php b/core/library/think/db/Connection.php index 6cbbd525..a69f1dd6 100644 --- a/core/library/think/db/Connection.php +++ b/core/library/think/db/Connection.php @@ -412,13 +412,17 @@ abstract class Connection { if ($bind) { foreach ($bind as $key => $val) { - $val = $this->quote(is_array($val) ? $val[0] : $val); + $value = is_array($val) ? $val[0] : $val; + $type = is_array($val) ? $val[1] : PDO::PARAM_STR; + if (PDO::PARAM_STR == $type) { + $value = $this->quote($value); + } // 判断占位符 $sql = is_numeric($key) ? - substr_replace($sql, $val, strpos($sql, '?'), 1) : + substr_replace($sql, $value, strpos($sql, '?'), 1) : str_replace( [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '], - [$val . ')', $val . ',', $val . ' '], + [$value . ')', $value . ',', $value . ' '], $sql . ' '); } } @@ -736,7 +740,7 @@ abstract class Connection * @param bool $master 是否主库查询 * @return string */ - public function quote($str, $master = false) + public function quote($str, $master = true) { $this->initConnect($master); return $this->linkID ? $this->linkID->quote($str) : $str; diff --git a/core/library/think/log/driver/File.php b/core/library/think/log/driver/File.php index 995ef260..c4e46279 100644 --- a/core/library/think/log/driver/File.php +++ b/core/library/think/log/driver/File.php @@ -79,7 +79,7 @@ class File } if (in_array($type, $this->config['apart_level'])) { // 独立记录的日志级别 - $filename = $path . DS . $type . '.log'; + $filename = $path . DS . date('d') . '_' . $type . '.log'; error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$level}\r\n---------------------------------------------------------------\r\n", 3, $filename); } else { $info .= $level; diff --git a/core/library/think/model/Merge.php b/core/library/think/model/Merge.php index 9a28ea9c..405c6bcc 100644 --- a/core/library/think/model/Merge.php +++ b/core/library/think/model/Merge.php @@ -144,11 +144,10 @@ class Merge extends Model * @access public * @param mixed $data 数据 * @param array $where 更新条件 - * @param bool $getId 新增的时候是否获取id - * @param bool $replace 是否replace - * @return mixed + * @param string $sequence 自增序列名 + * @return integer|false */ - public function save($data = [], $where = [], $getId = true, $replace = false) + public function save($data = [], $where = [], $sequence = null) { if (!empty($data)) { // 数据自动验证 @@ -230,11 +229,13 @@ class Merge extends Model // 处理模型数据 $data = $this->parseData($this->name, $this->data, true); // 写入主表数据 - $result = $db->name($this->name)->strict(false)->insert($data, $replace); + $result = $db->name($this->name)->strict(false)->insert($data); if ($result) { - $insertId = $db->getLastInsID(); + $insertId = $db->getLastInsID($sequence); // 写入外键数据 - $this->data[$this->fk] = $insertId; + if ($insertId) { + $this->data[$this->fk] = $insertId; + } // 写入附表数据 foreach (static::$relationModel as $key => $model) { @@ -245,7 +246,6 @@ class Merge extends Model $query = clone $db; $query->table($table)->strict(false)->insert($data); } - $result = $insertId; } // 新增回调 $this->trigger('after_insert', $this); diff --git a/core/library/think/response/Redirect.php b/core/library/think/response/Redirect.php index ae6084c4..81b7b050 100644 --- a/core/library/think/response/Redirect.php +++ b/core/library/think/response/Redirect.php @@ -42,6 +42,24 @@ class Redirect extends Response return; } + /** + * 重定向传值(通过Session) + * @access protected + * @param string|array $name 变量名或者数组 + * @param mixed $value 值 + * @return $this + */ + public function with($name, $value = null) + { + if (is_array($name)) { + foreach ($name as $key => $val) { + Session::set($key, $val); + } + } else { + Session::set($name, $value); + } + } + /** * 获取跳转地址 * @return string diff --git a/core/library/traits/model/SoftDelete.php b/core/library/traits/model/SoftDelete.php index 621cc8ce..cbfa275f 100644 --- a/core/library/traits/model/SoftDelete.php +++ b/core/library/traits/model/SoftDelete.php @@ -83,7 +83,10 @@ trait SoftDelete } elseif ($data instanceof \Closure) { call_user_func_array($data, [ & $query]); $data = null; + } elseif (is_null($data)) { + return 0; } + $resultSet = $query->select($data); $count = 0; if ($resultSet) { @@ -98,16 +101,15 @@ trait SoftDelete /** * 恢复被软删除的记录 * @access public + * @param array $where 更新条件 * @return integer */ - public function restore() + public function restore($where = []) { if (static::$deleteTime) { // 恢复删除 - $name = static::$deleteTime; - $this->change[] = $name; - $this->data[$name] = null; - return $this->isUpdate()->save(); + $name = static::$deleteTime; + return $this->isUpdate()->save([$name => null], $where); } return false; } @@ -115,6 +117,7 @@ trait SoftDelete /** * 查询默认不包含软删除数据 * @access protected + * @param \think\db\Query $query 查询对象 * @return void */ protected static function base($query)