diff --git a/README.md b/README.md index 9eecee1..4365641 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ https://github.com/yuan1994/tpadmin/archive/master.zip ## 鸣谢: 本平台使用了如下框架或插件、源码 -* ThinkPHP 5.0.3 正式版 +* ThinkPHP 5.0.4 正式版 * Hui.admin v2.5 * layer * jQuery Validform diff --git a/application/admin/tags.php b/application/admin/tags.php index b48ecf1..902c581 100644 --- a/application/admin/tags.php +++ b/application/admin/tags.php @@ -10,9 +10,9 @@ return [ 'module_init' => [ - '\\app\\common\behavior\\WebLog', + '\\app\\common\\behavior\\WebLog', ], 'app_end' => [ - '\\app\\common\behavior\\WebLog', + '\\app\\common\\behavior\\WebLog', ] ]; diff --git a/application/common/behavior/WebLog.php b/application/common/behavior/WebLog.php index 354fe01..a59117e 100644 --- a/application/common/behavior/WebLog.php +++ b/application/common/behavior/WebLog.php @@ -100,6 +100,16 @@ public function module_init(&$param) $this->init(); } + /** + * module_init同名函数,ThinkPHP5.0.4默默的将行为规范为psr-4标准 + * + * @param $param + */ + public function moduleInit(&$param) + { + $this->init(); + } + /** * 应用执行完 * @@ -110,6 +120,16 @@ public function app_end(&$param) $this->record(); } + /** + * app_end同名函数,ThinkPHP5.0.4默默的将行为规范为psr-4标准 + * + * @param $param + */ + public function appEnd(&$param) + { + $this->record(); + } + /** * 设置配置信息 * diff --git a/composer.lock b/composer.lock index cee6439..39cdcd3 100644 --- a/composer.lock +++ b/composer.lock @@ -66,16 +66,16 @@ }, { "name": "qiniu/php-sdk", - "version": "v7.1.1", + "version": "v7.1.3", "source": { "type": "git", "url": "https://github.com/qiniu/php-sdk.git", - "reference": "e9cdc254c95188c8d13e0f04fab9648d790c42f9" + "reference": "b91653485e36b4797d7a302cc86c49695e47a642" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/qiniu/php-sdk/e9cdc254c95188c8d13e0f04fab9648d790c42f9.zip", - "reference": "e9cdc254c95188c8d13e0f04fab9648d790c42f9", + "url": "https://packagist.phpcomposer.com/files/qiniu/php-sdk/b91653485e36b4797d7a302cc86c49695e47a642.zip", + "reference": "b91653485e36b4797d7a302cc86c49695e47a642", "shasum": "" }, "require": { @@ -113,7 +113,7 @@ "sdk", "storage" ], - "time": "2016-11-02 03:10:06" + "time": "2016-11-18 02:57:31" }, { "name": "swiftmailer/swiftmailer", @@ -170,16 +170,16 @@ }, { "name": "topthink/framework", - "version": "v5.0.3", + "version": "v5.0.4", "source": { "type": "git", "url": "https://github.com/top-think/framework.git", - "reference": "fd30f090e40dc25a758d99029fa07f669f575580" + "reference": "c695397733a707d4434fa8f8c070c9caf1f1f369" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/top-think/framework/fd30f090e40dc25a758d99029fa07f669f575580.zip", - "reference": "fd30f090e40dc25a758d99029fa07f669f575580", + "url": "https://packagist.phpcomposer.com/files/top-think/framework/c695397733a707d4434fa8f8c070c9caf1f1f369.zip", + "reference": "c695397733a707d4434fa8f8c070c9caf1f1f369", "shasum": "" }, "require": { @@ -218,7 +218,7 @@ "orm", "thinkphp" ], - "time": "2016-11-11 09:22:23" + "time": "2016-12-20 00:28:50" }, { "name": "topthink/think-captcha", @@ -258,16 +258,16 @@ }, { "name": "topthink/think-installer", - "version": "v1.0.10", + "version": "v1.0.11", "source": { "type": "git", "url": "https://github.com/top-think/think-installer.git", - "reference": "ae50760ebd7c687c7a8573db2cfa94a41e5100e3" + "reference": "4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/top-think/think-installer/ae50760ebd7c687c7a8573db2cfa94a41e5100e3.zip", - "reference": "ae50760ebd7c687c7a8573db2cfa94a41e5100e3", + "url": "https://packagist.phpcomposer.com/files/top-think/think-installer/4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d.zip", + "reference": "4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d", "shasum": "" }, "require": { @@ -295,20 +295,20 @@ "email": "448901948@qq.com" } ], - "time": "2016-09-23 04:04:44" + "time": "2016-12-01 09:08:45" }, { "name": "yuan1994/tp-mailer", - "version": "v0.2.3", + "version": "v0.2.4", "source": { "type": "git", "url": "https://github.com/yuan1994/tp-mailer.git", - "reference": "41c526cf1bc9a07249b1a420f97404b0bae69195" + "reference": "7fe9b64d69be67a325a2708368b99edf44d17981" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/yuan1994/tp-mailer/41c526cf1bc9a07249b1a420f97404b0bae69195.zip", - "reference": "41c526cf1bc9a07249b1a420f97404b0bae69195", + "url": "https://packagist.phpcomposer.com/files/yuan1994/tp-mailer/7fe9b64d69be67a325a2708368b99edf44d17981.zip", + "reference": "7fe9b64d69be67a325a2708368b99edf44d17981", "shasum": "" }, "require": { @@ -345,7 +345,7 @@ "tp-mailer", "tp5-mailer" ], - "time": "2016-12-10 03:19:02" + "time": "2016-12-10 11:54:45" } ], "packages-dev": [], diff --git a/thinkphp/base.php b/thinkphp/base.php index 5bd1b40..01ee13c 100644 --- a/thinkphp/base.php +++ b/thinkphp/base.php @@ -9,7 +9,7 @@ // | Author: liu21st // +---------------------------------------------------------------------- -define('THINK_VERSION', '5.0.3'); +define('THINK_VERSION', '5.0.4'); 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 8eb30f4..487c248 100644 --- a/thinkphp/convention.php +++ b/thinkphp/convention.php @@ -115,7 +115,9 @@ 'template' => [ // 模板引擎类型 支持 php think 支持扩展 'type' => 'Think', - // 模板路径 + // 视图基础目录,配置目录为所有模块的视图起始目录 + 'view_base' => '', + // 当前模板的视图目录 留空为自动获取 'view_path' => '', // 模板后缀 'view_suffix' => 'html', diff --git a/thinkphp/helper.php b/thinkphp/helper.php index b81970c..02d8761 100644 --- a/thinkphp/helper.php +++ b/thinkphp/helper.php @@ -125,7 +125,7 @@ function input($key = '', $default = null, $filter = '') } if ($pos = strpos($key, '.')) { // 指定参数来源 - list($method, $key) = explode('.', $key); + list($method, $key) = explode('.', $key, 2); if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { $key = $method . '.' . $key; $method = 'param'; diff --git a/thinkphp/lang/zh-cn.php b/thinkphp/lang/zh-cn.php index db43a1c..b3fef35 100644 --- a/thinkphp/lang/zh-cn.php +++ b/thinkphp/lang/zh-cn.php @@ -62,4 +62,5 @@ 'sae mc write error' => 'SAE mc 写入错误', 'route name not exists' => '路由标识不存在(或参数不够)', 'invalid request' => '非法请求', + 'bind attr has exists' => '模型的属性已经存在', ]; diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php index 4eddc7c..01af92c 100644 --- a/thinkphp/library/think/App.php +++ b/thinkphp/library/think/App.php @@ -141,11 +141,13 @@ public static function run(Request $request = null) break; case 'controller': // 执行控制器操作 - $data = Loader::action($dispatch['controller']); + $vars = Request::instance()->param(); + $data = Loader::action($dispatch['controller'], array_merge($vars, $dispatch['var'])); break; case 'method': // 执行回调方法 - $data = self::invokeMethod($dispatch['method']); + $vars = Request::instance()->param(); + $data = self::invokeMethod($dispatch['method'], array_merge($vars, $dispatch['var'])); break; case 'function': // 执行闭包 @@ -220,7 +222,7 @@ public static function invokeFunction($function, $vars = []) public static function invokeMethod($method, $vars = []) { if (is_array($method)) { - $class = is_object($method[0]) ? $method[0] : new $method[0](Request::instance()); + $class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]); $reflect = new \ReflectionMethod($class, $method[1]); } else { // 静态方法 @@ -345,6 +347,8 @@ public static function module($result, $config, $convert = null) // 初始化模块 $request->module($module); $config = self::init($module); + // 模块请求缓存检查 + $request->cache($config['request_cache'], $config['request_cache_expire']); } else { throw new HttpException(404, 'module not exists:' . $module); } @@ -386,7 +390,7 @@ public static function module($result, $config, $convert = null) } elseif (is_callable([$instance, '_empty'])) { // 空操作 $call = [$instance, '_empty']; - $vars = [$action]; + $vars = [$actionName]; } else { // 操作不存在 throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); @@ -446,9 +450,9 @@ public static function initCommon() // 监听app_init Hook::listen('app_init'); - self::$init = $config; + self::$init = true; } - return self::$init; + return Config::get(); } /** diff --git a/thinkphp/library/think/Cache.php b/thinkphp/library/think/Cache.php index a5ac0b3..208190b 100644 --- a/thinkphp/library/think/Cache.php +++ b/thinkphp/library/think/Cache.php @@ -185,6 +185,35 @@ public static function clear($tag = null) return self::$handler->clear($tag); } + /** + * 读取缓存并删除 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public static function pull($name) + { + self::init(); + self::$readTimes++; + self::$writeTimes++; + return self::$handler->pull($name); + } + + /** + * 如果不存在则写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int $expire 有效时间 0为永久 + * @return mixed + */ + public static function remember($name, $value, $expire = null) + { + self::init(); + self::$readTimes++; + return self::$handler->remember($name, $value, $expire); + } + /** * 缓存标签 * @access public diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php index a889e4d..fe4efae 100644 --- a/thinkphp/library/think/Controller.php +++ b/thinkphp/library/think/Controller.php @@ -20,9 +20,13 @@ class Controller { use \traits\controller\Jump; - // 视图类实例 + /** + * @var \think\View 视图类实例 + */ protected $view; - // Request实例 + /** + * @var \think\Request Request实例 + */ protected $request; // 验证失败是否抛出异常 protected $failException = false; diff --git a/thinkphp/library/think/Cookie.php b/thinkphp/library/think/Cookie.php index 648b2c6..12b5cc3 100644 --- a/thinkphp/library/think/Cookie.php +++ b/thinkphp/library/think/Cookie.php @@ -99,6 +99,22 @@ public static function set($name, $value = '', $option = null) $_COOKIE[$name] = $value; } + /** + * 永久保存Cookie数据 + * @param string $name cookie名称 + * @param mixed $value cookie值 + * @param mixed $option 可选参数 可能会是 null|integer|string + * @return void + */ + public static function forever($name, $value = '', $option = null) + { + if (is_null($option) || is_numeric($option)) { + $option = []; + } + $option['expire'] = 315360000; + self::set($name, $value, $option); + } + /** * 判断Cookie数据 * @param string $name cookie名称 diff --git a/thinkphp/library/think/Hook.php b/thinkphp/library/think/Hook.php index 062ac96..4d69ca5 100644 --- a/thinkphp/library/think/Hook.php +++ b/thinkphp/library/think/Hook.php @@ -1,5 +1,4 @@ $behavior) { + self::add($tag, $behavior); + } + } else { + self::$tags = $tags + self::$tags; + } + } - /** - * 批量导入插件 - * @param array $tags 插件信息 - * @param boolean $recursive 是否递归合并 - */ - public static function import(array $tags, $recursive = true) - { - if ($recursive) { - foreach ($tags as $tag => $behavior) { - self::add($tag, $behavior); - } - } else { - self::$tags = $tags + self::$tags; - } - } + /** + * 获取插件信息 + * @param string $tag 插件位置 留空获取全部 + * @return array + */ + public static function get($tag = '') + { + if (empty($tag)) { + //获取全部的插件信息 + return self::$tags; + } else { + return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : []; + } + } - /** - * 获取插件信息 - * @param string $tag 插件位置 留空获取全部 - * @return array - */ - public static function get($tag = '') - { - if (empty($tag)) {//获取全部的插件信息 - return self::$tags; - } else { - return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : []; - } - } + /** + * 监听标签的行为 + * @param string $tag 标签名称 + * @param mixed $params 传入参数 + * @param mixed $extra 额外参数 + * @param bool $once 只获取一个有效返回值 + * @return mixed + */ + public static function listen($tag, &$params = null, $extra = null, $once = false) + { + $results = []; + $tags = static::get($tag); + foreach ($tags as $key => $name) { + $results[$key] = self::exec($name, $tag, $params, $extra); + if (false === $results[$key]) { + // 如果返回false 则中断行为执行 + break; + } elseif (!is_null($results[$key]) && $once) { + break; + } + } + return $once ? end($results) : $results; + } - /** - * 监听标签的行为 - * @param string $tag 标签名称 - * @param mixed $params 传入参数 - * @param mixed $extra 额外参数 - * @param bool $once 只获取一个有效返回值 - * @return mixed - */ - public static function listen($tag, &$params = null, $extra = null, $once = false) - { - $results = []; - $tags = static::get($tag); - foreach ($tags as $key => $name) { - $results[$key] = self::exec($name, $tag, $params, $extra); - if (false === $results[$key]) {// 如果返回false 则中断行为执行 - break; - } elseif (!is_null($results[$key]) && $once) { - break; - } - } - return $once ? end($results) : $results; - } + /** + * 执行某个行为 + * @param mixed $class 要执行的行为 + * @param string $tag 方法名(标签名) + * @param Mixed $params 传人的参数 + * @param mixed $extra 额外参数 + * @return mixed + */ + public static function exec($class, $tag = '', &$params = null, $extra = null) + { + App::$debug && Debug::remark('behavior_start', 'time'); + $method = Loader::parseName($tag, 1, false); + if ($class instanceof \Closure) { + $result = call_user_func_array($class, [ & $params, $extra]); + $class = 'Closure'; + } elseif (is_array($class)) { + list($class, $method) = $class; - /** - * 执行某个行为 - * @param mixed $class 要执行的行为 - * @param string $tag 方法名(标签名) - * @param Mixed $params 传人的参数 - * @param mixed $extra 额外参数 - * @return mixed - */ - public static function exec($class, $tag = '', &$params = null, $extra = null) - { - App::$debug && Debug::remark('behavior_start', 'time'); - if (is_callable($class)) { - $result = call_user_func_array($class, [ & $params, $extra]); - $class = 'Closure'; - } elseif (is_object($class)) { - $result = call_user_func_array([$class, $tag], [ & $params, $extra]); - $class = get_class($class); - } else { - $obj = new $class(); - $result = ($tag && is_callable([$obj, $tag])) ? $obj->$tag($params, $extra) : $obj->run($params, $extra); - } - if (App::$debug) { - Debug::remark('behavior_end', 'time'); - Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info'); - } - return $result; - } + $result = (new $class())->$method($params, $extra); + $class = $class . '->' . $method; + } elseif (is_object($class)) { + $result = $class->$method($params, $extra); + $class = get_class($class); + } elseif (strpos($class, '::')) { + $result = call_user_func_array($class, [ & $params, $extra]); + } else { + $obj = new $class(); + $method = ($tag && is_callable([$obj, $method])) ? $method : 'run'; + $result = $obj->$method($params, $extra); + } + if (App::$debug) { + Debug::remark('behavior_end', 'time'); + Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info'); + } + return $result; + } } diff --git a/thinkphp/library/think/Loader.php b/thinkphp/library/think/Loader.php index e9429f8..0b536d6 100644 --- a/thinkphp/library/think/Loader.php +++ b/thinkphp/library/think/Loader.php @@ -494,17 +494,29 @@ public static function action($url, $vars = [], $layer = 'controller', $appendSu * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 * @param string $name 字符串 * @param integer $type 转换类型 + * @param bool $ucfirst 首字母是否大写(驼峰规则) * @return string */ - public static function parseName($name, $type = 0) + public static function parseName($name, $type = 0, $ucfirst = true) { + /****************** 修改开始 ********************/ if ($type) { - return preg_replace_callback(['/\_([a-zA-Z])/', '/([^.][a-zA-Z0-9]*$)/'], function ($match) { - return ucfirst($match[1]); + return preg_replace_callback(['/\_([a-zA-Z])/', '/([^.][a-zA-Z]*$)/'], function ($match) use ($ucfirst) { + return $ucfirst ? ucfirst($match[1]) : lcfirst($match[1]); }, $name); } else { return strtolower(preg_replace('/((?<=[a-z])(?=[A-Z]))/', '_', $name)); } + /****************** 修改结束 ********************/ + + /* if ($type) { + $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { + return strtoupper($match[1]); + }, $name); + return $ucfirst ? ucfirst($name) : lcfirst($name); + } else { + return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); + }*/ } /** diff --git a/thinkphp/library/think/Log.php b/thinkphp/library/think/Log.php index 5fd1631..413e276 100644 --- a/thinkphp/library/think/Log.php +++ b/thinkphp/library/think/Log.php @@ -32,13 +32,14 @@ class Log const SQL = 'sql'; const NOTICE = 'notice'; const ALERT = 'alert'; + const DEBUG = 'debug'; // 日志信息 protected static $log = []; // 配置参数 protected static $config = []; // 日志类型 - protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert']; + protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug']; // 日志写入驱动 protected static $driver; @@ -83,6 +84,10 @@ public static function getLog($type = '') public static function record($msg, $type = 'log') { self::$log[$type][] = $msg; + if (IS_CLI && count(self::$log[$type]) > 100) { + // 命令行下面日志写入改进 + self::save(); + } } /** @@ -136,6 +141,9 @@ public static function save() if (empty(self::$config['level'])) { // 获取全部日志 $log = self::$log; + if (!App::$debug && isset($log['debug'])) { + unset($log['debug']); + } } else { // 记录允许级别 $log = []; @@ -180,7 +188,7 @@ public static function write($msg, $type = 'log', $force = false) self::init(Config::get('log')); } // 写入日志 - return self::$driver->save($log); + return self::$driver->save($log, false); } /** diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php index aed24f7..80c224a 100644 --- a/thinkphp/library/think/Model.php +++ b/thinkphp/library/think/Model.php @@ -13,6 +13,7 @@ use InvalidArgumentException; use think\Cache; +use think\Collection; use think\Config; use think\Db; use think\db\Query; @@ -20,6 +21,13 @@ use think\Exception\ValidateException; use think\Loader; use think\model\Relation; +use think\model\relation\BelongsTo; +use think\model\relation\BelongsToMany; +use think\model\relation\HasMany; +use think\model\relation\HasManyThrough; +use think\model\relation\HasOne; +use think\model\relation\MorphMany; +use think\model\relation\MorphTo; use think\paginator\Collection as PaginatorCollection; /** @@ -103,6 +111,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess protected $useGlobalScope = true; // 是否采用批量验证 protected $batchValidate = false; + // 查询数据集对象 + protected $resultSetType; + // + protected static $db; /** * 初始化过的模型. @@ -156,8 +168,18 @@ public function db($baseQuery = true) { $model = $this->class; if (!isset(self::$links[$model])) { + // 合并数据库配置 + if (!empty($this->connection)) { + if (is_array($this->connection)) { + $connection = array_merge(Config::get('database'), $this->connection); + } else { + $connection = $this->connection; + } + } else { + $connection = []; + } // 设置当前模型 确保查询返回模型对象 - $query = Db::connect($this->connection)->model($model, $this->query); + $query = Db::connect($connection)->model($model, $this->query); // 设置当前数据表和模型名 if (!empty($this->table)) { @@ -180,26 +202,6 @@ public function db($baseQuery = true) return self::$links[$model]; } - /** - * 获取关联模型实例 - * @access protected - * @param string|array $relation 关联查询 - * @return Relation|Query - */ - protected function relation($relation = null) - { - if (!is_null($relation)) { - // 执行关联查询 - return $this->db()->relation($relation); - } - - // 获取关联对象实例 - if (is_null($this->relation)) { - $this->relation = new Relation($this); - } - return $this->relation; - } - /** * 初始化模型 * @access protected @@ -294,7 +296,9 @@ public function setAttr($name, $value, $data = []) } // 标记字段更改 - if (!isset($this->data[$name]) || ($this->data[$name] != $value && !in_array($name, $this->change))) { + if (isset($this->data[$name]) && is_scalar($this->data[$name]) && is_scalar($value) && 0 !== strcmp($this->data[$name], $value)) { + $this->change[] = $name; + } elseif (!isset($this->data[$name]) || $value != $this->data[$name]) { $this->change[] = $name; } // 设置数据对象属性 @@ -322,7 +326,8 @@ protected function autoWriteTimestamp($name) $value = date($format, $_SERVER['REQUEST_TIME']); break; case 'timestamp': - case 'int': + case 'integer': + default: $value = $_SERVER['REQUEST_TIME']; break; } @@ -414,10 +419,10 @@ public function getAttr($name) // 类型转换 $value = $this->readTransform($value, $this->type[$name]); } elseif ($notFound) { - $method = Loader::parseName($name, 1); - if (method_exists($this, $method) && !method_exists('\think\Model', $method)) { + $method = Loader::parseName($name, 1, false); + if (method_exists($this, $method) && $this->$method() instanceof Relation) { // 不存在该字段 获取关联数据 - $value = $this->relation()->getRelation($method); + $value = $this->$method()->getRelation(); // 保存关联对象值 $this->data[$name] = $value; } else { @@ -487,11 +492,38 @@ protected function readTransform($value, $type) * 设置需要追加的输出属性 * @access public * @param array $append 属性列表 + * @param bool $override 是否覆盖 + * @return $this + */ + public function append($append = [], $override = false) + { + $this->append = $override ? $append : array_merge($this->append, $append); + return $this; + } + + /** + * 设置附加关联对象的属性 + * @access public + * @param string $relation 关联方法 + * @param string|array $append 追加属性名 * @return $this */ - public function append($append = []) + public function appendRelationAttr($relation, $append) { - $this->append = $append; + if (is_string($append)) { + $append = explode(',', $append); + } + $model = $this->getAttr($relation); + if ($model instanceof Model) { + foreach ($append as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + if ($this->__isset($key)) { + throw new Exception('bind attr has exists:' . $key); + } else { + $this->setAttr($key, $model->$attr); + } + } + } return $this; } @@ -499,22 +531,24 @@ public function append($append = []) * 设置需要隐藏的输出属性 * @access public * @param array $hidden 属性列表 + * @param bool $override 是否覆盖 * @return $this */ - public function hidden($hidden = []) + public function hidden($hidden = [], $override = false) { - $this->hidden = $hidden; + $this->hidden = $override ? $hidden : array_merge($this->hidden, $hidden); return $this; } /** * 设置需要输出的属性 * @param array $visible + * @param bool $override 是否覆盖 * @return $this */ - public function visible($visible = []) + public function visible($visible = [], $override = false) { - $this->visible = $visible; + $this->visible = $override ? $visible : array_merge($this->visible, $visible); return $this; } @@ -572,6 +606,25 @@ public function toJson($options = JSON_UNESCAPED_UNICODE) return json_encode($this->toArray(), $options); } + /** + * 转换当前模型数据集为数据集对象 + * @access public + * @param array|Collection $collection 数据集 + * @return Collection + */ + public function toCollection($collection) + { + if ($this->resultSetType) { + if ('collection' == $this->resultSetType) { + $collection = new Collection($collection); + } else { + $class = $this->resultSetType; + $collection = new $class($collection); + } + } + return $collection; + } + /** * 获取模型对象的主键 * @access public @@ -711,7 +764,7 @@ public function save($data = [], $where = [], $sequence = null) $result = $this->db()->insert($this->data); // 获取自动增长主键 - if ($result && is_string($pk) && !isset($this->data[$pk])) { + if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) { $insertId = $this->db()->getLastInsID($sequence); if ($insertId) { $this->data[$pk] = $insertId; @@ -759,9 +812,9 @@ public function saveAll($dataSet, $replace = true) } foreach ($dataSet as $key => $data) { if (!empty($auto) && isset($data[$pk])) { - $result[$key] = self::update($data); + $result[$key] = self::update($data, [], $this->field); } else { - $result[$key] = self::create($data); + $result[$key] = self::create($data, $this->field); } } $db->commit(); @@ -979,12 +1032,16 @@ protected function trigger($event, &$params) /** * 写入数据 * @access public - * @param array $data 数据数组 + * @param array $data 数据数组 + * @param array|true $field 允许字段 * @return $this */ - public static function create($data = []) + public static function create($data = [], $field = null) { $model = new static(); + if (!empty($field)) { + $model->allowField($field); + } $model->isUpdate(false)->save($data, []); return $model; } @@ -992,13 +1049,17 @@ public static function create($data = []) /** * 更新数据 * @access public - * @param array $data 数据数组 - * @param array $where 更新条件 + * @param array $data 数据数组 + * @param array $where 更新条件 + * @param array|true $field 允许字段 * @return $this */ - public static function update($data = [], $where = []) + public static function update($data = [], $where = [], $field = null) { - $model = new static(); + $model = new static(); + if (!empty($field)) { + $model->allowField($field); + } $result = $model->isUpdate(true)->save($data, $where); return $model; } @@ -1126,8 +1187,8 @@ public static function scope($name) */ public static function useGlobalScope($use) { - $model = new static(); - $model->useGlobalScope = $use; + $model = new static(); + self::$db = $model->db($use); return $model; } @@ -1143,18 +1204,7 @@ public static function useGlobalScope($use) public static function has($relation, $operator = '>=', $count = 1, $id = '*') { $model = new static(); - $info = $model->$relation()->getRelationInfo(); - $table = $info['model']::getTable(); - switch ($info['type']) { - case Relation::HAS_MANY: - return $model->db()->alias('a') - ->join($table . ' b', 'a.' . $info['localKey'] . '=b.' . $info['foreignKey'], $info['joinType']) - ->group('b.' . $info['foreignKey']) - ->having('count(' . $id . ')' . $operator . $count); - case Relation::HAS_MANY_THROUGH: // TODO - default: - return $model; - } + return $model->$relation()->has($model, $operator, $count, $id); } /** @@ -1167,27 +1217,7 @@ public static function has($relation, $operator = '>=', $count = 1, $id = '*') public static function hasWhere($relation, $where = []) { $model = new static(); - $info = $model->$relation()->getRelationInfo(); - switch ($info['type']) { - case Relation::HAS_ONE: - case Relation::HAS_MANY: - $table = $info['model']::getTable(); - if (is_array($where)) { - foreach ($where as $key => $val) { - if (false === strpos($key, '.')) { - $where['b.' . $key] = $val; - unset($where[$key]); - } - } - } - return $model->db()->alias('a') - ->field('a.*') - ->join($table . ' b', 'a.' . $info['localKey'] . '=b.' . $info['foreignKey'], $info['joinType']) - ->where($where); - case Relation::HAS_MANY_THROUGH: // TODO - default: - return $model; - } + return $model->$relation()->hasWhere($model, $where); } /** @@ -1218,9 +1248,9 @@ public function relationQuery($relations) if (is_string($relations)) { $relations = explode(',', $relations); } - $this->relation(); + foreach ($relations as $relation) { - $this->data[$relation] = $this->relation->getRelation($relation); + $this->data[$relation] = $this->$relation()->getRelation(); } return $this; } @@ -1230,11 +1260,25 @@ public function relationQuery($relations) * @access public * @param array $resultSet 数据集 * @param string $relation 关联名 + * @param string $class 数据集对象名 为空表示数组 * @return array */ - public function eagerlyResultSet($resultSet, $relation) + public function eagerlyResultSet(&$resultSet, $relation, $class = '') { - return $this->relation()->eagerlyResultSet($resultSet, $relation); + $relations = is_string($relation) ? explode(',', $relation) : $relation; + foreach ($relations as $key => $relation) { + $subRelation = ''; + $closure = false; + if ($relation instanceof \Closure) { + $closure = $relation; + $relation = $key; + } + if (strpos($relation, '.')) { + list($relation, $subRelation) = explode('.', $relation); + } + $relation = Loader::parseName($relation, 1, false); + $this->$relation()->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $class); + } } /** @@ -1242,11 +1286,26 @@ public function eagerlyResultSet($resultSet, $relation) * @access public * @param Model $result 数据对象 * @param string $relation 关联名 + * @param string $class 数据集对象名 为空表示数组 * @return Model */ - public function eagerlyResult($result, $relation) + public function eagerlyResult(&$result, $relation, $class = '') { - return $this->relation()->eagerlyResult($result, $relation); + $relations = is_string($relation) ? explode(',', $relation) : $relation; + + foreach ($relations as $key => $relation) { + $subRelation = ''; + $closure = false; + if ($relation instanceof \Closure) { + $closure = $relation; + $relation = $key; + } + if (strpos($relation, '.')) { + list($relation, $subRelation) = explode('.', $relation); + } + $relation = Loader::parseName($relation, 1, false); + $this->$relation()->eagerlyResult($result, $relation, $subRelation, $closure, $class); + } } /** @@ -1257,7 +1316,7 @@ public function eagerlyResult($result, $relation) * @param string $localKey 关联主键 * @param array $alias 别名定义 * @param string $joinType JOIN类型 - * @return Relation + * @return HasOne */ public function hasOne($model, $foreignKey = '', $localKey = '', $alias = [], $joinType = 'INNER') { @@ -1265,7 +1324,7 @@ public function hasOne($model, $foreignKey = '', $localKey = '', $alias = [], $j $model = $this->parseModel($model); $localKey = $localKey ?: $this->getPk(); $foreignKey = $foreignKey ?: Loader::parseName($this->name) . '_id'; - return $this->relation()->hasOne($model, $foreignKey, $localKey, $alias, $joinType); + return new HasOne($this, $model, $foreignKey, $localKey, $alias, $joinType); } /** @@ -1276,7 +1335,7 @@ public function hasOne($model, $foreignKey = '', $localKey = '', $alias = [], $j * @param string $otherKey 关联主键 * @param array $alias 别名定义 * @param string $joinType JOIN类型 - * @return Relation + * @return BelongsTo */ public function belongsTo($model, $foreignKey = '', $otherKey = '', $alias = [], $joinType = 'INNER') { @@ -1284,7 +1343,7 @@ public function belongsTo($model, $foreignKey = '', $otherKey = '', $alias = [], $model = $this->parseModel($model); $foreignKey = $foreignKey ?: Loader::parseName(basename(str_replace('\\', '/', $model))) . '_id'; $otherKey = $otherKey ?: (new $model)->getPk(); - return $this->relation()->belongsTo($model, $foreignKey, $otherKey, $alias, $joinType); + return new BelongsTo($this, $model, $foreignKey, $otherKey, $alias, $joinType); } /** @@ -1294,7 +1353,7 @@ public function belongsTo($model, $foreignKey = '', $otherKey = '', $alias = [], * @param string $foreignKey 关联外键 * @param string $localKey 关联主键 * @param array $alias 别名定义 - * @return Relation + * @return HasMany */ public function hasMany($model, $foreignKey = '', $localKey = '', $alias = []) { @@ -1302,7 +1361,7 @@ public function hasMany($model, $foreignKey = '', $localKey = '', $alias = []) $model = $this->parseModel($model); $localKey = $localKey ?: $this->getPk(); $foreignKey = $foreignKey ?: Loader::parseName($this->name) . '_id'; - return $this->relation()->hasMany($model, $foreignKey, $localKey, $alias); + return new HasMany($this, $model, $foreignKey, $localKey, $alias); } /** @@ -1314,7 +1373,7 @@ public function hasMany($model, $foreignKey = '', $localKey = '', $alias = []) * @param string $throughKey 关联外键 * @param string $localKey 关联主键 * @param array $alias 别名定义 - * @return Relation + * @return HasManyThrough */ public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '', $alias = []) { @@ -1325,7 +1384,7 @@ public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = $foreignKey = $foreignKey ?: Loader::parseName($this->name) . '_id'; $name = Loader::parseName(basename(str_replace('\\', '/', $through))); $throughKey = $throughKey ?: $name . '_id'; - return $this->relation()->hasManyThrough($model, $through, $foreignKey, $throughKey, $localKey, $alias); + return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey, $alias); } /** @@ -1336,7 +1395,7 @@ public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = * @param string $foreignKey 关联外键 * @param string $localKey 当前模型关联键 * @param array $alias 别名定义 - * @return Relation + * @return BelongsToMany */ public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '', $alias = []) { @@ -1346,7 +1405,56 @@ public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = $table = $table ?: $this->db()->getTable(Loader::parseName($this->name) . '_' . $name); $foreignKey = $foreignKey ?: $name . '_id'; $localKey = $localKey ?: Loader::parseName($this->name) . '_id'; - return $this->relation()->belongsToMany($model, $table, $foreignKey, $localKey, $alias); + return new BelongsToMany($this, $model, $table, $foreignKey, $localKey, $alias); + } + + /** + * MORPH MANY 关联定义 + * @access public + * @param string $model 模型名 + * @param string|array $morph 多态字段信息 + * @param string $type 多态类型 + * @return MorphMany + */ + public function morphMany($model, $morph = null, $type = '') + { + // 记录当前关联信息 + $model = $this->parseModel($model); + if (is_null($morph)) { + $trace = debug_backtrace(false, 2); + $morph = Loader::parseName($trace[1]['function']); + } + $type = $type ?: Loader::parseName($this->name); + if (is_array($morph)) { + list($morphType, $foreignKey) = $morph; + } else { + $morphType = $morph . '_type'; + $foreignKey = $morph . '_id'; + } + return new MorphMany($this, $model, $foreignKey, $morphType, $type); + } + + /** + * MORPH TO 关联定义 + * @access public + * @param string|array $morph 多态字段信息 + * @param array $alias 多态别名定义 + * @return MorphTo + */ + public function morphTo($morph = null, $alias = []) + { + if (is_null($morph)) { + $trace = debug_backtrace(false, 2); + $morph = Loader::parseName($trace[1]['function']); + } + // 记录当前关联信息 + if (is_array($morph)) { + list($morphType, $foreignKey) = $morph; + } else { + $morphType = $morph . '_type'; + $foreignKey = $morph . '_id'; + } + return new MorphTo($this, $morphType, $foreignKey, $alias); } public function __call($method, $args) @@ -1365,7 +1473,12 @@ public function __call($method, $args) public static function __callStatic($method, $params) { - $query = (new static())->db(); + if (isset(static::$db)) { + $query = static::$db; + } else { + $query = (new static())->db(); + } + return call_user_func_array([$query, $method], $params); } @@ -1464,4 +1577,47 @@ public function __wakeup() $this->initialize(); } + /** + * 模型事件快捷方法 + */ + protected static function beforeInsert($callback, $override = false) + { + self::event('before_insert', $callback, $override); + } + + protected static function afterInsert($callback, $override = false) + { + self::event('after_insert', $callback, $override); + } + + protected static function beforeUpdate($callback, $override = false) + { + self::event('before_update', $callback, $override); + } + + protected static function afterUpdate($callback, $override = false) + { + self::event('after_update', $callback, $override); + } + + protected static function beforeWrite($callback, $override = false) + { + self::event('before_write', $callback, $override); + } + + protected static function afterWrite($callback, $override = false) + { + self::event('after_write', $callback, $override); + } + + protected static function beforeDelete($callback, $override = false) + { + self::event('before_delete', $callback, $override); + } + + protected static function afterDelete($callback, $override = false) + { + self::event('after_delete', $callback, $override); + } + } diff --git a/thinkphp/library/think/Request.php b/thinkphp/library/think/Request.php index 45b6542..086e366 100644 --- a/thinkphp/library/think/Request.php +++ b/thinkphp/library/think/Request.php @@ -257,7 +257,7 @@ public static function create($uri, $method = 'GET', $params = [], $cookie = [], } /** - * 获取当前包含协议的域名 + * 设置或获取当前包含协议的域名 * @access public * @param string $domain 域名 * @return string @@ -274,7 +274,7 @@ public function domain($domain = null) } /** - * 获取当前完整URL 包括QUERY_STRING + * 设置或获取当前完整URL 包括QUERY_STRING * @access public * @param string|true $url URL地址 true 带域名获取 * @return string @@ -301,7 +301,7 @@ public function url($url = null) } /** - * 获取当前URL 不含QUERY_STRING + * 设置或获取当前URL 不含QUERY_STRING * @access public * @param string $url URL地址 * @return string @@ -319,7 +319,7 @@ public function baseUrl($url = null) } /** - * 获取当前执行的文件 SCRIPT_NAME + * 设置或获取当前执行的文件 SCRIPT_NAME * @access public * @param string $file 当前执行的文件 * @return string @@ -351,7 +351,7 @@ public function baseFile($file = null) } /** - * 获取URL访问根地址 + * 设置或获取URL访问根地址 * @access public * @param string $url URL地址 * @return string @@ -455,7 +455,7 @@ public function time($float = false) */ public function type() { - $accept = isset($this->server['HTTP_ACCEPT']) ? $this->server['HTTP_ACCEPT'] : $_SERVER['HTTP_ACCEPT']; + $accept = $this->server('HTTP_ACCEPT'); if (empty($accept)) { return false; } @@ -602,7 +602,7 @@ public function isCgi() } /** - * 设置获取获取当前请求的参数 + * 获取获取当前请求的参数 * @access public * @param string|array $name 变量名 * @param mixed $default 默认值 @@ -686,7 +686,12 @@ public function get($name = '', $default = null, $filter = '') public function post($name = '', $default = null, $filter = '') { if (empty($this->post)) { - $this->post = $_POST; + $content = $this->input; + if (empty($_POST) && strpos($content, '":')) { + $this->post = json_decode($content, true); + } else { + $this->post = $_POST; + } } if (is_array($name)) { $this->param = []; @@ -847,7 +852,7 @@ public function file($name = '') $keys = array_keys($file); $count = count($file['name']); for ($i = 0; $i < $count; $i++) { - if (empty($file['tmp_name'][$i])) { + if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) { continue; } $temp['key'] = $key; @@ -861,7 +866,7 @@ public function file($name = '') if ($file instanceof File) { $array[$key] = $file; } else { - if (empty($file['tmp_name'])) { + if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) { continue; } $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file); @@ -1258,7 +1263,7 @@ public function ip($type = 0, $adv = false) } // IP地址合法验证 $long = sprintf("%u", ip2long($ip)); - $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); + $ip = $long ? [$ip, $long] : ['0.0.0.0', 0]; return $ip[$type]; } diff --git a/thinkphp/library/think/Response.php b/thinkphp/library/think/Response.php index a202ce7..a7ebecf 100644 --- a/thinkphp/library/think/Response.php +++ b/thinkphp/library/think/Response.php @@ -103,6 +103,16 @@ public function send() Debug::inject($this, $data); } + if (200 == $this->code) { + $cache = Request::instance()->getCache(); + if ($cache) { + $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; + $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; + $this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'; + Cache::set($cache[0], [$data, $this->header], $cache[1]); + } + } + if (!headers_sent() && !empty($this->header)) { // 发送状态码 http_response_code($this->code); @@ -111,16 +121,7 @@ public function send() header($name . ':' . $val); } } - if (200 == $this->code) { - $cache = Request::instance()->getCache(); - if ($cache) { - header('Cache-Control: max-age=' . $cache[1] . ',must-revalidate'); - header('Last-Modified:' . gmdate('D, d M Y H:i:s') . ' GMT'); - header('Expires:' . gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'); - $header['Content-Type'] = $this->header['Content-Type']; - Cache::set($cache[0], [$data, $header], $cache[1]); - } - } + echo $data; if (function_exists('fastcgi_finish_request')) { @@ -132,7 +133,9 @@ public function send() Hook::listen('response_end', $this); // 清空当次请求有效的数据 - Session::flush(); + if (!($this instanceof RedirectResponse)) { + Session::flush(); + } } /** @@ -281,7 +284,11 @@ public function contentType($contentType, $charset = 'utf-8') */ public function getHeader($name = '') { - return !empty($name) ? $this->header[$name] : $this->header; + if (!empty($name)) { + return isset($this->header[$name]) ? $this->header[$name] : null; + } else { + return $this->header; + } } /** diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php index c8eb24e..d327207 100644 --- a/thinkphp/library/think/Route.php +++ b/thinkphp/library/think/Route.php @@ -151,7 +151,7 @@ public static function name($name = '', $value = null) } elseif ('' === $name) { return self::$rules['name']; } elseif (!is_null($value)) { - self::$rules['name'][$name][] = $value; + self::$rules['name'][strtolower($name)][] = $value; } else { $name = strtolower($name); return isset(self::$rules['name'][$name]) ? self::$rules['name'][$name] : null; @@ -310,7 +310,7 @@ protected static function setRule($rule, $route, $type = '*', $option = [], $pat $vars = self::parseVar($rule); if (isset($name)) { $key = $group ? $group . ($rule ? '/' . $rule : '') : $rule; - self::name(strtolower($name), [$key, $vars, self::$domain]); + self::name($name, [$key, $vars, self::$domain]); } if ($group) { if ('*' != $type) { @@ -770,6 +770,10 @@ public static function checkDomain($request, &$currentRules, $method = 'get') } } if (!empty($item)) { + if (isset($panDomain)) { + // 保存当前泛域名 + $request->route(['__domain__' => $panDomain]); + } if (isset($item['[bind]'])) { // 解析子域名部署规则 list($rule, $option, $pattern) = $item['[bind]']; @@ -1223,7 +1227,7 @@ public static function parseUrl($url, $depr = '/', $autoSearch = false) $find = true; break; } else { - $dir .= DS . $val; + $dir .= DS . Loader::parseName($val); } } if ($find) { @@ -1480,12 +1484,15 @@ private static function parseRule($rule, $route, $pathinfo, $option = [], $match $result = ['type' => 'redirect', 'url' => $route, 'status' => isset($option['status']) ? $option['status'] : 301]; } elseif (false !== strpos($route, '\\')) { // 路由到方法 - $route = str_replace('/', '@', $route); - $method = strpos($route, '@') ? explode('@', $route) : $route; - $result = ['type' => 'method', 'method' => $method]; + list($path, $var) = self::parseUrlPath($route); + $route = str_replace('/', '@', implode('/', $path)); + $method = strpos($route, '@') ? explode('@', $route) : $route; + $result = ['type' => 'method', 'method' => $method, 'var' => $var]; } elseif (0 === strpos($route, '@')) { // 路由到控制器 - $result = ['type' => 'controller', 'controller' => substr($route, 1)]; + $route = substr($route, 1); + list($route, $var) = self::parseUrlPath($route); + $result = ['type' => 'controller', 'controller' => implode('/', $route), 'var' => $var]; } else { // 路由到模块/控制器/操作 $result = self::parseModule($route); @@ -1496,7 +1503,7 @@ private static function parseRule($rule, $route, $pathinfo, $option = [], $match if (is_array($cache)) { list($key, $expire) = $cache; } else { - $key = $pathinfo; + $key = str_replace('|', '/', $pathinfo); $expire = $cache; } $request->cache($key, $expire); diff --git a/thinkphp/library/think/Session.php b/thinkphp/library/think/Session.php index ab0bdfa..b9527a5 100644 --- a/thinkphp/library/think/Session.php +++ b/thinkphp/library/think/Session.php @@ -114,7 +114,9 @@ public static function boot() if (is_null(self::$init)) { self::init(); } elseif (false === self::$init) { - session_start(); + if (PHP_SESSION_ACTIVE != session_status()) { + session_start(); + } self::$init = true; } } diff --git a/thinkphp/library/think/Template.php b/thinkphp/library/think/Template.php index 4058b08..9f7793b 100644 --- a/thinkphp/library/think/Template.php +++ b/thinkphp/library/think/Template.php @@ -12,6 +12,7 @@ namespace think; use think\exception\TemplateNotFoundException; +use think\Request; /** * ThinkPHP分离出来的模板引擎 @@ -25,6 +26,7 @@ class Template // 引擎配置 protected $config = [ 'view_path' => '', // 模板路径 + 'view_base' => '', 'view_suffix' => 'html', // 默认模板文件后缀 'view_depr' => DS, 'cache_suffix' => 'php', // 默认模板缓存后缀 @@ -1042,11 +1044,14 @@ private function parseTemplateName($templateName) //支持加载变量文件名 $templateName = $this->get(substr($templateName, 1)); } + + /****************** 修改开始 ********************/ // 解决模板 include 标签不支持自动定位当前控制器的问题 - // tianpian 修改 if (!preg_match("/(\/|\:)/", $templateName)) { $templateName = str_replace(".", DS, \think\Loader::parseName(\think\Request::instance()->controller())) . DS . $templateName; } + /****************** 修改结束 ********************/ + $template = $this->parseTemplateFile($templateName); if ($template) { // 获取模板文件内容 @@ -1066,14 +1071,20 @@ private function parseTemplateFile($template) { if ('' == pathinfo($template, PATHINFO_EXTENSION)) { if (strpos($template, '@')) { - // 跨模块调用模板 + list($module, $template) = explode('@', $template); + } + if (0 !== strpos($template, '/')) { $template = str_replace(['/', ':'], $this->config['view_depr'], $template); - $template = APP_PATH . str_replace('@', '/' . basename($this->config['view_path']) . '/', $template); } else { - $template = str_replace(['/', ':'], $this->config['view_depr'], $template); - $template = $this->config['view_path'] . $template; + $template = str_replace(['/', ':'], $this->config['view_depr'], substr($template, 1)); + } + if ($this->config['view_base']) { + $module = isset($module) ? $module : Request::instance()->module(); + $path = $this->config['view_base'] . ($module ? $module . DS : ''); + } else { + $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path']; } - $template .= '.' . ltrim($this->config['view_suffix'], '.'); + $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.'); } if (is_file($template)) { diff --git a/thinkphp/library/think/Validate.php b/thinkphp/library/think/Validate.php index fc38d89..28f7c35 100644 --- a/thinkphp/library/think/Validate.php +++ b/thinkphp/library/think/Validate.php @@ -34,6 +34,8 @@ class Validate // 验证提示信息 protected $message = []; + // 验证字段描述 + protected $field = []; // 验证规则默认提示信息 protected static $typeMsg = [ @@ -70,8 +72,8 @@ class Validate 'expire' => '不在有效期内 :rule', 'allowIp' => '不允许的IP访问', 'denyIp' => '禁止的IP访问', - 'confirm' => ':attribute和字段 :rule 不一致', - 'different' => ':attribute和字段 :rule 不能相同', + 'confirm' => ':attribute和确认字段:2不一致', + 'different' => ':attribute和比较字段:2不能相同', 'egt' => ':attribute必须大于等于 :rule', 'gt' => ':attribute必须大于 :rule', 'elt' => ':attribute必须小于等于 :rule', @@ -107,11 +109,13 @@ class Validate * @access public * @param array $rules 验证规则 * @param array $message 验证提示信息 + * @param array $field 验证字段描述信息 */ - public function __construct(array $rules = [], $message = []) + public function __construct(array $rules = [], $message = [], $field = []) { $this->rule = array_merge($this->rule, $rules); $this->message = array_merge($this->message, $message); + $this->field = array_merge($this->field, $field); } /** @@ -119,12 +123,13 @@ public function __construct(array $rules = [], $message = []) * @access public * @param array $rules 验证规则 * @param array $message 验证提示信息 + * @param array $field 验证字段描述信息 * @return Validate */ - public static function make($rules = [], $message = []) + public static function make($rules = [], $message = [], $field = []) { if (is_null(self::$instance)) { - self::$instance = new self($rules, $message); + self::$instance = new self($rules, $message, $field); } return self::$instance; } @@ -216,6 +221,17 @@ public function scene($name, $fields = null) return $this; } + /** + * 判断是否存在某个验证场景 + * @access public + * @param string $name 场景名 + * @return bool + */ + public function hasScene($name) + { + return isset($this->scene[$name]); + } + /** * 设置批量验证 * @access public @@ -280,7 +296,7 @@ public function check($data, $rules = [], $scene = '') // 字段|描述 用于指定属性名称 list($key, $title) = explode('|', $key); } else { - $title = $key; + $title = isset($this->field[$key]) ? $this->field[$key] : $key; } // 场景检测 @@ -301,7 +317,12 @@ public function check($data, $rules = [], $scene = '') $value = $this->getDataValue($data, $key); // 字段验证 - $result = $this->checkItem($key, $value, $rule, $data, $title, $msg); + if ($rule instanceof \Closure) { + // 匿名函数验证 支持传入当前字段和所有字段两个数据 + $result = call_user_func_array($rule, [$value, $data]); + } else { + $result = $this->checkItem($key, $value, $rule, $data, $title, $msg); + } if (true !== $result) { // 没有返回true 则表示验证失败 @@ -334,82 +355,89 @@ public function check($data, $rules = [], $scene = '') */ protected function checkItem($field, $value, $rules, $data, $title = '', $msg = []) { - if ($rules instanceof \Closure) { - // 匿名函数验证 支持传入当前字段和所有字段两个数据 - $result = call_user_func_array($rules, [$value, $data]); - } else { - // 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...] - if (is_string($rules)) { - $rules = explode('|', $rules); - } - $i = 0; - foreach ($rules as $key => $rule) { - if ($rule instanceof \Closure) { - $result = call_user_func_array($rule, [$value, $data]); - } else { - // 判断验证类型 - if (is_numeric($key)) { - if (strpos($rule, ':')) { - list($type, $rule) = explode(':', $rule, 2); - if (isset($this->alias[$type])) { - // 判断别名 - $type = $this->alias[$type]; - } - $info = $type; - } elseif (method_exists($this, $rule)) { - $type = $rule; - $info = $rule; - $rule = ''; - } else { - $type = 'is'; - $info = $rule; + // 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...] + if (is_string($rules)) { + $rules = explode('|', $rules); + } + $i = 0; + foreach ($rules as $key => $rule) { + if ($rule instanceof \Closure) { + $result = call_user_func_array($rule, [$value, $data]); + $info = is_numeric($key) ? '' : $key; + } else { + // 判断验证类型 + if (is_numeric($key)) { + if (strpos($rule, ':')) { + list($type, $rule) = explode(':', $rule, 2); + if (isset($this->alias[$type])) { + // 判断别名 + $type = $this->alias[$type]; } + $info = $type; + } elseif (method_exists($this, $rule)) { + $type = $rule; + $info = $rule; + $rule = ''; } else { - $info = $type = $key; + $type = 'is'; + $info = $rule; } + } else { + $info = $type = $key; + } - // 如果不是require 有数据才会行验证 - if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { - // 验证类型 - $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type]; - // 验证数据 - $result = call_user_func_array($callback, [$value, $rule, $data, $field]); - } else { - $result = true; - } + // 如果不是require 有数据才会行验证 + if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { + // 验证类型 + $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type]; + // 验证数据 + $result = call_user_func_array($callback, [$value, $rule, $data, $field, $title]); + } else { + $result = true; } + } - if (false === $result) { - // 验证失败 返回错误信息 - if (isset($msg[$i])) { - $message = $msg[$i]; - if (is_string($message) && strpos($message, '{%') === 0) { - $message = Lang::get(substr($message, 2, -1)); - } - } else { - $message = $this->getRuleMsg($field, $title, $info, $rule); + if (false === $result) { + // 验证失败 返回错误信息 + if (isset($msg[$i])) { + $message = $msg[$i]; + if (is_string($message) && strpos($message, '{%') === 0) { + $message = Lang::get(substr($message, 2, -1)); } - return $message; - } elseif (true !== $result) { - // 返回自定义错误信息 - return $result; + } else { + $message = $this->getRuleMsg($field, $title, $info, $rule); + } + return $message; + } elseif (true !== $result) { + // 返回自定义错误信息 + if (is_string($result) && false !== strpos($result, ':')) { + $result = str_replace([':attribute', ':rule'], [$title, (string) $rule], $result); } - $i++; + return $result; } + $i++; } - return true !== $result ? $result : true; + return $result; } /** * 验证是否和某个字段的值一致 * @access protected - * @param mixed $value 字段值 + * @param mixed $value 字段值 * @param mixed $rule 验证规则 * @param array $data 数据 + * @param string $field 字段名 * @return bool */ - protected function confirm($value, $rule, $data) + protected function confirm($value, $rule, $data, $field = '') { + if ('' == $rule) { + if (strpos($field, '_confirm')) { + $rule = strstr($field, '_confirm', true); + } else { + $rule = $field . '_confirm'; + } + } return $this->getDataValue($data, $rule) == $value; } @@ -1174,6 +1202,8 @@ protected function getRuleMsg($attribute, $title, $type, $rule) { if (isset($this->message[$attribute . '.' . $type])) { $msg = $this->message[$attribute . '.' . $type]; + } elseif (isset($this->message[$attribute][$type])) { + $msg = $this->message[$attribute][$type]; } elseif (isset($this->message[$attribute])) { $msg = $this->message[$attribute]; } elseif (isset(self::$typeMsg[$type])) { @@ -1182,11 +1212,11 @@ protected function getRuleMsg($attribute, $title, $type, $rule) $msg = $title . '规则错误'; } - if (is_string($msg) && strpos($msg, '{%')) { + if (is_string($msg) && 0 === strpos($msg, '{%')) { $msg = Lang::get(substr($msg, 2, -1)); } - if (is_string($msg) && false !== strpos($msg, ':')) { + if (is_string($msg) && is_string($rule) && false !== strpos($msg, ':')) { // 变量替换 if (strpos($rule, ',')) { $array = array_pad(explode(',', $rule), 3, ''); @@ -1228,7 +1258,7 @@ protected function getScene($scene = '') public static function __callStatic($method, $params) { - $class = new static; + $class = self::make(); if (method_exists($class, $method)) { return call_user_func_array([$class, $method], $params); } else { diff --git a/thinkphp/library/think/View.php b/thinkphp/library/think/View.php index da08703..b724ba9 100644 --- a/thinkphp/library/think/View.php +++ b/thinkphp/library/think/View.php @@ -11,6 +11,9 @@ namespace think; +use think\Loader; +use think\Request; + class View { // 视图实例 @@ -19,6 +22,8 @@ class View public $engine; // 模板变量 protected $data = []; + // 用于静态赋值的模板变量 + protected static $var = []; // 视图输出替换 protected $replace = []; @@ -32,7 +37,21 @@ public function __construct($engine = [], $replace = []) { // 初始化模板引擎 $this->engine((array) $engine); - $this->replace = $replace; + // 基础替换字符串 + $request = Request::instance(); + $base = $request->root(); + $root = strpos($base, '.') ? ltrim(dirname($base), DS) : $base; + if ('' != $root) { + $root = '/' . ltrim($root, '/'); + } + $baseReplace = [ + '__ROOT__' => $root, + '__URL__' => $base . '/' . $request->module() . '/' . Loader::parseName($request->controller()), + '__STATIC__' => $root . '/static', + '__CSS__' => $root . '/static/css', + '__JS__' => $root . '/static/js', + ]; + $this->replace = array_merge($baseReplace, (array) $replace); } /** @@ -50,6 +69,22 @@ public static function instance($engine = [], $replace = []) return self::$instance; } + /** + * 模板变量静态赋值 + * @access public + * @param mixed $name 变量名 + * @param mixed $value 变量值 + * @return void + */ + public static function share($name, $value = '') + { + if (is_array($name)) { + self::$var = array_merge(self::$var, $name); + } else { + self::$var[$name] = $value; + } + } + /** * 模板变量赋值 * @access public @@ -116,7 +151,7 @@ public function config($name, $value = null) public function fetch($template = '', $vars = [], $replace = [], $config = [], $renderContent = false) { // 模板变量 - $vars = array_merge($this->data, $vars); + $vars = array_merge(self::$var, $this->data, $vars); // 页面缓存 ob_start(); diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php index 69484ff..49b3aeb 100644 --- a/thinkphp/library/think/db/Builder.php +++ b/thinkphp/library/think/db/Builder.php @@ -37,22 +37,33 @@ abstract class Builder /** * 架构函数 * @access public - * @param Connection $connection 数据库连接对象实例 + * @param Connection $connection 数据库连接对象实例 + * @param Query $query 数据库查询对象实例 */ - public function __construct(Connection $connection) + public function __construct(Connection $connection, Query $query) { $this->connection = $connection; + $this->query = $query; } /** - * 设置当前的Query对象实例 - * @access protected - * @param Query $query 当前查询对象实例 + * 获取当前的连接对象实例 + * @access public + * @return void + */ + public function getConnection() + { + return $this->connection; + } + + /** + * 获取当前的Query对象实例 + * @access public * @return void */ - public function setQuery(Query $query) + public function getQuery() { - $this->query = $query; + return $this->query; } /** @@ -90,7 +101,7 @@ protected function parseData($data, $options) $result = []; foreach ($data as $key => $val) { $item = $this->parseKey($key, $options); - if (!in_array($key, $fields, true)) { + if (false === strpos($key, '.') && !in_array($key, $fields, true)) { if ($options['strict']) { throw new Exception('fields not exists:[' . $key . ']'); } @@ -100,9 +111,10 @@ protected function parseData($data, $options) $result[$item] = 'NULL'; } elseif (is_scalar($val)) { // 过滤非标量数据 - if ($this->query->isBind(substr($val, 1))) { + if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) { $result[$item] = $val; } else { + $key = str_replace('.', '_', $key); $this->query->bind($key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR); $result[$item] = ':' . $key; } @@ -182,6 +194,9 @@ protected function parseTable($tables, $options = []) $item = []; foreach ((array) $tables as $key => $table) { if (!is_numeric($key)) { + if (strpos($key, '@think')) { + $key = strstr($key, '@think', true); + } $key = $this->parseSqlTable($key); $item[] = $this->parseKey($key) . ' ' . $this->parseKey($table); } else { @@ -306,7 +321,7 @@ protected function parseWhereItem($field, $val, $rule = '', $options = [], $bind 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))) { if ($this->query->isBind($bindName)) { - $bindName .= '_' . uniqid(); + $bindName .= '_' . str_replace('.', '_', uniqid('', true)); } $this->query->bind($bindName, $value, $bindType); $value = ':' . $bindName; @@ -333,8 +348,13 @@ protected function parseWhereItem($field, $val, $rule = '', $options = [], $bind $bind = []; $array = []; foreach ($value as $k => $v) { - $bind[$bindName . '_in_' . $k] = [$v, $bindType]; - $array[] = ':' . $bindName . '_in_' . $k; + if ($this->query->isBind($bindName . '_in_' . $k)) { + $bindKey = $bindName . '_in_' . uniqid() . '_' . $k; + } else { + $bindKey = $bindName . '_in_' . $k; + } + $bind[$bindKey] = [$v, $bindType]; + $array[] = ':' . $bindKey; } $this->query->bind($bind); $zone = implode(',', $array); @@ -347,12 +367,19 @@ protected function parseWhereItem($field, $val, $rule = '', $options = [], $bind // BETWEEN 查询 $data = is_array($value) ? $value : explode(',', $value); if (array_key_exists($field, $binds)) { + if ($this->query->isBind($bindName . '_between_1')) { + $bindKey1 = $bindName . '_between_1' . uniqid(); + $bindKey2 = $bindName . '_between_2' . uniqid(); + } else { + $bindKey1 = $bindName . '_between_1'; + $bindKey2 = $bindName . '_between_2'; + } $bind = [ - $bindName . '_between_1' => [$data[0], $bindType], - $bindName . '_between_2' => [$data[1], $bindType], + $bindKey1 => [$data[0], $bindType], + $bindKey2 => [$data[1], $bindType], ]; $this->query->bind($bind); - $between = ':' . $bindName . '_between_1' . ' AND :' . $bindName . '_between_2'; + $between = ':' . $bindKey1 . ' AND :' . $bindKey2; } else { $between = $this->parseValue($data[0], $field) . ' AND ' . $this->parseValue($data[1], $field); } @@ -397,12 +424,23 @@ protected function parseClosure($call, $show = true) protected function parseDateTime($value, $key, $options = [], $bindName = null, $bindType = null) { // 获取时间字段类型 - $type = $this->query->getFieldsType($options); + if (strpos($key, '.')) { + list($table, $key) = explode('.', $key); + if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) { + $table = $pos; + } + } else { + $table = $options['table']; + } + $type = $this->query->getTableInfo($table, 'type'); if (isset($type[$key])) { $info = $type[$key]; } if (isset($info)) { - $value = strtotime($value) ?: $value; + if (is_string($value)) { + $value = strtotime($value) ?: $value; + } + if (preg_match('/(datetime|timestamp)/is', $info)) { // 日期及时间戳类型 $value = date('Y-m-d H:i:s', $value); diff --git a/thinkphp/library/think/db/Connection.php b/thinkphp/library/think/db/Connection.php index 9806b82..f7d3316 100644 --- a/thinkphp/library/think/db/Connection.php +++ b/thinkphp/library/think/db/Connection.php @@ -421,8 +421,8 @@ public function getRealSql($sql, array $bind = []) $type = is_array($val) ? $val[1] : PDO::PARAM_STR; if (PDO::PARAM_STR == $type) { $value = $this->quote($value); - } elseif (PDO::PARAM_INT == $type && '' === $value) { - $value = 0; + } elseif (PDO::PARAM_INT == $type) { + $value = (float) $value; } // 判断占位符 $sql = is_numeric($key) ? @@ -489,10 +489,7 @@ protected function getResult($class = '', $procedure = false) $result = $this->PDOStatement->fetchAll($this->fetchType); $this->numRows = count($result); - if (!empty($class)) { - // 返回指定数据集对象类 - $result = new $class($result); - } elseif ('collection' == $this->resultSetType) { + if ('collection' == $this->resultSetType) { // 返回数据集Collection对象 $result = new Collection($result); } diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php index 3f4d5fd..ace9a90 100644 --- a/thinkphp/library/think/db/Query.php +++ b/thinkphp/library/think/db/Query.php @@ -27,13 +27,14 @@ use think\Loader; use think\Model; use think\model\Relation; +use think\model\relation\OneToOne; use think\Paginator; class Query { // 数据库Connection对象实例 protected $connection; - // 数据库驱动类型 + // 数据库Builder对象实例 protected $builder; // 当前模型类名称 protected $model; @@ -51,6 +52,8 @@ class Query protected $bind = []; // 数据表信息 protected static $info = []; + // 回调事件 + private static $event = []; /** * 架构函数 @@ -61,9 +64,10 @@ class Query public function __construct(Connection $connection = null, $model = '') { $this->connection = $connection ?: Db::connect([], true); - $this->builder = $this->connection->getConfig('builder') ?: $this->connection->getConfig('type'); $this->prefix = $this->connection->getConfig('prefix'); $this->model = $model; + // 设置当前连接的Builder对象 + $this->setBuilder(); } /** @@ -111,9 +115,42 @@ public function getConnection() public function connect($config) { $this->connection = Db::connect($config); + $this->setBuilder(); return $this; } + /** + * 设置当前的数据库Builder对象 + * @access protected + * @return void + */ + protected function setBuilder() + { + $builder = $this->connection->getConfig('builder') ?: $this->connection->getConfig('type'); + $class = false !== strpos($builder, '\\') ? $builder : '\\think\\db\\builder\\' . ucfirst($builder); + $this->builder = new $class($this->connection, $this); + } + + /** + * 获取当前的模型对象名 + * @access public + * @return string + */ + public function getModel() + { + return $this->model; + } + + /** + * 获取当前的builder实例对象 + * @access public + * @return Builder + */ + public function getBuilder() + { + return $this->builder; + } + /** * 指定默认的数据表名(不含前缀) * @access public @@ -350,35 +387,18 @@ public function getPartitionTableName($data, $field, $rule = []) } } - /** - * 获取当前的builder实例对象 - * @access protected - * @return Builder - */ - protected function builder() - { - static $builder = []; - $driver = $this->builder; - if (!isset($builder[$driver])) { - $class = false !== strpos($driver, '\\') ? $driver : '\\think\\db\\builder\\' . ucfirst($driver); - $builder[$driver] = new $class($this->connection); - } - // 设置当前查询对象 - $builder[$driver]->setQuery($this); - return $builder[$driver]; - } - /** * 得到某个字段的值 * @access public * @param string $field 字段名 * @param mixed $default 默认值 + * @param bool $force 强制转为数字类型 * @return mixed */ - public function value($field, $default = null) + public function value($field, $default = null, $force = false) { $result = false; - if (!empty($this->options['cache'])) { + if (empty($options['fetch_sql']) && !empty($this->options['cache'])) { // 判断查询缓存 $cache = $this->options['cache']; if (empty($this->options['table'])) { @@ -397,6 +417,9 @@ public function value($field, $default = null) return $pdo; } $result = $pdo->fetchColumn(); + if ($force) { + $result = is_numeric($result) ? $result + 0 : $result; + } if (isset($cache)) { // 缓存数据 if (isset($cache['tag'])) { @@ -422,7 +445,7 @@ public function value($field, $default = null) public function column($field, $key = '') { $result = false; - if (!empty($this->options['cache'])) { + if (empty($options['fetch_sql']) && !empty($this->options['cache'])) { // 判断查询缓存 $cache = $this->options['cache']; if (empty($this->options['table'])) { @@ -453,6 +476,9 @@ public function column($field, $key = '') $key1 = array_shift($fields); $key2 = $fields ? array_shift($fields) : ''; $key = $key ?: $key1; + if (strpos($key, '.')) { + list($alias, $key) = explode('.', $key); + } foreach ($resultSet as $val) { if ($count > 2) { $result[$val[$key]] = $val; @@ -489,7 +515,7 @@ public function column($field, $key = '') */ public function count($field = '*') { - return (int) $this->value('COUNT(' . $field . ') AS tp_count', 0); + return $this->value('COUNT(' . $field . ') AS tp_count', 0, true); } /** @@ -500,7 +526,7 @@ public function count($field = '*') */ public function sum($field = '*') { - return $this->value('SUM(' . $field . ') AS tp_sum', 0) + 0; + return $this->value('SUM(' . $field . ') AS tp_sum', 0, true); } /** @@ -511,8 +537,7 @@ public function sum($field = '*') */ public function min($field = '*') { - $value = $this->value('MIN(' . $field . ') AS tp_min', 0); - return is_numeric($value) ? $value + 0 : $value; + return $this->value('MIN(' . $field . ') AS tp_min', 0, true); } /** @@ -523,8 +548,7 @@ public function min($field = '*') */ public function max($field = '*') { - $value = $this->value('MAX(' . $field . ') AS tp_max', 0); - return is_numeric($value) ? $value + 0 : $value; + return $this->value('MAX(' . $field . ') AS tp_max', 0, true); } /** @@ -535,7 +559,7 @@ public function max($field = '*') */ public function avg($field = '*') { - return $this->value('AVG(' . $field . ') AS tp_avg', 0) + 0; + return $this->value('AVG(' . $field . ') AS tp_avg', 0, true); } /** @@ -702,6 +726,9 @@ protected function getJoinTable($join, &$alias = null) } } if (isset($alias)) { + if (isset($this->options['alias'][$table])) { + $table = $table . '@think' . uniqid(); + } $table = [$table => $alias]; $this->alias($table); } @@ -915,6 +942,9 @@ protected function parseWhereExp($logic, $field, $op, $condition, $param = []) if (is_array($field)) { // 数组批量查询 $where = $field; + foreach ($where as $k => $val) { + $this->options['multi'][$k][] = $val; + } } elseif ($field && is_string($field)) { // 字符串查询 $where[$field] = ['null', '']; @@ -929,15 +959,32 @@ protected function parseWhereExp($logic, $field, $op, $condition, $param = []) $where[$field] = ['eq', $op]; } else { $where[$field] = [$op, $condition]; + // 记录一个字段多次查询条件 + $this->options['multi'][$field][] = $where[$field]; } if (!empty($where)) { if (!isset($this->options['where'][$logic])) { $this->options['where'][$logic] = []; } + if (is_string($field) && $this->checkMultiField($field)) { + $where[$field] = $this->options['multi'][$field]; + } elseif (is_array($field)) { + foreach ($field as $key => $val) { + if ($this->checkMultiField($key)) { + $where[$key] = $this->options['multi'][$key]; + } + } + } $this->options['where'][$logic] = array_merge($this->options['where'][$logic], $where); } } + // 检查是否存在一个字段多次查询条件 + private function checkMultiField($field) + { + return isset($this->options['multi'][$field]) && count($this->options['multi'][$field]) > 1; + } + /** * 去除某个查询条件 * @access public @@ -954,6 +1001,20 @@ public function removeWhereField($field, $logic = 'AND') return $this; } + /** + * 去除某个查询参数 + * @access public + * @param string $option 参数名 + * @return $this + */ + public function removeOption($option) + { + if (isset($this->options[$option])) { + unset($this->options[$option]); + } + return $this; + } + /** * 指定查询数量 * @access public @@ -1047,7 +1108,9 @@ public function paginate($listRows = null, $simple = false, $config = []) public function table($table) { if (is_string($table)) { - if (strpos($table, ',')) { + if (strpos($table, ')')) { + // 子查询 + } elseif (strpos($table, ',')) { $tables = explode(',', $table); $table = []; foreach ($tables as $item) { @@ -1061,7 +1124,8 @@ public function table($table) } } elseif (strpos($table, ' ')) { list($table, $alias) = explode(' ', $table); - $table = [$table => $alias]; + + $table = [$table => $alias]; $this->alias($table); } } else { @@ -1267,18 +1331,6 @@ public function fetchPdo($pdo = true) return $this; } - /** - * 指定数据集返回对象 - * @access public - * @param string $class 指定返回的数据集对象类名 - * @return $this - */ - public function fetchClass($class) - { - $this->options['fetch_class'] = $class; - return $this; - } - /** * 设置从主服务器读取数据 * @access public @@ -1410,10 +1462,16 @@ public function getTableInfo($tableName = '', $fetch = '') $tableName = $this->parseSqlTable($tableName); } + // 修正子查询作为表名的问题 + if (strpos($tableName, ')')) { + return []; + } + list($guid) = explode(' ', $tableName); - if (!isset(self::$info[$guid])) { + $db = $this->getConfig('database'); + if (!isset(self::$info[$db . '.' . $guid])) { if (!strpos($guid, '.')) { - $schema = $this->getConfig('database') . '.' . $guid; + $schema = $db . '.' . $guid; } else { $schema = $guid; } @@ -1439,9 +1497,9 @@ public function getTableInfo($tableName = '', $fetch = '') } else { $pk = null; } - self::$info[$guid] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk]; + self::$info[$db . '.' . $guid] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk]; } - return $fetch ? self::$info[$guid][$fetch] : self::$info[$guid]; + return $fetch ? self::$info[$db . '.' . $guid][$fetch] : self::$info[$db . '.' . $guid]; } /** @@ -1575,13 +1633,14 @@ public function with($with) $with = explode(',', $with); } - $i = 0; + $first = true; $currentModel = $this->model; /** @var Model $class */ $class = new $currentModel; foreach ($with as $key => $relation) { - $closure = false; + $subRelation = ''; + $closure = false; if ($relation instanceof \Closure) { // 支持闭包查询过滤关联条件 $closure = $relation; @@ -1593,49 +1652,11 @@ public function with($with) } /** @var Relation $model */ - $model = $class->$relation(); - $info = $model->getRelationInfo(); - if (in_array($info['type'], [Relation::HAS_ONE, Relation::BELONGS_TO])) { - if (0 == $i) { - $name = Loader::parseName(basename(str_replace('\\', '/', $currentModel))); - $table = $this->getTable(); - $alias = isset($info['alias'][$name]) ? $info['alias'][$name] : $name; - $this->table([$table => $alias]); - if (isset($this->options['field'])) { - $field = $this->options['field']; - unset($this->options['field']); - } else { - $field = true; - } - $this->field($field, false, $table, $alias); - } - // 预载入封装 - $joinTable = $model->getTable(); - $joinName = Loader::parseName(basename(str_replace('\\', '/', $info['model']))); - $joinAlias = isset($info['alias'][$joinName]) ? $info['alias'][$joinName] : $relation; - $this->via($joinAlias); - - if (Relation::HAS_ONE == $info['type']) { - $this->join($joinTable . ' ' . $joinAlias, $alias . '.' . $info['localKey'] . '=' . $joinAlias . '.' . $info['foreignKey'], $info['joinType']); - } else { - $this->join($joinTable . ' ' . $joinAlias, $alias . '.' . $info['foreignKey'] . '=' . $joinAlias . '.' . $info['localKey'], $info['joinType']); - } - - if ($closure) { - // 执行闭包查询 - call_user_func_array($closure, [ & $this]); - //指定获取关联的字段 - //需要在 回调中 调方法 withField 方法,如 - // $query->where(['id'=>1])->withField('id,name'); - if (!empty($this->options['with_field'])) { - $field = $this->options['with_field']; - unset($this->options['with_field']); - } - } elseif (isset($info['option']['field'])) { - $field = $info['option']['field']; - } - $this->field($field, false, $joinTable, $joinAlias, $relation . '__'); - $i++; + $relation = Loader::parseName($relation, 1, false); + $model = $class->$relation(); + if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) { + $model->eagerly($this, $relation, $subRelation, $closure, $first); + $first = false; } elseif ($closure) { $with[$key] = $closure; } @@ -1745,7 +1766,7 @@ public function insert(array $data, $replace = false, $getLastInsID = false, $se // 分析查询表达式 $options = $this->parseExpress(); // 生成SQL语句 - $sql = $this->builder()->insert($data, $options, $replace); + $sql = $this->builder->insert($data, $options, $replace); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { @@ -1755,6 +1776,9 @@ public function insert(array $data, $replace = false, $getLastInsID = false, $se // 执行操作 $result = $this->execute($sql, $bind); + if ($result) { + $this->trigger('after_insert', $options); + } if ($getLastInsID) { $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); return $this->getLastInsID($sequence); @@ -1789,7 +1813,7 @@ public function insertAll(array $dataSet) return false; } // 生成SQL语句 - $sql = $this->builder()->insertAll($dataSet, $options); + $sql = $this->builder->insertAll($dataSet, $options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { @@ -1815,7 +1839,7 @@ public function selectInsert($fields, $table) $options = $this->parseExpress(); // 生成SQL语句 $table = $this->parseSqlTable($table); - $sql = $this->builder()->selectInsert($fields, $table, $options); + $sql = $this->builder->selectInsert($fields, $table, $options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { @@ -1873,7 +1897,7 @@ public function update(array $data) $key = 'think:' . $options['table'] . '|' . $options['where']['AND'][$pk]; } // 生成UPDATE SQL语句 - $sql = $this->builder()->update($data, $options); + $sql = $this->builder->update($data, $options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { @@ -1886,7 +1910,11 @@ public function update(array $data) Cache::rm($key); } // 执行操作 - return '' == $sql ? 0 : $this->execute($sql, $bind); + $result = '' == $sql ? 0 : $this->execute($sql, $bind); + if ($result) { + $this->trigger('after_update', $options); + } + return $result; } } @@ -1928,19 +1956,22 @@ public function select($data = null) } if (!$resultSet) { // 生成查询SQL - $sql = $this->builder()->select($options); + $sql = $this->builder->select($options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); } - // 执行查询操作 - $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_class']); + if ($resultSet = $this->trigger('before_select', $options)) { + } else { + // 执行查询操作 + $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_class']); - if ($resultSet instanceof \PDOStatement) { - // 返回PDOStatement对象 - return $resultSet; + if ($resultSet instanceof \PDOStatement) { + // 返回PDOStatement对象 + return $resultSet; + } } if (isset($cache)) { @@ -1953,12 +1984,11 @@ public function select($data = null) } } - // 返回结果处理 - if (count($resultSet) > 0) { - // 数据列表读取后的处理 - if (!empty($this->model)) { - // 生成模型对象 - $model = $this->model; + // 数据列表读取后的处理 + if (!empty($this->model)) { + // 生成模型对象 + $model = $this->model; + if (count($resultSet) > 0) { foreach ($resultSet as $key => $result) { /** @var Model $result */ $result = new $model($result); @@ -1969,12 +1999,16 @@ public function select($data = null) } $resultSet[$key] = $result; } - if (!empty($options['with']) && $result instanceof Model) { + if (!empty($options['with'])) { // 预载入 - $resultSet = $result->eagerlyResultSet($resultSet, $options['with'], is_object($resultSet) ? get_class($resultSet) : ''); + $result->eagerlyResultSet($resultSet, $options['with'], is_object($resultSet) ? get_class($resultSet) : ''); } } - } elseif (!empty($options['fail'])) { + // 模型数据集转换 + $resultSet = (new $model)->toCollection($resultSet); + } + // 返回结果处理 + if (!empty($options['fail']) && count($resultSet) == 0) { $this->throwNotFound($options); } return $resultSet; @@ -2019,19 +2053,24 @@ public function find($data = null) } if (!$result) { // 生成查询SQL - $sql = $this->builder()->select($options); + $sql = $this->builder->select($options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); } - // 执行查询 - $result = $this->query($sql, $bind, $options['master'], $options['fetch_class']); - if ($result instanceof \PDOStatement) { - // 返回PDOStatement对象 - return $result; + // 事件回调 + if ($result = $this->trigger('before_find', $options)) { + } else { + // 执行查询 + $result = $this->query($sql, $bind, $options['master'], $options['fetch_class']); + + if ($result instanceof \PDOStatement) { + // 返回PDOStatement对象 + return $result; + } } if (isset($cache)) { @@ -2133,19 +2172,30 @@ public function chunk($count, $callback, $column = null) $column = $column ?: $this->getPk($table); $bind = $this->bind; $resultSet = $this->limit($count)->order($column, 'asc')->select(); + if (strpos($column, '.')) { + list($alias, $key) = explode('.', $column); + } else { + $key = $column; + } + if ($resultSet instanceof Collection) { + $resultSet = $resultSet->all(); + } while (!empty($resultSet)) { if (false === call_user_func($callback, $resultSet)) { return false; } $end = end($resultSet); - $lastId = is_array($end) ? $end[$column] : $end->$column; + $lastId = is_array($end) ? $end[$key] : $end->$key; $resultSet = $this->options($options) ->limit($count) ->bind($bind) ->where($column, '>', $lastId) ->order($column, 'asc') ->select(); + if ($resultSet instanceof Collection) { + $resultSet = $resultSet->all(); + } } return true; } @@ -2204,7 +2254,7 @@ public function delete($data = null) throw new Exception('delete without condition'); } // 生成删除SQL语句 - $sql = $this->builder()->delete($options); + $sql = $this->builder->delete($options); // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { @@ -2218,7 +2268,11 @@ public function delete($data = null) Cache::rm($key); } // 执行操作 - return $this->execute($sql, $bind); + $result = $this->execute($sql, $bind); + if ($result) { + $this->trigger('after_delete', $options); + } + return $result; } /** @@ -2308,4 +2362,32 @@ protected function parseExpress() return $options; } + /** + * 注册回调方法 + * @access public + * @param string $event 事件名 + * @param callable $callback 回调方法 + * @return void + */ + public static function event($event, $callback) + { + self::$event[$event] = $callback; + } + + /** + * 触发事件 + * @access protected + * @param string $event 事件名 + * @param mixed $options 当前查询参数 + * @return bool + */ + protected function trigger($event, $options = []) + { + $result = false; + if (isset(self::$event[$event])) { + $callback = self::$event[$event]; + $result = call_user_func_array($callback, [$options, $this]); + } + return $result; + } } diff --git a/thinkphp/library/think/log/driver/File.php b/thinkphp/library/think/log/driver/File.php index c4e4627..b639fd0 100644 --- a/thinkphp/library/think/log/driver/File.php +++ b/thinkphp/library/think/log/driver/File.php @@ -11,6 +11,8 @@ namespace think\log\driver; +use think\App; + /** * 本地化调试输出到文件 */ @@ -35,9 +37,10 @@ public function __construct($config = []) * 日志写入接口 * @access public * @param array $log 日志信息 + * @param bool $depr 是否写入分割线 * @return bool */ - public function save(array $log = []) + public function save(array $log = [], $depr = true) { $now = date($this->config['time_format']); $destination = $this->config['path'] . date('Ym') . DS . date('d') . '.log'; @@ -50,25 +53,29 @@ public function save(array $log = []) rename($destination, dirname($destination) . DS . $_SERVER['REQUEST_TIME'] . '-' . basename($destination)); } - // 获取基本信息 - if (isset($_SERVER['HTTP_HOST'])) { - $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - } else { - $current_uri = "cmd:" . implode(' ', $_SERVER['argv']); - } + $depr = $depr ? "---------------------------------------------------------------\r\n" : ''; + $info = ''; + if (App::$debug) { + // 获取基本信息 + if (isset($_SERVER['HTTP_HOST'])) { + $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + } else { + $current_uri = "cmd:" . implode(' ', $_SERVER['argv']); + } - $runtime = number_format(microtime(true) - THINK_START_TIME, 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; - $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); - $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; - $file_load = ' [文件加载:' . count(get_included_files()) . ']'; + $runtime = round(microtime(true) - THINK_START_TIME, 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; + $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); + $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; + $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - $info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n"; - $server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0'; - $remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; - $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; - $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + $info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n"; + $server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0'; + $remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; + $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; + $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + } foreach ($log as $type => $val) { $level = ''; foreach ($val as $msg) { @@ -80,12 +87,15 @@ public function save(array $log = []) if (in_array($type, $this->config['apart_level'])) { // 独立记录的日志级别 $filename = $path . DS . date('d') . '_' . $type . '.log'; - error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$level}\r\n---------------------------------------------------------------\r\n", 3, $filename); + error_log("[{$now}] {$level}\r\n{$depr}", 3, $filename); } else { $info .= $level; } } - return error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$info}\r\n---------------------------------------------------------------\r\n", 3, $destination); + if (App::$debug) { + $info = "{$server} {$remote} {$method} {$uri}\r\n" . $info; + } + return error_log("[{$now}] {$info}\r\n{$depr}", 3, $destination); } } diff --git a/thinkphp/library/think/log/driver/Socket.php b/thinkphp/library/think/log/driver/Socket.php index f24b609..612a902 100644 --- a/thinkphp/library/think/log/driver/Socket.php +++ b/thinkphp/library/think/log/driver/Socket.php @@ -11,6 +11,8 @@ namespace think\log\driver; +use think\App; + /** * github: https://github.com/luofei614/SocketLog * @author luofei614 @@ -63,24 +65,27 @@ public function save(array $log = []) if (!$this->check()) { return false; } - $runtime = number_format(microtime(true) - THINK_START_TIME, 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; - $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); - $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; - $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - - if (isset($_SERVER['HTTP_HOST'])) { - $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - } else { - $current_uri = 'cmd:' . implode(' ', $_SERVER['argv']); + $trace = []; + if (App::$debug) { + $runtime = round(microtime(true) - THINK_START_TIME, 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; + $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); + $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; + $file_load = ' [文件加载:' . count(get_included_files()) . ']'; + + if (isset($_SERVER['HTTP_HOST'])) { + $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + } else { + $current_uri = 'cmd:' . implode(' ', $_SERVER['argv']); + } + // 基本信息 + $trace[] = [ + 'type' => 'group', + 'msg' => $current_uri . $time_str . $memory_str . $file_load, + 'css' => $this->css['page'], + ]; } - // 基本信息 - $trace[] = [ - 'type' => 'group', - 'msg' => $current_uri . $time_str . $memory_str . $file_load, - 'css' => $this->css['page'], - ]; foreach ($log as $type => $val) { $trace[] = [ diff --git a/thinkphp/library/think/model/Relation.php b/thinkphp/library/think/model/Relation.php index f9675c1..4fc68ff 100644 --- a/thinkphp/library/think/model/Relation.php +++ b/thinkphp/library/think/model/Relation.php @@ -11,32 +11,18 @@ namespace think\model; -use think\Db; +use think\db\Query; use think\Exception; -use think\Loader; use think\Model; -use think\model\Pivot; -class Relation +abstract class Relation { - const HAS_ONE = 1; - const HAS_MANY = 2; - const HAS_MANY_THROUGH = 5; - const BELONGS_TO = 3; - const BELONGS_TO_MANY = 4; - // 父模型对象 protected $parent; /** @var Model 当前关联的模型类 */ protected $model; - // 中间表模型 - protected $middle; - // 当前关联类型 - protected $type; // 关联表外键 protected $foreignKey; - // 中间关联表外键 - protected $throughKey; // 关联表主键 protected $localKey; // 数据表别名 @@ -49,180 +35,37 @@ class Relation protected $where; // 关联查询参数 protected $option; + // 基础查询 + protected $baseQuery; + /** - * 架构函数 + * 获取关联的所属模型 * @access public - * @param Model $model 上级模型对象 + * @return Model */ - public function __construct(Model $model) + public function getParent() { - $this->parent = $model; + return $this->parent; } /** - * 获取当前关联信息 + * 获取当前的关联模型类 * @access public - * @param string $name 关联信息 - * @return array|string|integer + * @return string */ - public function getRelationInfo($name = '') - { - $info = [ - 'type' => $this->type, - 'model' => $this->model, - 'middle' => $this->middle, - 'foreignKey' => $this->foreignKey, - 'localKey' => $this->localKey, - 'alias' => $this->alias, - 'joinType' => $this->joinType, - 'option' => $this->option, - ]; - return $name ? $info[$name] : $info; - } - - // 获取关联数据 - public function getRelation($name) + public function getModel() { - // 执行关联定义方法 - $relation = $this->parent->$name(); - $foreignKey = $this->foreignKey; - $localKey = $this->localKey; - - // 判断关联类型执行查询 - switch ($this->type) { - case self::HAS_ONE: - $result = $relation->where($foreignKey, $this->parent->$localKey)->find(); - break; - case self::BELONGS_TO: - $result = $relation->where($localKey, $this->parent->$foreignKey)->find(); - break; - case self::HAS_MANY: - $result = $relation->select(); - break; - case self::HAS_MANY_THROUGH: - $result = $relation->select(); - break; - case self::BELONGS_TO_MANY: - // 关联查询 - $pk = $this->parent->getPk(); - $condition['pivot.' . $localKey] = $this->parent->$pk; - $result = $this->belongsToManyQuery($relation, $this->middle, $foreignKey, $localKey, $condition)->select(); - foreach ($result as $set) { - $pivot = []; - foreach ($set->getData() as $key => $val) { - if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); - if ('pivot' == $name) { - $pivot[$attr] = $val; - unset($set->$key); - } - } - } - $set->pivot = new Pivot($pivot, $this->middle); - } - break; - default: - // 直接返回 - $result = $relation; - } - return $result; + return $this->model; } /** - * 预载入关联查询 返回数据集 + * 获取关联的查询对象 * @access public - * @param array $resultSet 数据集 - * @param string $relation 关联名 - * @param string $class 数据集对象名 为空表示数组 - * @return array + * @return Query */ - public function eagerlyResultSet($resultSet, $relation, $class = '') + public function getQuery() { - /** @var array $relations */ - $relations = is_string($relation) ? explode(',', $relation) : $relation; - - foreach ($relations as $key => $relation) { - $subRelation = ''; - $closure = false; - if ($relation instanceof \Closure) { - $closure = $relation; - $relation = $key; - } - if (strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation); - } - // 执行关联方法 - $model = $this->parent->$relation(); - // 获取关联信息 - $localKey = $this->localKey; - $foreignKey = $this->foreignKey; - switch ($this->type) { - case self::HAS_ONE: - case self::BELONGS_TO: - foreach ($resultSet as $result) { - // 模型关联组装 - $this->match($this->model, $relation, $result); - } - break; - case self::HAS_MANY: - $range = []; - foreach ($resultSet as $result) { - // 获取关联外键列表 - if (isset($result->$localKey)) { - $range[] = $result->$localKey; - } - } - - if (!empty($range)) { - $this->where[$foreignKey] = ['in', $range]; - $data = $this->eagerlyOneToMany($model, [ - $foreignKey => [ - 'in', - $range, - ], - ], $relation, $subRelation, $closure); - - // 关联数据封装 - foreach ($resultSet as $result) { - if (!isset($data[$result->$localKey])) { - $data[$result->$localKey] = []; - } - $result->setAttr($relation, $this->resultSetBuild($data[$result->$localKey], $class)); - } - } - break; - case self::BELONGS_TO_MANY: - $pk = $resultSet[0]->getPk(); - $range = []; - foreach ($resultSet as $result) { - // 获取关联外键列表 - if (isset($result->$pk)) { - $range[] = $result->$pk; - } - } - - if (!empty($range)) { - // 查询关联数据 - $data = $this->eagerlyManyToMany($model, [ - 'pivot.' . $localKey => [ - 'in', - $range, - ], - ], $relation, $subRelation); - - // 关联数据封装 - foreach ($resultSet as $result) { - if (!isset($data[$result->$pk])) { - $data[$result->$pk] = []; - } - - $result->setAttr($relation, $this->resultSetBuild($data[$result->$pk], $class)); - } - } - break; - } - } - return $resultSet; + return $this->query; } /** @@ -237,154 +80,6 @@ protected function resultSetBuild($resultSet, $class = '') return $class ? new $class($resultSet) : $resultSet; } - /** - * 预载入关联查询 返回模型对象 - * @access public - * @param Model $result 数据对象 - * @param string $relation 关联名 - * @param string $class 数据集对象名 为空表示数组 - * @return Model - */ - public function eagerlyResult($result, $relation, $class = '') - { - $relations = is_string($relation) ? explode(',', $relation) : $relation; - - foreach ($relations as $key => $relation) { - $subRelation = ''; - $closure = false; - if ($relation instanceof \Closure) { - $closure = $relation; - $relation = $key; - } - if (strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation); - } - // 执行关联方法 - $model = $this->parent->$relation(); - $localKey = $this->localKey; - $foreignKey = $this->foreignKey; - switch ($this->type) { - case self::HAS_ONE: - case self::BELONGS_TO: - // 模型关联组装 - $this->match($this->model, $relation, $result); - break; - case self::HAS_MANY: - if (isset($result->$localKey)) { - $data = $this->eagerlyOneToMany($model, [$foreignKey => $result->$localKey], $relation, $subRelation, $closure); - // 关联数据封装 - if (!isset($data[$result->$localKey])) { - $data[$result->$localKey] = []; - } - $result->setAttr($relation, $this->resultSetBuild($data[$result->$localKey], $class)); - } - break; - case self::BELONGS_TO_MANY: - $pk = $result->getPk(); - if (isset($result->$pk)) { - $pk = $result->$pk; - // 查询管理数据 - $data = $this->eagerlyManyToMany($model, ['pivot.' . $localKey => $pk], $relation, $subRelation); - - // 关联数据封装 - if (!isset($data[$pk])) { - $data[$pk] = []; - } - $result->setAttr($relation, $this->resultSetBuild($data[$pk], $class)); - } - break; - - } - } - return $result; - } - - /** - * 一对一 关联模型预查询拼装 - * @access public - * @param string $model 模型名称 - * @param string $relation 关联名 - * @param Model $result 模型对象实例 - * @return void - */ - protected function match($model, $relation, &$result) - { - // 重新组装模型数据 - foreach ($result->getData() as $key => $val) { - if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); - if ($name == $relation) { - $list[$name][$attr] = $val; - unset($result->$key); - } - } - } - - $result->setAttr($relation, !isset($list[$relation]) ? null : (new $model($list[$relation]))->isUpdate(true)); - } - - /** - * 一对多 关联模型预查询 - * @access public - * @param object $model 关联模型对象 - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param bool $closure - * @return array - */ - protected function eagerlyOneToMany($model, $where, $relation, $subRelation = '', $closure = false) - { - $foreignKey = $this->foreignKey; - // 预载入关联查询 支持嵌套预载入 - if ($closure) { - call_user_func_array($closure, [ & $model]); - } - $list = $model->where($where)->with($subRelation)->select(); - - // 组装模型数据 - $data = []; - foreach ($list as $set) { - $data[$set->$foreignKey][] = $set; - } - return $data; - } - - /** - * 多对多 关联模型预查询 - * @access public - * @param object $model 关联模型对象 - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @return array - */ - protected function eagerlyManyToMany($model, $where, $relation, $subRelation = '') - { - $foreignKey = $this->foreignKey; - $localKey = $this->localKey; - // 预载入关联查询 支持嵌套预载入 - $list = $this->belongsToManyQuery($model, $this->middle, $foreignKey, $localKey, $where)->with($subRelation)->select(); - - // 组装模型数据 - $data = []; - foreach ($list as $set) { - $pivot = []; - foreach ($set->getData() as $key => $val) { - if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); - if ('pivot' == $name) { - $pivot[$attr] = $val; - unset($set->$key); - } - } - } - $set->pivot = new Pivot($pivot, $this->middle); - $data[$pivot[$localKey]][] = $set; - } - return $data; - } - /** * 设置当前关联定义的数据表别名 * @access public @@ -397,309 +92,23 @@ public function setAlias($alias) return $this; } - /** - * HAS ONE 关联定义 - * @access public - * @param string $model 模型名 - * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 - * @param array $alias 别名定义 - * @param string $joinType JOIN类型 - * @return $this - */ - public function hasOne($model, $foreignKey, $localKey, $alias = [], $joinType = 'INNER') - { - $this->type = self::HAS_ONE; - $this->model = $model; - $this->foreignKey = $foreignKey; - $this->localKey = $localKey; - $this->alias = $alias; - $this->joinType = $joinType; - $this->query = (new $model)->db(); - // 返回关联的模型对象 - return $this; - } - - /** - * BELONGS TO 关联定义 - * @access public - * @param string $model 模型名 - * @param string $foreignKey 关联外键 - * @param string $otherKey 关联主键 - * @param array $alias 别名定义 - * @param string $joinType JOIN类型 - * @return $this - */ - public function belongsTo($model, $foreignKey, $otherKey, $alias = [], $joinType = 'INNER') - { - // 记录当前关联信息 - $this->type = self::BELONGS_TO; - $this->model = $model; - $this->foreignKey = $foreignKey; - $this->localKey = $otherKey; - $this->alias = $alias; - $this->joinType = $joinType; - $this->query = (new $model)->db(); - // 返回关联的模型对象 - return $this; - } - - /** - * HAS MANY 关联定义 - * @access public - * @param string $model 模型名 - * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 - * @param array $alias 别名定义 - * @return $this - */ - public function hasMany($model, $foreignKey, $localKey, $alias) - { - // 记录当前关联信息 - $this->type = self::HAS_MANY; - $this->model = $model; - $this->foreignKey = $foreignKey; - $this->localKey = $localKey; - $this->alias = $alias; - $this->query = (new $model)->db(); - // 返回关联的模型对象 - return $this; - } - - /** - * HAS MANY 远程关联定义 - * @access public - * @param string $model 模型名 - * @param string $through 中间模型名 - * @param string $firstkey 关联外键 - * @param string $secondKey 关联外键 - * @param string $localKey 关联主键 - * @param array $alias 别名定义 - * @return $this - */ - public function hasManyThrough($model, $through, $foreignKey, $throughKey, $localKey, $alias) - { - // 记录当前关联信息 - $this->type = self::HAS_MANY_THROUGH; - $this->model = $model; - $this->middle = $through; - $this->foreignKey = $foreignKey; - $this->throughKey = $throughKey; - $this->localKey = $localKey; - $this->alias = $alias; - $this->query = (new $model)->db(); - // 返回关联的模型对象 - return $this; - } - - /** - * BELONGS TO MANY 关联定义 - * @access public - * @param string $model 模型名 - * @param string $table 中间表名 - * @param string $foreignKey 关联模型外键 - * @param string $localKey 当前模型关联键 - * @param array $alias 别名定义 - * @return $this - */ - public function belongsToMany($model, $table, $foreignKey, $localKey, $alias) - { - // 记录当前关联信息 - $this->type = self::BELONGS_TO_MANY; - $this->model = $model; - $this->foreignKey = $foreignKey; - $this->localKey = $localKey; - $this->middle = $table; - $this->alias = $alias; - $this->query = (new $model)->db(); - // 返回关联的模型对象 - return $this; - } - - /** - * BELONGS TO MANY 关联查询 - * @access public - * @param object $model 关联模型对象 - * @param string $table 中间表名 - * @param string $foreignKey 关联模型关联键 - * @param string $localKey 当前模型关联键 - * @param array $condition 关联查询条件 - * @return \think\db\Query|string - */ - protected function belongsToManyQuery($model, $table, $foreignKey, $localKey, $condition = []) - { - // 关联查询封装 - $tableName = $model->getTable(); - $relationFk = $model->getPk(); - return $model::field($tableName . '.*') - ->field(true, false, $table, 'pivot', 'pivot__') - ->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) - ->where($condition); - } - - /** - * 保存(新增)当前关联数据对象 - * @access public - * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键 - * @param array $pivot 中间表额外数据 - * @return integer - */ - public function save($data, array $pivot = []) - { - // 判断关联类型 - switch ($this->type) { - case self::HAS_ONE: - case self::BELONGS_TO: - case self::HAS_MANY: - if ($data instanceof Model) { - $data = $data->getData(); - } - // 保存关联表数据 - $data[$this->foreignKey] = $this->parent->{$this->localKey}; - $model = new $this->model; - return $model->save($data); - case self::BELONGS_TO_MANY: - // 保存关联表/中间表数据 - return $this->attach($data, $pivot); - } - } - - /** - * 批量保存当前关联数据对象 - * @access public - * @param array $dataSet 数据集 - * @param array $pivot 中间表额外数据 - * @return integer - */ - public function saveAll(array $dataSet, array $pivot = []) - { - $result = false; - foreach ($dataSet as $key => $data) { - // 判断关联类型 - switch ($this->type) { - case self::HAS_MANY: - $data[$this->foreignKey] = $this->parent->{$this->localKey}; - $result = $this->save($data); - break; - case self::BELONGS_TO_MANY: - // TODO - $result = $this->attach($data, !empty($pivot) ? $pivot[$key] : []); - break; - } - } - return $result; - } - - /** - * 附加关联的一个中间表数据 - * @access public - * @param mixed $data 数据 可以使用数组、关联模型对象 或者 关联对象的主键 - * @param array $pivot 中间表额外数据 - * @return integer - */ - public function attach($data, $pivot = []) - { - if (is_array($data)) { - // 保存关联表数据 - $model = new $this->model; - $model->save($data); - $id = $model->getLastInsID(); - } elseif (is_numeric($data) || is_string($data)) { - // 根据关联表主键直接写入中间表 - $id = $data; - } elseif ($data instanceof Model) { - // 根据关联表主键直接写入中间表 - $relationFk = $data->getPk(); - $id = $data->$relationFk; - } - - if ($id) { - // 保存中间表数据 - $pk = $this->parent->getPk(); - $pivot[$this->localKey] = $this->parent->$pk; - $pivot[$this->foreignKey] = $id; - $query = clone $this->parent->db(); - return $query->table($this->middle)->insert($pivot); - } else { - throw new Exception('miss relation data'); - } - } - - /** - * 解除关联的一个中间表数据 - * @access public - * @param integer|array $data 数据 可以使用关联对象的主键 - * @param bool $relationDel 是否同时删除关联表数据 - * @return integer - */ - public function detach($data, $relationDel = false) - { - if (is_array($data)) { - $id = $data; - } elseif (is_numeric($data) || is_string($data)) { - // 根据关联表主键直接写入中间表 - $id = $data; - } elseif ($data instanceof Model) { - // 根据关联表主键直接写入中间表 - $relationFk = $data->getPk(); - $id = $data->$relationFk; - } - // 删除中间表数据 - $pk = $this->parent->getPk(); - $pivot[$this->localKey] = $this->parent->$pk; - if (isset($id)) { - $pivot[$this->foreignKey] = is_array($id) ? ['in', $id] : $id; - } - $query = clone $this->parent->db(); - $query->table($this->middle)->where($pivot)->delete(); - - // 删除关联表数据 - if (isset($id) && $relationDel) { - $model = $this->model; - $model::destroy($id); - } - } - public function __call($method, $args) { if ($this->query) { - switch ($this->type) { - case self::HAS_MANY: - if (isset($this->where)) { - $this->query->where($this->where); - } elseif (isset($this->parent->{$this->localKey})) { - // 关联查询带入关联条件 - $this->query->where($this->foreignKey, $this->parent->{$this->localKey}); - } - break; - case self::HAS_MANY_THROUGH: - $through = $this->middle; - $model = $this->model; - $alias = Loader::parseName(basename(str_replace('\\', '/', $model))); - $throughTable = $through::getTable(); - $pk = (new $this->model)->getPk(); - $throughKey = $this->throughKey; - $modelTable = $this->parent->getTable(); - $this->query->field($alias . '.*')->alias($alias) - ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey) - ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey) - ->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey}); - break; - case self::BELONGS_TO_MANY: - // TODO + // 执行基础查询 + $this->baseQuery(); - } $result = call_user_func_array([$this->query, $method], $args); - if ($result instanceof \think\db\Query) { + if ($result instanceof Query) { $this->option = $result->getOptions(); return $this; } else { - $this->option = []; + $this->option = []; + $this->baseQuery = false; return $result; } } else { throw new Exception('method not exists:' . __CLASS__ . '->' . $method); } } - } diff --git a/thinkphp/library/think/response/Redirect.php b/thinkphp/library/think/response/Redirect.php index 0d65e5e..a3104c2 100644 --- a/thinkphp/library/think/response/Redirect.php +++ b/thinkphp/library/think/response/Redirect.php @@ -78,14 +78,17 @@ public function params($params = []) /** * 记住当前url后跳转 + * @return $this */ public function remember() { Session::set('redirect_url', Request::instance()->url()); + return $this; } /** * 跳转到上次记住的url + * @return $this */ public function restore() { @@ -93,5 +96,6 @@ public function restore() $this->data = Session::get('redirect_url'); Session::delete('redirect_url'); } + return $this; } } diff --git a/thinkphp/library/think/session/driver/Memcache.php b/thinkphp/library/think/session/driver/Memcache.php index 2c04027..7832086 100644 --- a/thinkphp/library/think/session/driver/Memcache.php +++ b/thinkphp/library/think/session/driver/Memcache.php @@ -79,7 +79,7 @@ public function close() */ public function read($sessID) { - return $this->handler->get($this->config['session_name'] . $sessID); + return (string) $this->handler->get($this->config['session_name'] . $sessID); } /** @@ -87,6 +87,7 @@ public function read($sessID) * @access public * @param string $sessID * @param String $sessData + * @return bool */ public function write($sessID, $sessData) { @@ -97,6 +98,7 @@ public function write($sessID, $sessData) * 删除Session * @access public * @param string $sessID + * @return bool */ public function destroy($sessID) { @@ -107,6 +109,7 @@ public function destroy($sessID) * Session 垃圾回收 * @access public * @param string $sessMaxLifeTime + * @return true */ public function gc($sessMaxLifeTime) { diff --git a/thinkphp/library/think/session/driver/Memcached.php b/thinkphp/library/think/session/driver/Memcached.php index 4187204..c5df23d 100644 --- a/thinkphp/library/think/session/driver/Memcached.php +++ b/thinkphp/library/think/session/driver/Memcached.php @@ -87,7 +87,7 @@ public function close() */ public function read($sessID) { - return $this->handler->get($this->config['session_name'] . $sessID); + return (string) $this->handler->get($this->config['session_name'] . $sessID); } /** @@ -95,6 +95,7 @@ public function read($sessID) * @access public * @param string $sessID * @param String $sessData + * @return bool */ public function write($sessID, $sessData) { @@ -105,6 +106,7 @@ public function write($sessID, $sessData) * 删除Session * @access public * @param string $sessID + * @return bool */ public function destroy($sessID) { @@ -115,6 +117,7 @@ public function destroy($sessID) * Session 垃圾回收 * @access public * @param string $sessMaxLifeTime + * @return true */ public function gc($sessMaxLifeTime) { diff --git a/thinkphp/library/think/session/driver/Redis.php b/thinkphp/library/think/session/driver/Redis.php index e3dc998..b1632f9 100644 --- a/thinkphp/library/think/session/driver/Redis.php +++ b/thinkphp/library/think/session/driver/Redis.php @@ -81,11 +81,11 @@ public function close() * 读取Session * @access public * @param string $sessID - * @return bool|string + * @return string */ public function read($sessID) { - return $this->handler->get($this->config['session_name'] . $sessID); + return (string) $this->handler->get($this->config['session_name'] . $sessID); } /** @@ -108,11 +108,11 @@ public function write($sessID, $sessData) * 删除Session * @access public * @param string $sessID - * @return bool|void + * @return bool */ public function destroy($sessID) { - $this->handler->delete($this->config['session_name'] . $sessID); + return $this->handler->delete($this->config['session_name'] . $sessID) > 0; } /** diff --git a/thinkphp/library/think/view/driver/Php.php b/thinkphp/library/think/view/driver/Php.php index 31fe780..b7028c2 100644 --- a/thinkphp/library/think/view/driver/Php.php +++ b/thinkphp/library/think/view/driver/Php.php @@ -21,6 +21,8 @@ class Php { // 模板引擎参数 protected $config = [ + // 视图基础目录(集中式) + 'view_base' => '', // 模板起始路径 'view_path' => '', // 模板文件后缀 @@ -109,25 +111,34 @@ private function parseTemplate($template) $this->config['view_path'] = App::$modulePath . 'view' . DS; } + $request = Request::instance(); + // 获取视图根目录 if (strpos($template, '@')) { + // 跨模块调用 list($module, $template) = explode('@', $template); - $path = APP_PATH . $module . DS . 'view' . DS; + } + if ($this->config['view_base']) { + // 基础视图目录 + $module = isset($module) ? $module : $request->module(); + $path = $this->config['view_base'] . ($module ? $module . DS : ''); } else { - $path = $this->config['view_path']; + $path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path']; } - // 分析模板文件规则 - $request = Request::instance(); - $controller = Loader::parseName($request->controller()); - if ($controller && 0 !== strpos($template, '/')) { - $depr = $this->config['view_depr']; - $template = str_replace(['/', ':'], $depr, $template); - if ('' == $template) { - // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); - } elseif (false === strpos($template, $depr)) { - $template = str_replace('.', DS, $controller) . $depr . $template; + $depr = $this->config['view_depr']; + if (0 !== strpos($template, '/')) { + $template = str_replace(['/', ':'], $depr, $template); + $controller = Loader::parseName($request->controller()); + if ($controller) { + if ('' == $template) { + // 如果模板文件名为空 按照默认规则定位 + $template = str_replace('.', DS, $controller) . $depr . $request->action(); + } elseif (false === strpos($template, $depr)) { + $template = str_replace('.', DS, $controller) . $depr . $template; + } } + } else { + $template = str_replace(['/', ':'], $depr, substr($template, 1)); } return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); } diff --git a/thinkphp/library/think/view/driver/Think.php b/thinkphp/library/think/view/driver/Think.php index db1d981..e5336b4 100644 --- a/thinkphp/library/think/view/driver/Think.php +++ b/thinkphp/library/think/view/driver/Think.php @@ -120,16 +120,20 @@ private function parseTemplate($template) $path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path']; } - $controller = Loader::parseName($request->controller()); - if ($controller && 0 !== strpos($template, '/')) { - $depr = $this->config['view_depr']; - $template = str_replace(['/', ':'], $depr, $template); - if ('' == $template) { - // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); - } elseif (false === strpos($template, $depr)) { - $template = str_replace('.', DS, $controller) . $depr . $template; + $depr = $this->config['view_depr']; + if (0 !== strpos($template, '/')) { + $template = str_replace(['/', ':'], $depr, $template); + $controller = Loader::parseName($request->controller()); + if ($controller) { + if ('' == $template) { + // 如果模板文件名为空 按照默认规则定位 + $template = str_replace('.', DS, $controller) . $depr . $request->action(); + } elseif (false === strpos($template, $depr)) { + $template = str_replace('.', DS, $controller) . $depr . $template; + } } + } else { + $template = str_replace(['/', ':'], $depr, substr($template, 1)); } return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); } diff --git a/thinkphp/library/traits/controller/Jump.php b/thinkphp/library/traits/controller/Jump.php index 0fad996..51f4281 100644 --- a/thinkphp/library/traits/controller/Jump.php +++ b/thinkphp/library/traits/controller/Jump.php @@ -81,7 +81,7 @@ protected function error($msg = '', $url = null, $data = '', $wait = 3, array $h $msg = ''; } if (is_null($url)) { - $url = 'javascript:history.back(-1);'; + $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);'; } elseif ('' !== $url) { $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url); } diff --git a/thinkphp/library/traits/model/SoftDelete.php b/thinkphp/library/traits/model/SoftDelete.php index 9d855c7..1a69c2c 100644 --- a/thinkphp/library/traits/model/SoftDelete.php +++ b/thinkphp/library/traits/model/SoftDelete.php @@ -2,6 +2,8 @@ namespace traits\model; +use think\db\Query; + trait SoftDelete { @@ -22,7 +24,7 @@ public function trashed() /** * 查询软删除数据 * @access public - * @return \think\db\Query + * @return Query */ public static function withTrashed() { @@ -34,7 +36,7 @@ public static function withTrashed() /** * 只查询软删除数据 * @access public - * @return \think\db\Query + * @return Query */ public static function onlyTrashed() { @@ -77,8 +79,8 @@ public function delete($force = false) */ public static function destroy($data, $force = false) { - $model = new static(); - $query = $model->db(); + // 包含软删除数据 + $query = self::withTrashed(); if (is_array($data) && key($data) !== 0) { $query->where($data); $data = null; @@ -109,15 +111,19 @@ public static function destroy($data, $force = false) public function restore($where = []) { $name = $this->getDeleteTimeField(); + if (empty($where)) { + $pk = $this->getPk(); + $where[$pk] = $this->getData($pk); + $where[$name] = ['not null', '']; + } // 恢复删除 - return $this->isUpdate()->save([$name => null], $where); - + return $this->db(false)->removeWhereField($this->getDeleteTimeField(true))->where($where)->update([$name => null]); } /** * 查询默认不包含软删除数据 * @access protected - * @param \think\db\Query $query 查询对象 + * @param Query $query 查询对象 * @return void */ protected function base($query) diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 305927e..7740efd 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -23,7 +23,7 @@ public static function getLoader() self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit42f1a2b06c32df0543aaa7dd0a10f07a', 'loadClassLoader')); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index cc91889..45193d8 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,47 +1,4 @@ [ - { - "name": "topthink/think-installer", - "version": "v1.0.10", - "version_normalized": "1.0.10.0", - "source": { - "type": "git", - "url": "https://github.com/top-think/think-installer.git", - "reference": "ae50760ebd7c687c7a8573db2cfa94a41e5100e3" - }, - "dist": { - "type": "zip", - "url": "https://packagist.phpcomposer.com/files/top-think/think-installer/ae50760ebd7c687c7a8573db2cfa94a41e5100e3.zip", - "reference": "ae50760ebd7c687c7a8573db2cfa94a41e5100e3", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0" - }, - "require-dev": { - "composer/composer": "1.0.*@dev" - }, - "time": "2016-09-23 04:04:44", - "type": "composer-plugin", - "extra": { - "class": "think\\composer\\Plugin" - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "think\\composer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "yunwuxin", - "email": "448901948@qq.com" - } - ] - }, { "name": "topthink/think-captcha", "version": "v1.0.7", @@ -139,19 +96,117 @@ "xlsx" ] }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.4", + "version_normalized": "5.4.4.0", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "545ce9136690cea74f98f86fbb9c92dd9ab1a756" + }, + "dist": { + "type": "zip", + "url": "https://packagist.phpcomposer.com/files/swiftmailer/swiftmailer/545ce9136690cea74f98f86fbb9c92dd9ab1a756.zip", + "reference": "545ce9136690cea74f98f86fbb9c92dd9ab1a756", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "time": "2016-11-24 01:01:23", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ] + }, + { + "name": "topthink/think-installer", + "version": "v1.0.11", + "version_normalized": "1.0.11.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-installer.git", + "reference": "4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d" + }, + "dist": { + "type": "zip", + "url": "https://packagist.phpcomposer.com/files/top-think/think-installer/4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d.zip", + "reference": "4c6e1ebecd1afce3f4ccc47e147d61bbe1bf641d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0" + }, + "require-dev": { + "composer/composer": "1.0.*@dev" + }, + "time": "2016-12-01 09:08:45", + "type": "composer-plugin", + "extra": { + "class": "think\\composer\\Plugin" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ] + }, { "name": "topthink/framework", - "version": "v5.0.3", - "version_normalized": "5.0.3.0", + "version": "v5.0.4", + "version_normalized": "5.0.4.0", "source": { "type": "git", "url": "https://github.com/top-think/framework.git", - "reference": "fd30f090e40dc25a758d99029fa07f669f575580" + "reference": "c695397733a707d4434fa8f8c070c9caf1f1f369" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/top-think/framework/fd30f090e40dc25a758d99029fa07f669f575580.zip", - "reference": "fd30f090e40dc25a758d99029fa07f669f575580", + "url": "https://packagist.phpcomposer.com/files/top-think/framework/c695397733a707d4434fa8f8c070c9caf1f1f369.zip", + "reference": "c695397733a707d4434fa8f8c070c9caf1f1f369", "shasum": "" }, "require": { @@ -167,7 +222,7 @@ "sebastian/phpcpd": "2.*", "squizlabs/php_codesniffer": "2.*" }, - "time": "2016-11-11 09:22:23", + "time": "2016-12-20 00:28:50", "type": "think-framework", "installation-source": "dist", "autoload": { @@ -195,17 +250,17 @@ }, { "name": "qiniu/php-sdk", - "version": "v7.1.1", - "version_normalized": "7.1.1.0", + "version": "v7.1.3", + "version_normalized": "7.1.3.0", "source": { "type": "git", "url": "https://github.com/qiniu/php-sdk.git", - "reference": "e9cdc254c95188c8d13e0f04fab9648d790c42f9" + "reference": "b91653485e36b4797d7a302cc86c49695e47a642" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/qiniu/php-sdk/e9cdc254c95188c8d13e0f04fab9648d790c42f9.zip", - "reference": "e9cdc254c95188c8d13e0f04fab9648d790c42f9", + "url": "https://packagist.phpcomposer.com/files/qiniu/php-sdk/b91653485e36b4797d7a302cc86c49695e47a642.zip", + "reference": "b91653485e36b4797d7a302cc86c49695e47a642", "shasum": "" }, "require": { @@ -215,7 +270,7 @@ "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~2.3" }, - "time": "2016-11-02 03:10:06", + "time": "2016-11-18 02:57:31", "type": "library", "installation-source": "dist", "autoload": { @@ -246,81 +301,26 @@ "storage" ] }, - { - "name": "swiftmailer/swiftmailer", - "version": "v5.4.4", - "version_normalized": "5.4.4.0", - "source": { - "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "545ce9136690cea74f98f86fbb9c92dd9ab1a756" - }, - "dist": { - "type": "zip", - "url": "https://packagist.phpcomposer.com/files/swiftmailer/swiftmailer/545ce9136690cea74f98f86fbb9c92dd9ab1a756.zip", - "reference": "545ce9136690cea74f98f86fbb9c92dd9ab1a756", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "mockery/mockery": "~0.9.1" - }, - "time": "2016-11-24 01:01:23", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.4-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "lib/swift_required.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Chris Corbyn" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "http://swiftmailer.org", - "keywords": [ - "email", - "mail", - "mailer" - ] - }, { "name": "yuan1994/tp-mailer", - "version": "v0.2.3", - "version_normalized": "0.2.3.0", + "version": "v0.2.4", + "version_normalized": "0.2.4.0", "source": { "type": "git", "url": "https://github.com/yuan1994/tp-mailer.git", - "reference": "41c526cf1bc9a07249b1a420f97404b0bae69195" + "reference": "7fe9b64d69be67a325a2708368b99edf44d17981" }, "dist": { "type": "zip", - "url": "https://packagist.phpcomposer.com/files/yuan1994/tp-mailer/41c526cf1bc9a07249b1a420f97404b0bae69195.zip", - "reference": "41c526cf1bc9a07249b1a420f97404b0bae69195", + "url": "https://packagist.phpcomposer.com/files/yuan1994/tp-mailer/7fe9b64d69be67a325a2708368b99edf44d17981.zip", + "reference": "7fe9b64d69be67a325a2708368b99edf44d17981", "shasum": "" }, "require": { "php": ">=5.4.0", "swiftmailer/swiftmailer": "^5.4" }, - "time": "2016-12-10 03:19:02", + "time": "2016-12-10 11:54:45", "type": "library", "installation-source": "dist", "autoload": { diff --git a/vendor/qiniu/php-sdk/CHANGELOG.md b/vendor/qiniu/php-sdk/CHANGELOG.md index c72d2b1..f6a9ad0 100644 --- a/vendor/qiniu/php-sdk/CHANGELOG.md +++ b/vendor/qiniu/php-sdk/CHANGELOG.md @@ -1,5 +1,13 @@ #Changelog +## 7.1.3 (2016-11-18) +### 增加 +* move, copy操作增加force参数 + +## 7.1.2 (2016-11-12) +### 修正 +* 明确抛出获取各区域域名失败时的报错 + ## 7.1.1 (2016-11-02) ### 修正 * 多区域配置文件存储目录从home修改到tmp目录 diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Config.php b/vendor/qiniu/php-sdk/src/Qiniu/Config.php index 0f6693d..564bf29 100644 --- a/vendor/qiniu/php-sdk/src/Qiniu/Config.php +++ b/vendor/qiniu/php-sdk/src/Qiniu/Config.php @@ -5,7 +5,7 @@ final class Config { - const SDK_VER = '7.1.1'; + const SDK_VER = '7.1.3'; const BLOCK_SIZE = 4194304; //4*1024*1024 分块上传块大小,该参数为接口规格,不能修改 diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php index 2fa09ed..0afb781 100644 --- a/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php @@ -135,11 +135,14 @@ public function rename($bucket, $oldname, $newname) * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error * @link http://developer.qiniu.com/docs/v6/api/reference/rs/copy.html */ - public function copy($from_bucket, $from_key, $to_bucket, $to_key) + public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false) { $from = \Qiniu\entry($from_bucket, $from_key); $to = \Qiniu\entry($to_bucket, $to_key); $path = '/copy/' . $from . '/' . $to; + if ($force) { + $path .= '/force/true'; + } list(, $error) = $this->rsPost($path); return $error; } @@ -155,11 +158,14 @@ public function copy($from_bucket, $from_key, $to_bucket, $to_key) * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error * @link http://developer.qiniu.com/docs/v6/api/reference/rs/move.html */ - public function move($from_bucket, $from_key, $to_bucket, $to_key) + public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false) { $from = \Qiniu\entry($from_bucket, $from_key); $to = \Qiniu\entry($to_bucket, $to_key); $path = '/move/' . $from . '/' . $to; + if ($force) { + $path .= '/force/true'; + } list(, $error) = $this->rsPost($path); return $error; } diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php index e3a314c..2e1cae8 100644 --- a/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php @@ -49,7 +49,11 @@ public static function put( } } - $upHost = $config->zone->getUpHostByToken($upToken); + list($upHost, $err) = $config->zone->getUpHostByToken($upToken); + if ($err != null) { + return array(null, $err); + } + $response = Client::multipartPost($upHost, $fields, 'file', $fname, $data, $mime); if (!$response->ok()) { return array(null, new Error($upHost, $response)); @@ -99,7 +103,11 @@ public static function putFile( $fields['key'] = $key; $headers =array('Content-Type' => 'multipart/form-data'); - $upHost = $config->zone->getUpHostByToken($upToken); + list($upHost, $err) = $config->zone->getUpHostByToken($upToken); + if ($err != null) { + return array(null, $err); + } + $response = client::post($upHost, $fields, $headers); if (!$response->ok()) { return array(null, new Error($upHost, $response)); diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php index 34160d0..382f21c 100644 --- a/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php @@ -54,7 +54,12 @@ public function __construct( $this->mime = $mime; $this->contexts = array(); $this->config = $config; - $this->host = $config->zone->getUpHostByToken($upToken); + + list($upHost, $err) = $config->zone->getUpHostByToken($upToken); + if ($err != null) { + throw new \Exception($err, 1); + } + $this->host = $upHost; } /** @@ -76,7 +81,11 @@ public function upload() $ret = $response->json(); } if ($response->statusCode < 0) { - $this->host = $this->config->zone->getBackupUpHostByToken($this->upToken); + list($bakHost, $err) = $this->config->zone->getBackupUpHostByToken($this->upToken); + if ($err != null) { + return array(null, $err); + } + $this->host = $bakHost; } if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) { $response = $this->makeBlock($data, $blockSize); diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Zone.php b/vendor/qiniu/php-sdk/src/Qiniu/Zone.php index c9829c9..3f58430 100644 --- a/vendor/qiniu/php-sdk/src/Qiniu/Zone.php +++ b/vendor/qiniu/php-sdk/src/Qiniu/Zone.php @@ -28,17 +28,17 @@ public function __construct($scheme = null) public function getUpHostByToken($uptoken) { list($ak, $bucket) = $this->unmarshalUpToken($uptoken); - list($upHosts,) = $this->getUpHosts($ak, $bucket); - return $upHosts[0]; + list($upHosts, $err) = $this->getUpHosts($ak, $bucket); + return array($upHosts[0], $err); } public function getBackupUpHostByToken($uptoken) { list($ak, $bucket) = $this->unmarshalUpToken($uptoken); - list($upHosts,) = $this->getUpHosts($ak, $bucket); + list($upHosts, $err) = $this->getUpHosts($ak, $bucket); $upHost = isset($upHosts[1]) ? $upHosts[1] : $upHosts[0]; - return $upHost; + return array($upHost, $err); } public function getIoHost($ak, $bucket) diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php index 7c8653d..288e1bf 100644 --- a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php @@ -9,12 +9,15 @@ class BucketTest extends \PHPUnit_Framework_TestCase protected $dummyBucketManager; protected $bucketName; protected $key; + protected $key2; protected function setUp() { global $bucketName; global $key; + global $key2; $this->bucketName = $bucketName; $this->key = $key; + $this->key2 = $key2; global $testAuth; $this->bucketManager = new BucketManager($testAuth); @@ -83,6 +86,8 @@ public function testRename() public function testCopy() { $key = 'copyto' . rand(); + $this->bucketManager->delete($this->bucketName, $key); + $error = $this->bucketManager->copy( $this->bucketName, $this->key, @@ -90,6 +95,23 @@ public function testCopy() $key ); $this->assertNull($error); + + //test force copy + $error = $this->bucketManager->copy( + $this->bucketName, + $this->key2, + $this->bucketName, + $key, + true + ); + $this->assertNull($error); + + list($key2Stat,) = $this->bucketManager->stat($this->bucketName, $this->key2); + list($key2CopiedStat,) = $this->bucketManager->stat($this->bucketName, $key); + + var_dump($key2Stat); + $this->assertEquals($key2Stat['hash'], $key2CopiedStat['hash']); + $error = $this->bucketManager->delete($this->bucketName, $key); $this->assertNull($error); } diff --git a/vendor/qiniu/php-sdk/tests/bootstrap.php b/vendor/qiniu/php-sdk/tests/bootstrap.php index bed9e87..329f994 100644 --- a/vendor/qiniu/php-sdk/tests/bootstrap.php +++ b/vendor/qiniu/php-sdk/tests/bootstrap.php @@ -9,7 +9,9 @@ $testAuth = new Auth($accessKey, $secretKey); $bucketName = 'phpsdk'; $key = 'php-logo.png'; +$key2 = 'niu.jpg'; $bucketNameBC = 'phpsdk-bc'; +$bucketNameNA = 'phpsdk-na'; $dummyAccessKey = 'abcdefghklmnopq'; $dummySecretKey = '1234567890'; diff --git a/vendor/topthink/think-installer/src/ThinkExtend.php b/vendor/topthink/think-installer/src/ThinkExtend.php index c9ff318..d78f118 100644 --- a/vendor/topthink/think-installer/src/ThinkExtend.php +++ b/vendor/topthink/think-installer/src/ThinkExtend.php @@ -33,30 +33,39 @@ public function update(InstalledRepositoryInterface $repo, PackageInterface $ini protected function copyExtraFiles(PackageInterface $package) { - $extra = $package->getExtra(); + if ($this->composer->getPackage()->getType() == 'project') { - if (!empty($extra['think-config'])) { + $extra = $package->getExtra(); - $composerExtra = $this->composer->getPackage()->getExtra(); - $extraDir = (!empty($composerExtra['app-path']) ? $composerExtra['app-path'] : 'application') . DIRECTORY_SEPARATOR . 'extra'; - $this->filesystem->ensureDirectoryExists($extraDir); + if (!empty($extra['think-config'])) { - //配置文件 - foreach ((array) $extra['think-config'] as $name => $config) { - $target = $extraDir . DIRECTORY_SEPARATOR . $name . '.php'; - $source = $this->getInstallPath($package) . DIRECTORY_SEPARATOR . $config; + $composerExtra = $this->composer->getPackage()->getExtra(); - if (is_file($target)) { - $this->io->write("File {$target} exist!"); - continue; - } + $appDir = !empty($composerExtra['app-path']) ? $composerExtra['app-path'] : 'application'; - if (!is_file($source)) { - $this->io->write("File {$target} not exist!"); - continue; - } + if (is_dir($appDir)) { + + $extraDir = $appDir . DIRECTORY_SEPARATOR . 'extra'; + $this->filesystem->ensureDirectoryExists($extraDir); + + //配置文件 + foreach ((array) $extra['think-config'] as $name => $config) { + $target = $extraDir . DIRECTORY_SEPARATOR . $name . '.php'; + $source = $this->getInstallPath($package) . DIRECTORY_SEPARATOR . $config; - copy($source, $target); + if (is_file($target)) { + $this->io->write("File {$target} exist!"); + continue; + } + + if (!is_file($source)) { + $this->io->write("File {$target} not exist!"); + continue; + } + + copy($source, $target); + } + } } } }