From 25c9cbbaebc5c99a944767ab2d658736f1e1c96a Mon Sep 17 00:00:00 2001 From: Zhao <756958008@qq.com> Date: Wed, 18 Apr 2018 17:04:42 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6applica?= =?UTF-8?q?tion/wiki/apiRoute.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/wiki/apiRoute.php | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 application/wiki/apiRoute.php diff --git a/application/wiki/apiRoute.php b/application/wiki/apiRoute.php deleted file mode 100644 index 6f97d7f..0000000 --- a/application/wiki/apiRoute.php +++ /dev/null @@ -1,8 +0,0 @@ - Date: Thu, 19 Apr 2018 23:41:25 +0800 Subject: [PATCH 2/5] =?UTF-8?q?modified=20=E4=BF=AE=E6=AD=A3=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E7=9A=84Cache=E5=89=8D=E7=BC=80=E4=BB=A5=E9=80=82?= =?UTF-8?q?=E9=85=8DFile=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 application/config.php diff --git a/application/config.php b/application/config.php old mode 100755 new mode 100644 index a3c00ca..3b54aee --- a/application/config.php +++ b/application/config.php @@ -191,7 +191,7 @@ return [ // 缓存保存目录 'path' => CACHE_PATH, // 缓存前缀 - 'prefix' => 'ApiAdmin:', + 'prefix' => 'ApiAdmin_', // 缓存有效期 0表示永久缓存 'expire' => 0, ], From f5cc7aa3ee1b341f98aedeae58be97e8df8d3da9 Mon Sep 17 00:00:00 2001 From: Zhao <756958008@qq.com> Date: Thu, 19 Apr 2018 23:43:10 +0800 Subject: [PATCH 3/5] =?UTF-8?q?modified=20=E4=BF=AE=E5=A4=8D=E9=BB=98?= =?UTF-8?q?=E8=AE=A4root=E5=AF=86=E7=A0=81=E4=B8=BA123456?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/apiadmin_3.0.6.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/apiadmin_3.0.6.sql b/data/apiadmin_3.0.6.sql index 7b7e388..60f68f8 100644 --- a/data/apiadmin_3.0.6.sql +++ b/data/apiadmin_3.0.6.sql @@ -287,7 +287,7 @@ LOCK TABLES `admin_user` WRITE; INSERT INTO `admin_user` (`id`, `username`, `nickname`, `password`, `regTime`, `regIp`, `updateTime`, `status`, `openId`) VALUES - (1,'root','root','953dbb5a8a45ae6000e30f29d78dcc68',1519453594,3663623043,1520173599,1,NULL); + (1,'root','root','912601e4ad1b308c9ae41877cf6ca754',1519453594,3663623043,1520173599,1,NULL); /*!40000 ALTER TABLE `admin_user` ENABLE KEYS */; UNLOCK TABLES; From 5175d614dee0d7541cb899edca9ddb2895265cd8 Mon Sep 17 00:00:00 2001 From: zhaoxiang <756958008@qq.com> Date: Tue, 8 May 2018 00:59:51 +0800 Subject: [PATCH 4/5] =?UTF-8?q?modified=20=E5=8D=87=E7=BA=A7ThinkPHP?= =?UTF-8?q?=E6=A0=B8=E5=BF=83=E5=88=B05.0.19=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- thinkphp/base.php | 2 +- thinkphp/convention.php | 2 + thinkphp/helper.php | 6 - thinkphp/lang/zh-cn.php | 1 + thinkphp/library/think/App.php | 13 +- thinkphp/library/think/Controller.php | 7 - thinkphp/library/think/Loader.php | 43 ++-- thinkphp/library/think/Model.php | 24 ++ thinkphp/library/think/Paginator.php | 10 +- thinkphp/library/think/Request.php | 25 +- thinkphp/library/think/Response.php | 4 +- thinkphp/library/think/Route.php | 9 +- thinkphp/library/think/Url.php | 2 +- thinkphp/library/think/db/Builder.php | 110 +++++---- thinkphp/library/think/db/Connection.php | 48 ++-- thinkphp/library/think/db/Query.php | 221 ++++++++++++++---- thinkphp/library/think/db/builder/Mysql.php | 15 +- thinkphp/library/think/db/builder/Pgsql.php | 10 +- thinkphp/library/think/db/builder/Sqlite.php | 10 +- thinkphp/library/think/db/builder/Sqlsrv.php | 52 +++-- .../think/model/relation/BelongsToMany.php | 3 +- .../library/think/model/relation/HasMany.php | 9 +- .../think/model/relation/MorphMany.php | 3 +- .../library/think/template/driver/File.php | 5 +- thinkphp/library/think/view/driver/Php.php | 30 ++- thinkphp/library/think/view/driver/Think.php | 4 +- 26 files changed, 452 insertions(+), 216 deletions(-) diff --git a/thinkphp/base.php b/thinkphp/base.php index 619eb93..87e1cc9 100755 --- a/thinkphp/base.php +++ b/thinkphp/base.php @@ -9,7 +9,7 @@ // | Author: liu21st // +---------------------------------------------------------------------- -define('THINK_VERSION', '5.0.16'); +define('THINK_VERSION', '5.0.19'); define('THINK_START_TIME', microtime(true)); define('THINK_START_MEM', memory_get_usage()); define('EXT', '.php'); diff --git a/thinkphp/convention.php b/thinkphp/convention.php index 15e3496..31a0a0c 100755 --- a/thinkphp/convention.php +++ b/thinkphp/convention.php @@ -116,6 +116,8 @@ return [ // +---------------------------------------------------------------------- 'template' => [ + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, // 模板引擎类型 支持 php think 支持扩展 'type' => 'Think', // 视图基础目录,配置目录为所有模块的视图起始目录 diff --git a/thinkphp/helper.php b/thinkphp/helper.php index b568dab..12683cf 100755 --- a/thinkphp/helper.php +++ b/thinkphp/helper.php @@ -443,12 +443,6 @@ if (!function_exists('view')) { */ function view($template = '', $vars = [], $replace = [], $code = 200) { - if ('' === $template) { - $trace = debug_backtrace(false, 2); - $suffix = Config::get('action_suffix'); - $action = $suffix ? substr($trace[1]['function'], 0, -strlen($suffix)) : $trace[1]['function']; - $template = Loader::parseName($action); - } return Response::create($template, 'view', $code)->replace($replace)->assign($vars); } } diff --git a/thinkphp/lang/zh-cn.php b/thinkphp/lang/zh-cn.php index 0c2732f..c821f9f 100755 --- a/thinkphp/lang/zh-cn.php +++ b/thinkphp/lang/zh-cn.php @@ -66,6 +66,7 @@ return [ 'relation data not exists' => '关联数据不存在', 'relation not support' => '关联不支持', 'chunk not support order' => 'Chunk不支持调用order方法', + 'closure not support cache(true)' => '使用闭包查询不支持cache(true),请指定缓存Key', // 上传错误信息 'unknown upload error' => '未知上传错误!', diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php index d34c04c..3c5f81f 100755 --- a/thinkphp/library/think/App.php +++ b/thinkphp/library/think/App.php @@ -555,7 +555,11 @@ class App // 获取操作名 $actionName = strip_tags($result[2] ?: $config['default_action']); - $actionName = $convert ? strtolower($actionName) : $actionName; + if (!empty($config['action_convert'])) { + $actionName = Loader::parseName($actionName, 1); + } else { + $actionName = $convert ? strtolower($actionName) : $actionName; + } // 设置当前请求的控制器、操作 $request->controller(Loader::parseName($controller, 1))->action($actionName); @@ -581,6 +585,13 @@ class App if (is_callable([$instance, $action])) { // 执行操作方法 $call = [$instance, $action]; + // 严格获取当前操作方法名 + $reflect = new \ReflectionMethod($instance, $action); + $methodName = $reflect->getName(); + $suffix = $config['action_suffix']; + $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; + $request->action($actionName); + } elseif (is_callable([$instance, '_empty'])) { // 空操作 $call = [$instance, '_empty']; diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php index 43044de..77225b7 100755 --- a/thinkphp/library/think/Controller.php +++ b/thinkphp/library/think/Controller.php @@ -117,13 +117,6 @@ class Controller */ protected function fetch($template = '', $vars = [], $replace = [], $config = []) { - if ('' === $template) { - $trace = debug_backtrace(false, 2); - $suffix = Config::get('action_suffix'); - $action = $suffix ? substr($trace[1]['function'], 0, -strlen($suffix)) : $trace[1]['function']; - $template = Loader::parseName($action); - } - return $this->view->fetch($template, $vars, $replace, $config); } diff --git a/thinkphp/library/think/Loader.php b/thinkphp/library/think/Loader.php index e75fe53..d813a5d 100755 --- a/thinkphp/library/think/Loader.php +++ b/thinkphp/library/think/Loader.php @@ -23,7 +23,7 @@ class Loader /** * @var array 类名映射 */ - protected static $map = []; + protected static $classMap = []; /** * @var array 命名空间别名 @@ -56,9 +56,9 @@ class Loader private static $fallbackDirsPsr0 = []; /** - * @var array 自动加载的文件 + * @var array 需要加载的文件 */ - private static $autoloadFiles = []; + private static $files = []; /** * 自动加载 @@ -99,8 +99,8 @@ class Loader private static function findFile($class) { // 类库映射 - if (!empty(self::$map[$class])) { - return self::$map[$class]; + if (!empty(self::$classMap[$class])) { + return self::$classMap[$class]; } // 查找 PSR-4 @@ -156,7 +156,7 @@ class Loader } // 找不到则设置映射为 false 并返回 - return self::$map[$class] = false; + return self::$classMap[$class] = false; } /** @@ -169,9 +169,9 @@ class Loader public static function addClassMap($class, $map = '') { if (is_array($class)) { - self::$map = array_merge(self::$map, $class); + self::$classMap = array_merge(self::$classMap, $class); } else { - self::$map[$class] = $map; + self::$classMap[$class] = $map; } } @@ -292,12 +292,11 @@ class Loader $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); - self::$prefixLengthsPsr4 = $composerClass::$prefixLengthsPsr4; - - self::$prefixDirsPsr4 = property_exists($composerClass, 'prefixDirsPsr4') ? $composerClass::$prefixDirsPsr4 : []; - - self::$prefixesPsr0 = property_exists($composerClass, 'prefixesPsr0') ? $composerClass::$prefixesPsr0 : []; - self::$map = property_exists($composerClass, 'classMap') ? $composerClass::$classMap : []; + foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { + if (property_exists($composerClass, $attr)) { + self::${$attr} = $composerClass::${$attr}; + } + } } else { self::registerComposerLoader(); } @@ -348,18 +347,20 @@ class Loader self::addClassMap($classMap); } } + + if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { + self::$files = require VENDOR_PATH . 'composer/autoload_files.php'; + } } // 加载composer autofile文件 public static function loadComposerAutoloadFiles() { - if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { - $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php'; - foreach ($includeFiles as $fileIdentifier => $file) { - if (empty(self::$autoloadFiles[$fileIdentifier])) { - __require_file($file); - self::$autoloadFiles[$fileIdentifier] = true; - } + foreach (self::$files as $fileIdentifier => $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + __require_file($file); + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; } } } diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php index cbab715..386660c 100755 --- a/thinkphp/library/think/Model.php +++ b/thinkphp/library/think/Model.php @@ -116,6 +116,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ protected static $initialized = []; + /** + * 是否从主库读取(主从分布式有效) + * @var array + */ + protected static $readMaster; + /** * 构造方法 * @access public @@ -171,6 +177,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $this->initialize(); } + /** + * 是否从主库读取数据(主从分布有效) + * @access public + * @param bool $all 是否所有模型生效 + * @return $this + */ + public function readMaster($all = false) + { + $model = $all ? '*' : $this->class; + + static::$readMaster[$model] = true; + return $this; + } + /** * 创建模型的查询对象 * @access protected @@ -194,6 +214,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $queryClass = $this->query ?: $con->getConfig('query'); $query = new $queryClass($con, $this); + if (isset(static::$readMaster['*']) || isset(static::$readMaster[$this->class])) { + $query->master(true); + } + // 设置当前数据表和模型名 if (!empty($this->table)) { $query->setTable($this->table); diff --git a/thinkphp/library/think/Paginator.php b/thinkphp/library/think/Paginator.php index 0b2a3c6..3655567 100755 --- a/thinkphp/library/think/Paginator.php +++ b/thinkphp/library/think/Paginator.php @@ -395,7 +395,15 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J public function __call($name, $arguments) { - return call_user_func_array([$this->getCollection(), $name], $arguments); + $collection = $this->getCollection(); + + $result = call_user_func_array([$collection, $name], $arguments); + + if ($result === $collection) { + return $this; + } + + return $result; } } diff --git a/thinkphp/library/think/Request.php b/thinkphp/library/think/Request.php index d49295d..7c72587 100755 --- a/thinkphp/library/think/Request.php +++ b/thinkphp/library/think/Request.php @@ -232,7 +232,7 @@ class Request parse_str(html_entity_decode($info['query']), $query); if (!empty($params)) { $params = array_replace($query, $params); - $queryString = http_build_query($query, '', '&'); + $queryString = http_build_query($params, '', '&'); } else { $params = $query; $queryString = $info['query']; @@ -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 其他安全过滤 @@ -1273,7 +1273,11 @@ class Request return $ip[$type]; } - if ($adv) { + $httpAgentIp = Config::get('http_agent_ip'); + + if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) { + $ip = $_SERVER[$httpAgentIp]; + } elseif ($adv) { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $pos = array_search('unknown', $arr); @@ -1338,14 +1342,18 @@ class Request /** * 当前请求的host * @access public + * @param bool $strict true 仅仅获取HOST * @return string */ - public function host() + public function host($strict = false) { if (isset($_SERVER['HTTP_X_REAL_HOST'])) { - return $_SERVER['HTTP_X_REAL_HOST']; + $host = $_SERVER['HTTP_X_REAL_HOST']; + } else { + $host = $this->server('HTTP_HOST'); } - return $this->server('HTTP_HOST'); + + return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host; } /** @@ -1466,11 +1474,12 @@ class Request */ public function action($action = null) { - if (!is_null($action)) { + if (!is_null($action) && !is_bool($action)) { $this->action = $action; return $this; } else { - return $this->action ?: ''; + $name = $this->action ?: ''; + return true === $action ? $name : strtolower($name); } } diff --git a/thinkphp/library/think/Response.php b/thinkphp/library/think/Response.php index f14bbcf..c5c1520 100755 --- a/thinkphp/library/think/Response.php +++ b/thinkphp/library/think/Response.php @@ -69,9 +69,7 @@ class Response */ public static function create($data = '', $type = '', $code = 200, array $header = [], $options = []) { - $type = empty($type) ? 'null' : strtolower($type); - - $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst($type); + $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type)); if (class_exists($class)) { $response = new $class($data, $code, $header, $options); } else { diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php index 2dbd61d..99ffa70 100755 --- a/thinkphp/library/think/Route.php +++ b/thinkphp/library/think/Route.php @@ -737,7 +737,7 @@ class Route $rules = self::$rules['domain']; // 开启子域名部署 支持二级和三级域名 if (!empty($rules)) { - $host = $request->host(); + $host = $request->host(true); if (isset($rules[$host])) { // 完整域名或者IP配置 $item = $rules[$host]; @@ -1506,7 +1506,7 @@ class Route App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : ''); } else { // 路由到模块/控制器/操作 - $result = self::parseModule($route); + $result = self::parseModule($route, isset($option['convert']) ? $option['convert'] : false); } // 开启请求缓存 if ($request->isGet() && isset($option['cache'])) { @@ -1527,9 +1527,10 @@ class Route * 解析URL地址为 模块/控制器/操作 * @access private * @param string $url URL地址 + * @param bool $convert 是否自动转换URL地址 * @return array */ - private static function parseModule($url) + private static function parseModule($url, $convert = false) { list($path, $var) = self::parseUrlPath($url); $action = array_pop($path); @@ -1543,7 +1544,7 @@ class Route // 设置当前请求的路由变量 Request::instance()->route($var); // 路由到模块/控制器/操作 - return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false]; + return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => $convert]; } /** diff --git a/thinkphp/library/think/Url.php b/thinkphp/library/think/Url.php index 53a545f..bb69719 100755 --- a/thinkphp/library/think/Url.php +++ b/thinkphp/library/think/Url.php @@ -239,7 +239,7 @@ class Url $rootDomain = Config::get('url_domain_root'); if (true === $domain) { // 自动判断域名 - $domain = Config::get('app_host') ?: $request->host(); + $domain = Config::get('app_host') ?: $request->host(true); $domains = Route::rules('domain'); if ($domains) { diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php index cd948da..d4d27a1 100755 --- a/thinkphp/library/think/db/Builder.php +++ b/thinkphp/library/think/db/Builder.php @@ -11,7 +11,6 @@ namespace think\db; -use BadMethodCallException; use PDO; use think\Exception; @@ -99,8 +98,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(); } @@ -112,18 +114,11 @@ abstract class Builder $result[$item] = 'NULL'; } elseif (is_array($val) && !empty($val)) { switch ($val[0]) { - case 'exp': - $result[$item] = $val[1]; - break; case 'inc': - if ($key == $val[1]) { - $result[$item] = $this->parseKey($val[1]) . '+' . floatval($val[2]); - } + $result[$item] = $item . '+' . floatval($val[1]); break; case 'dec': - if ($key == $val[1]) { - $result[$item] = $this->parseKey($val[1]) . '-' . floatval($val[2]); - } + $result[$item] = $item . '-' . floatval($val[1]); break; } } elseif (is_scalar($val)) { @@ -147,7 +142,7 @@ abstract class Builder * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { return $key; } @@ -188,8 +183,10 @@ 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); } @@ -268,6 +265,10 @@ abstract class Builder foreach ($where as $key => $val) { $str = []; foreach ($val as $field => $value) { + if ($value instanceof Expression) { + $str[] = ' ' . $key . ' ( ' . $value->getValue() . ' )'; + continue; + } if ($value instanceof \Closure) { // 使用闭包查询 $query = new Query($this->connection); @@ -309,7 +310,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)) { @@ -348,7 +349,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(); } @@ -385,7 +388,11 @@ abstract class Builder } } elseif ('EXP' == $exp) { // 表达式查询 - $whereStr .= '( ' . $key . ' ' . $value . ' )'; + if ($value instanceof Expression) { + $whereStr .= '( ' . $key . ' ' . $value->getValue() . ' )'; + } else { + throw new Exception('where express error:' . $exp); + } } elseif (in_array($exp, ['NOT NULL', 'NULL'])) { // NULL 查询 $whereStr .= $key . ' IS ' . $exp; @@ -503,6 +510,11 @@ abstract class Builder } } $bindName = $bindName ?: $key; + + if ($this->query->isBind($bindName)) { + $bindName .= '_' . str_replace('.', '_', uniqid('', true)); + } + $this->query->bind($bindName, $value, $bindType); return ':' . $bindName; } @@ -533,7 +545,9 @@ abstract class Builder list($table, $type, $on) = $item; $condition = []; foreach ((array) $on as $val) { - if (strpos($val, '=')) { + if ($val instanceof Expression) { + $condition[] = $val->getValue(); + } elseif (strpos($val, '=')) { list($val1, $val2) = explode('=', $val, 2); $condition[] = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options); } else { @@ -557,28 +571,29 @@ abstract class Builder */ protected function parseOrder($order, $options = []) { - if (is_array($order)) { - $array = []; - foreach ($order as $key => $val) { - if (is_numeric($key)) { - if ('[rand]' == $val) { - if (method_exists($this, 'parseRand')) { - $array[] = $this->parseRand(); - } else { - throw new BadMethodCallException('method not exists:' . get_class($this) . '-> parseRand'); - } - } elseif (false === strpos($val, '(')) { - $array[] = $this->parseKey($val, $options); - } else { - $array[] = $val; - } - } else { - $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; - $array[] = $this->parseKey($key, $options) . ' ' . $sort; - } - } - $order = implode(',', $array); + if (empty($order)) { + return ''; } + + $array = []; + foreach ($order as $key => $val) { + if ($val instanceof Expression) { + $array[] = $val->getValue(); + } elseif ('[rand]' == $val) { + $array[] = $this->parseRand(); + } else { + if (is_numeric($key)) { + list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' '); + } else { + $sort = $val; + } + $sort = strtoupper($sort); + $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; + $array[] = $this->parseKey($key, $options, true) . $sort; + } + } + $order = implode(',', $array); + return !empty($order) ? ' ORDER BY ' . $order : ''; } @@ -612,6 +627,9 @@ abstract class Builder */ protected function parseComment($comment) { + if (false !== strpos($comment, '*/')) { + $comment = strstr($coment, '*/', true); + } return !empty($comment) ? ' /* ' . $comment . ' */' : ''; } @@ -661,11 +679,7 @@ abstract class Builder return ''; } - if (is_array($index)) { - $index = join(",", $index); - } - - return sprintf(" FORCE INDEX ( %s ) ", $index); + return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index); } /** @@ -783,10 +797,14 @@ abstract class Builder $values[] = 'SELECT ' . implode(',', $value); if (!isset($insertFields)) { - $insertFields = array_map([$this, 'parseKey'], array_keys($data)); + $insertFields = array_keys($data); } } + foreach ($insertFields as $field) { + $fields[] = $this->parseKey($query, $field, true); + } + return str_replace( ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], [ diff --git a/thinkphp/library/think/db/Connection.php b/thinkphp/library/think/db/Connection.php index e252b90..7720282 100755 --- a/thinkphp/library/think/db/Connection.php +++ b/thinkphp/library/think/db/Connection.php @@ -90,6 +90,8 @@ abstract class Connection 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', + // 模型写入后自动读取主服务器 + 'read_master' => false, // 是否严格检查字段是否存在 'fields_strict' => true, // 数据返回类型 @@ -378,7 +380,7 @@ abstract class Connection // 执行查询 $this->PDOStatement->execute(); // 调试结束 - $this->debug(false); + $this->debug(false, '', $master); // 返回结果集 return $this->getResult($pdo, $procedure); } catch (\PDOException $e) { @@ -402,13 +404,14 @@ abstract class Connection /** * 执行语句 * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param Query $query 查询对象 * @return int * @throws PDOException * @throws \Exception */ - public function execute($sql, $bind = []) + public function execute($sql, $bind = [], Query $query = null) { $this->initConnect(true); if (!$this->linkID) { @@ -445,23 +448,27 @@ abstract class Connection // 执行语句 $this->PDOStatement->execute(); // 调试结束 - $this->debug(false); + $this->debug(false, '', true); + + if ($query && !empty($this->config['deploy']) && !empty($this->config['read_master'])) { + $query->readMaster(); + } $this->numRows = $this->PDOStatement->rowCount(); return $this->numRows; } catch (\PDOException $e) { if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind); + return $this->close()->execute($sql, $bind, $query); } throw new PDOException($e, $this->config, $this->getLastsql()); } catch (\Throwable $e) { if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind); + return $this->close()->execute($sql, $bind, $query); } throw $e; } catch (\Exception $e) { if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind); + return $this->close()->execute($sql, $bind, $query); } throw $e; } @@ -744,7 +751,7 @@ abstract class Connection * @param array $sqlArray SQL批处理指令 * @return boolean */ - public function batchQuery($sqlArray = [], $bind = []) + public function batchQuery($sqlArray = [], $bind = [], Query $query = null) { if (!is_array($sqlArray)) { return false; @@ -753,7 +760,7 @@ abstract class Connection $this->startTrans(); try { foreach ($sqlArray as $sql) { - $this->execute($sql, $bind); + $this->execute($sql, $bind, $query); } // 提交事务 $this->commit(); @@ -904,9 +911,10 @@ abstract class Connection * @access protected * @param boolean $start 调试开始标记 true 开始 false 结束 * @param string $sql 执行的SQL语句 留空自动获取 + * @param boolean $master 主从标记 * @return void */ - protected function debug($start, $sql = '') + protected function debug($start, $sql = '', $master = false) { if (!empty($this->config['debug'])) { // 开启数据库调试模式 @@ -923,7 +931,7 @@ abstract class Connection $result = $this->getExplain($sql); } // SQL监听 - $this->trigger($sql, $runtime, $result); + $this->trigger($sql, $runtime, $result, $master); } } } @@ -945,19 +953,27 @@ abstract class Connection * @param string $sql SQL语句 * @param float $runtime SQL运行时间 * @param mixed $explain SQL分析 - * @return bool + * @param bool $master 主从标记 + * @return void */ - protected function trigger($sql, $runtime, $explain = []) + protected function trigger($sql, $runtime, $explain = [], $master = false) { if (!empty(self::$event)) { foreach (self::$event as $callback) { if (is_callable($callback)) { - call_user_func_array($callback, [$sql, $runtime, $explain]); + call_user_func_array($callback, [$sql, $runtime, $explain, $master]); } } } else { // 未注册监听则记录到日志中 - Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql'); + if ($this->config['deploy']) { + // 分布式记录当前操作的主从 + $master = $master ? 'master|' : 'slave|'; + } else { + $master = ''; + } + + Log::record('[ SQL ] ' . $sql . ' [ ' . $master . 'RunTime:' . $runtime . 's ]', 'sql'); if (!empty($explain)) { Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql'); } diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php index 50f0fd8..1f3ddc2 100755 --- a/thinkphp/library/think/db/Query.php +++ b/thinkphp/library/think/db/Query.php @@ -53,6 +53,8 @@ class Query protected static $info = []; // 回调事件 private static $event = []; + // 读取主库 + private static $readMaster = []; /** * 构造函数 @@ -140,6 +142,25 @@ class Query return $this->model; } + /** + * 设置后续从主库读取数据 + * @access public + * @param bool $allTable + * @return void + */ + public function readMaster($allTable = false) + { + if ($allTable) { + $table = '*'; + } else { + $table = isset($this->options['table']) ? $this->options['table'] : $this->getTable(); + } + + static::$readMaster[$table] = true; + + return $this; + } + /** * 获取当前的builder实例对象 * @access public @@ -238,7 +259,7 @@ class Query */ public function execute($sql, $bind = []) { - return $this->connection->execute($sql, $bind); + return $this->connection->execute($sql, $bind, $this); } /** @@ -609,7 +630,7 @@ class Query return true; } } - return $this->setField($field, ['inc', $field, $step]); + return $this->setField($field, ['inc', $step]); } /** @@ -637,9 +658,9 @@ class Query $this->options = []; return true; } - return $this->setField($field, ['inc', $field, $step]); + return $this->setField($field, ['inc', $step]); } - return $this->setField($field, ['dec', $field, $step]); + return $this->setField($field, ['dec', $step]); } /** @@ -769,8 +790,15 @@ class Query { if (empty($field)) { return $this; + } elseif ($field instanceof Expression) { + $this->options['field'][] = $field; + return $this; } + if (is_string($field)) { + if (preg_match('/[\<\'\"\(]/', $field)) { + return $this->fieldRaw($field); + } $field = array_map('trim', explode(',', $field)); } if (true === $field) { @@ -800,6 +828,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 @@ -828,7 +874,7 @@ class Query { $fields = is_string($field) ? explode(',', $field) : $field; foreach ($fields as $field) { - $this->data($field, ['inc', $field, $step]); + $this->data($field, ['inc', $step]); } return $this; } @@ -844,7 +890,7 @@ class Query { $fields = is_string($field) ? explode(',', $field) : $field; foreach ($fields as $field) { - $this->data($field, ['dec', $field, $step]); + $this->data($field, ['dec', $step]); } return $this; } @@ -858,16 +904,27 @@ class Query */ public function exp($field, $value) { - $this->data($field, ['exp', $value]); + $this->data($field, $this->raw($value)); return $this; } + /** + * 使用表达式设置数据 + * @access public + * @param mixed $value 表达式 + * @return Expression + */ + public function raw($value) + { + return new Expression($value); + } + /** * 指定JOIN查询字段 * @access public * @param string|array $table 数据表 * @param string|array $field 查询字段 - * @param string|array $on JOIN条件 + * @param mixed $on JOIN条件 * @param string $type JOIN类型 * @return $this */ @@ -975,6 +1032,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 @@ -1121,7 +1209,7 @@ class Query */ public function whereExp($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'exp', $condition, [], true); + $this->parseWhereExp($logic, $field, 'exp', $this->raw($condition), [], true); return $this; } @@ -1163,14 +1251,16 @@ 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]; // 记录一个字段多次查询条件 $this->options['multi'][$logic][$field][] = $where[$field]; } elseif (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) { - $where[] = ['exp', $field]; + $where[] = ['exp', $this->raw($field)]; if (is_array($op)) { // 参数绑定 $this->bind($op); @@ -1191,21 +1281,28 @@ class Query $where[$field] = $param; } elseif (in_array(strtolower($op), ['null', 'notnull', 'not null'])) { // null查询 - $where[$field] = [$op, '']; + $where[$field] = [$op, '']; + $this->options['multi'][$logic][$field][] = $where[$field]; } elseif (is_null($condition)) { // 字段相等查询 - $where[$field] = ['eq', $op]; + $where[$field] = ['eq', $op]; + $this->options['multi'][$logic][$field][] = $where[$field]; } else { - $where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null]; - if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) { + if ('exp' == strtolower($op)) { + $where[$field] = ['exp', $this->raw($condition)]; // 参数绑定 - $this->bind($param[2]); + if (isset($param[2]) && is_array($param[2])) { + $this->bind($param[2]); + } + } else { + $where[$field] = [$op, $condition]; } // 记录一个字段多次查询条件 $this->options['multi'][$logic][$field][] = $where[$field]; } + if (!empty($where)) { if (!isset($this->options['where'][$logic])) { $this->options['where'][$logic] = []; @@ -1423,31 +1520,59 @@ class Query */ public function order($field, $order = null) { - if (!empty($field)) { - if (is_string($field)) { - if (!empty($this->options['via'])) { - $field = $this->options['via'] . '.' . $field; - } - $field = empty($order) ? $field : [$field => $order]; - } elseif (!empty($this->options['via'])) { - foreach ($field as $key => $val) { - if (is_numeric($key)) { - $field[$key] = $this->options['via'] . '.' . $val; - } else { - $field[$this->options['via'] . '.' . $key] = $val; - unset($field[$key]); - } - } + if (empty($field)) { + return $this; + } elseif ($field instanceof Expression) { + $this->options['order'][] = $field; + return $this; + } + + if (is_string($field)) { + if (!empty($this->options['via'])) { + $field = $this->options['via'] . '.' . $field; } - if (!isset($this->options['order'])) { - $this->options['order'] = []; - } - if (is_array($field)) { - $this->options['order'] = array_merge($this->options['order'], $field); + if (strpos($field, ',')) { + $field = array_map('trim', explode(',', $field)); } else { - $this->options['order'][] = $field; + $field = empty($order) ? $field : [$field => $order]; + } + } elseif (!empty($this->options['via'])) { + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $field[$key] = $this->options['via'] . '.' . $val; + } else { + $field[$this->options['via'] . '.' . $key] = $val; + unset($field[$key]); + } } } + if (!isset($this->options['order'])) { + $this->options['order'] = []; + } + if (is_array($field)) { + $this->options['order'] = array_merge($this->options['order'], $field); + } else { + $this->options['order'][] = $field; + } + + 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; } @@ -2100,7 +2225,7 @@ class Query } // 执行操作 - $result = 0 === $sql ? 0 : $this->execute($sql, $bind); + $result = 0 === $sql ? 0 : $this->execute($sql, $bind, $this); if ($result) { $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); $lastInsId = $this->getLastInsID($sequence); @@ -2166,10 +2291,10 @@ class Query return $this->connection->getRealSql($sql, $bind); } elseif (is_array($sql)) { // 执行操作 - return $this->batchQuery($sql, $bind); + return $this->batchQuery($sql, $bind, $this); } else { // 执行操作 - return $this->execute($sql, $bind); + return $this->execute($sql, $bind, $this); } } @@ -2195,7 +2320,7 @@ class Query return $this->connection->getRealSql($sql, $bind); } else { // 执行操作 - return $this->execute($sql, $bind); + return $this->execute($sql, $bind, $this); } } @@ -2262,7 +2387,7 @@ class Query Cache::clear($options['cache']['tag']); } // 执行操作 - $result = '' == $sql ? 0 : $this->execute($sql, $bind); + $result = '' == $sql ? 0 : $this->execute($sql, $bind, $this); if ($result) { if (is_string($pk) && isset($where[$pk])) { $data[$pk] = $where[$pk]; @@ -2436,8 +2561,12 @@ class Query if (isset($data)) { return 'think:' . $prefix . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; - } else { + } + + try { return md5($prefix . serialize($options) . serialize($bind)); + } catch (\Exception $e) { + throw new Exception('closure not support cache(true)'); } } @@ -2730,7 +2859,7 @@ class Query Cache::clear($options['cache']['tag']); } // 执行操作 - $result = $this->execute($sql, $bind); + $result = $this->execute($sql, $bind, $this); if ($result) { if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) { list($a, $val) = explode('|', $key); @@ -2815,6 +2944,10 @@ class Query } } + if (isset(static::$readMaster['*']) || (is_string($options['table']) && isset(static::$readMaster[$options['table']]))) { + $options['master'] = true; + } + foreach (['join', 'union', 'group', 'having', 'limit', 'order', 'force', 'comment'] as $name) { if (!isset($options[$name])) { $options[$name] = ''; diff --git a/thinkphp/library/think/db/builder/Mysql.php b/thinkphp/library/think/db/builder/Mysql.php index 30fa506..8eee746 100755 --- a/thinkphp/library/think/db/builder/Mysql.php +++ b/thinkphp/library/think/db/builder/Mysql.php @@ -82,17 +82,23 @@ class Mysql extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $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 +108,8 @@ class Mysql extends Builder $table = $options['alias'][$table]; } } - if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) { + + if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) { $key = '`' . $key . '`'; } if (isset($table)) { diff --git a/thinkphp/library/think/db/builder/Pgsql.php b/thinkphp/library/think/db/builder/Pgsql.php index 21de525..acc2289 100755 --- a/thinkphp/library/think/db/builder/Pgsql.php +++ b/thinkphp/library/think/db/builder/Pgsql.php @@ -44,12 +44,18 @@ class Pgsql extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $key = trim($key); if (strpos($key, '$.') && false === strpos($key, '(')) { // JSON字段支持 diff --git a/thinkphp/library/think/db/builder/Sqlite.php b/thinkphp/library/think/db/builder/Sqlite.php index 960533b..c727f04 100755 --- a/thinkphp/library/think/db/builder/Sqlite.php +++ b/thinkphp/library/think/db/builder/Sqlite.php @@ -52,12 +52,18 @@ class Sqlite extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $key = trim($key); if (strpos($key, '.')) { list($table, $key) = explode('.', $key, 2); diff --git a/thinkphp/library/think/db/builder/Sqlsrv.php b/thinkphp/library/think/db/builder/Sqlsrv.php index 59ea021..f79ae03 100755 --- a/thinkphp/library/think/db/builder/Sqlsrv.php +++ b/thinkphp/library/think/db/builder/Sqlsrv.php @@ -12,6 +12,7 @@ namespace think\db\builder; use think\db\Builder; +use think\db\Expression; /** * Sqlsrv数据库驱动 @@ -34,25 +35,29 @@ class Sqlsrv extends Builder */ protected function parseOrder($order, $options = []) { - if (is_array($order)) { - $array = []; - foreach ($order as $key => $val) { - if (is_numeric($key)) { - if (false === strpos($val, '(')) { - $array[] = $this->parseKey($val, $options); - } elseif ('[rand]' == $val) { - $array[] = $this->parseRand(); - } else { - $array[] = $val; - } - } else { - $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; - $array[] = $this->parseKey($key, $options) . ' ' . $sort; - } - } - $order = implode(',', $array); + if (empty($order)) { + return ' ORDER BY rand()'; } - return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()'; + + $array = []; + foreach ($order as $key => $val) { + if ($val instanceof Expression) { + $array[] = $val->getValue(); + } elseif (is_numeric($key)) { + if (false === strpos($val, '(')) { + $array[] = $this->parseKey($val, $options); + } elseif ('[rand]' == $val) { + $array[] = $this->parseRand(); + } else { + $array[] = $val; + } + } else { + $sort = in_array(strtolower(trim($val)), ['asc', 'desc'], true) ? ' ' . $val : ''; + $array[] = $this->parseKey($key, $options, true) . ' ' . $sort; + } + } + + return ' ORDER BY ' . implode(',', $array); } /** @@ -68,12 +73,17 @@ class Sqlsrv extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } $key = trim($key); if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) { list($table, $key) = explode('.', $key, 2); @@ -84,7 +94,7 @@ class Sqlsrv extends Builder $table = $options['alias'][$table]; } } - if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) { + if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) { $key = '[' . $key . ']'; } if (isset($table)) { diff --git a/thinkphp/library/think/model/relation/BelongsToMany.php b/thinkphp/library/think/model/relation/BelongsToMany.php index 2f451a7..c9845a9 100755 --- a/thinkphp/library/think/model/relation/BelongsToMany.php +++ b/thinkphp/library/think/model/relation/BelongsToMany.php @@ -12,6 +12,7 @@ namespace think\model\relation; use think\Collection; +use think\Db; use think\db\Query; use think\Exception; use think\Loader; @@ -338,7 +339,7 @@ class BelongsToMany extends Relation return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ 'pivot.' . $this->localKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + Db::raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk()), ], ])->fetchSql()->count(); } diff --git a/thinkphp/library/think/model/relation/HasMany.php b/thinkphp/library/think/model/relation/HasMany.php index 3a9b111..cfcf2a9 100755 --- a/thinkphp/library/think/model/relation/HasMany.php +++ b/thinkphp/library/think/model/relation/HasMany.php @@ -143,7 +143,7 @@ class HasMany extends Relation if ($closure) { call_user_func_array($closure, [ & $this->query]); } - $count = $this->query->where([$this->foreignKey => $result->$localKey])->count(); + $count = $this->query->where($this->foreignKey, $result->$localKey)->count(); } return $count; } @@ -160,12 +160,7 @@ class HasMany extends Relation call_user_func_array($closure, [ & $this->query]); } $localKey = $this->localKey ?: $this->parent->getPk(); - return $this->query->where([ - $this->foreignKey => [ - 'exp', - '=' . $this->parent->getTable() . '.' . $localKey, - ], - ])->fetchSql()->count(); + return $this->query->whereExp($this->foreignKey, '=' . $this->parent->getTable() . '.' . $localKey)->fetchSql()->count(); } /** diff --git a/thinkphp/library/think/model/relation/MorphMany.php b/thinkphp/library/think/model/relation/MorphMany.php index 23f7c52..8945042 100755 --- a/thinkphp/library/think/model/relation/MorphMany.php +++ b/thinkphp/library/think/model/relation/MorphMany.php @@ -11,6 +11,7 @@ namespace think\model\relation; +use think\Db; use think\db\Query; use think\Exception; use think\Loader; @@ -201,7 +202,7 @@ class MorphMany extends Relation return $this->query->where([ $this->morphKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + Db::raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk()), ], $this->morphType => $this->type, ])->fetchSql()->count(); diff --git a/thinkphp/library/think/template/driver/File.php b/thinkphp/library/think/template/driver/File.php index bf3d22a..a9a86bf 100755 --- a/thinkphp/library/think/template/driver/File.php +++ b/thinkphp/library/think/template/driver/File.php @@ -15,6 +15,8 @@ use think\Exception; class File { + protected $cacheFile; + /** * 写入编译缓存 * @param string $cacheFile 缓存的文件名 @@ -42,12 +44,13 @@ class File */ public function read($cacheFile, $vars = []) { + $this->cacheFile = $cacheFile; if (!empty($vars) && is_array($vars)) { // 模板阵列变量分解成为独立变量 extract($vars, EXTR_OVERWRITE); } //载入模版缓存文件 - include $cacheFile; + include $this->cacheFile; } /** diff --git a/thinkphp/library/think/view/driver/Php.php b/thinkphp/library/think/view/driver/Php.php index fa50535..f594a43 100755 --- a/thinkphp/library/think/view/driver/Php.php +++ b/thinkphp/library/think/view/driver/Php.php @@ -29,7 +29,11 @@ class Php 'view_suffix' => 'php', // 模板文件名分隔符 'view_depr' => DS, + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, ]; + protected $template; + protected $content; public function __construct($config = []) { @@ -68,16 +72,12 @@ class Php if (!is_file($template)) { throw new TemplateNotFoundException('template not exists:' . $template, $template); } + $this->template = $template; // 记录视图信息 App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info'); - if (isset($data['template'])) { - $__template__ = $template; - extract($data, EXTR_OVERWRITE); - include $__template__; - } else { - extract($data, EXTR_OVERWRITE); - include $template; - } + + extract($data, EXTR_OVERWRITE); + include $this->template; } /** @@ -89,14 +89,10 @@ class Php */ public function display($content, $data = []) { - if (isset($data['content'])) { - $__content__ = $content; - extract($data, EXTR_OVERWRITE); - eval('?>' . $__content__); - } else { - extract($data, EXTR_OVERWRITE); - eval('?>' . $content); - } + $this->content = $content; + + extract($data, EXTR_OVERWRITE); + eval('?>' . $this->content); } /** @@ -132,7 +128,7 @@ class Php if ($controller) { if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); + $template = str_replace('.', DS, $controller) . $depr . (1 == $this->config['auto_rule'] ? Loader::parseName($request->action(true)) : $request->action()); } elseif (false === strpos($template, $depr)) { $template = str_replace('.', DS, $controller) . $depr . $template; } diff --git a/thinkphp/library/think/view/driver/Think.php b/thinkphp/library/think/view/driver/Think.php index 46829d5..a314ad6 100755 --- a/thinkphp/library/think/view/driver/Think.php +++ b/thinkphp/library/think/view/driver/Think.php @@ -34,6 +34,8 @@ class Think 'view_depr' => DS, // 是否开启模板编译缓存,设为false则每次都会重新编译 'tpl_cache' => true, + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, ]; public function __construct($config = []) @@ -127,7 +129,7 @@ class Think if ($controller) { if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); + $template = str_replace('.', DS, $controller) . $depr . (1 == $this->config['auto_rule'] ? Loader::parseName($request->action(true)) : $request->action()); } elseif (false === strpos($template, $depr)) { $template = str_replace('.', DS, $controller) . $depr . $template; } From 6c8372f1bfbe932adff3c450ddb53d1a9dee2090 Mon Sep 17 00:00:00 2001 From: zhaoxiang <756958008@qq.com> Date: Tue, 8 May 2018 01:01:45 +0800 Subject: [PATCH 5/5] =?UTF-8?q?modified=20=E5=8D=87=E7=BA=A7ApiAdmin?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=88=B03.0.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d8de5bb..1912b99 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ # ApiAdmin [![ApiAdmin](https://img.shields.io/hexpm/l/plug.svg)](http://www.apiadmin.org/) -[![ApiAdmin](https://img.shields.io/badge/release-v3.0.7-blue.svg)](http://www.apiadmin.org/) +[![ApiAdmin](https://img.shields.io/badge/release-v3.0.8-blue.svg)](http://www.apiadmin.org/) [![ApiAdmin](https://img.shields.io/wercker/ci/wercker/docs.svg)](http://www.apiadmin.org/) -[![ApiAdmin](https://img.shields.io/badge/ApiAdmin-v3.0.7-brightgreen.svg)](http://www.apiadmin.org/) +[![ApiAdmin](https://img.shields.io/badge/ApiAdmin-v3.0.8-brightgreen.svg)](http://www.apiadmin.org/) ## 前端页面 ApiAdmin3.0是一个前后端完全分离的项目,前端采用Vue构建,如需要可视化配置的请移步:[ApiAdmin-WEB](https://gitee.com/apiadmin/ApiAdmin-WEB) @@ -31,7 +31,7 @@ ApiAdmin3.0是一个前后端完全分离的项目,前端采用Vue构建,如 **项目构成** -- ThinkPHP v5.0.16 +- ThinkPHP v5.0.19 - Vue 2.0 - semanticUI - ... @@ -44,8 +44,7 @@ ApiAdmin3.0是一个前后端完全分离的项目,前端采用Vue构建,如 4. 灵活的参数规则设定 5. 支持三方Api无缝融合 6. 本地二次开发友好 - 7. 使用Datatables完成数据JS加载 - 8. ... + 7. ... ``` ApiAdmin(PHP部分)