更新tp5内核

This commit is contained in:
2018-01-02 23:03:31 +08:00
parent 590696a06b
commit 3818619504
99 changed files with 3362 additions and 2006 deletions
+4 -2
View File
@@ -2,14 +2,14 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com> // | Author: liu21st <liu21st@gmail.com>
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
define('THINK_VERSION', '5.0.10'); define('THINK_VERSION', '5.0.14');
define('THINK_START_TIME', microtime(true)); define('THINK_START_TIME', microtime(true));
define('THINK_START_MEM', memory_get_usage()); define('THINK_START_MEM', memory_get_usage());
define('EXT', '.php'); define('EXT', '.php');
@@ -40,8 +40,10 @@ require CORE_PATH . 'Loader.php';
// 加载环境变量配置文件 // 加载环境变量配置文件
if (is_file(ROOT_PATH . '.env')) { if (is_file(ROOT_PATH . '.env')) {
$env = parse_ini_file(ROOT_PATH . '.env', true); $env = parse_ini_file(ROOT_PATH . '.env', true);
foreach ($env as $key => $val) { foreach ($env as $key => $val) {
$name = ENV_PREFIX . strtoupper($key); $name = ENV_PREFIX . strtoupper($key);
if (is_array($val)) { if (is_array($val)) {
foreach ($val as $k => $v) { foreach ($val as $k => $v) {
$item = $name . '_' . strtoupper($k); $item = $name . '_' . strtoupper($k);
+2
View File
@@ -155,6 +155,8 @@ return [
'show_error_msg' => false, 'show_error_msg' => false,
// 异常处理handle类 留空使用 \think\exception\Handle // 异常处理handle类 留空使用 \think\exception\Handle
'exception_handle' => '', 'exception_handle' => '',
// 是否记录trace信息到日志
'record_trace' => false,
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | 日志设置 // | 日志设置
+2 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -127,7 +127,7 @@ if (!function_exists('input')) {
if ($pos = strpos($key, '.')) { if ($pos = strpos($key, '.')) {
// 指定参数来源 // 指定参数来源
list($method, $key) = explode('.', $key, 2); list($method, $key) = explode('.', $key, 2);
if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
$key = $method . '.' . $key; $key = $method . '.' . $key;
$method = 'param'; $method = 'param';
} }
+118 -52
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -12,57 +12,123 @@
// 核心中文语言包 // 核心中文语言包
return [ return [
// 系统错误提示 // 系统错误提示
'Undefined variable' => '未定义变量', 'Undefined variable' => '未定义变量',
'Undefined index' => '未定义数组索引', 'Undefined index' => '未定义数组索引',
'Undefined offset' => '未定义数组下标', 'Undefined offset' => '未定义数组下标',
'Parse error' => '语法解析错误', 'Parse error' => '语法解析错误',
'Type error' => '类型错误', 'Type error' => '类型错误',
'Fatal error' => '致命错误', 'Fatal error' => '致命错误',
'syntax error' => '语法错误', 'syntax error' => '语法错误',
// 框架核心错误提示 // 框架核心错误提示
'dispatch type not support' => '不支持的调度类型', 'dispatch type not support' => '不支持的调度类型',
'method param miss' => '方法参数错误', 'method param miss' => '方法参数错误',
'method not exists' => '方法不存在', 'method not exists' => '方法不存在',
'module not exists' => '模块不存在', 'module not exists' => '模块不存在',
'controller not exists' => '控制器不存在', 'controller not exists' => '控制器不存在',
'class not exists' => '类不存在', 'class not exists' => '类不存在',
'property not exists' => '类的属性不存在', 'property not exists' => '类的属性不存在',
'template not exists' => '模板文件不存在', 'template not exists' => '模板文件不存在',
'illegal controller name' => '非法的控制器名称', 'illegal controller name' => '非法的控制器名称',
'illegal action name' => '非法的操作名称', 'illegal action name' => '非法的操作名称',
'url suffix deny' => '禁止的URL后缀访问', 'url suffix deny' => '禁止的URL后缀访问',
'Route Not Found' => '当前访问路由未定义', 'Route Not Found' => '当前访问路由未定义',
'Undefined db type' => '未定义数据库类型', 'Undefined db type' => '未定义数据库类型',
'variable type error' => '变量类型错误', 'variable type error' => '变量类型错误',
'PSR-4 error' => 'PSR-4 规范错误', 'PSR-4 error' => 'PSR-4 规范错误',
'not support total' => '简洁模式下不能获取数据总数', 'not support total' => '简洁模式下不能获取数据总数',
'not support last' => '简洁模式下不能获取最后一页', 'not support last' => '简洁模式下不能获取最后一页',
'error session handler' => '错误的SESSION处理器类', 'error session handler' => '错误的SESSION处理器类',
'not allow php tag' => '模板不允许使用PHP语法', 'not allow php tag' => '模板不允许使用PHP语法',
'not support' => '不支持', 'not support' => '不支持',
'redisd master' => 'Redisd 主服务器错误', 'redisd master' => 'Redisd 主服务器错误',
'redisd slave' => 'Redisd 从服务器错误', 'redisd slave' => 'Redisd 从服务器错误',
'must run at sae' => '必须在SAE运行', 'must run at sae' => '必须在SAE运行',
'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
'fields not exists' => '数据表字段不存在', 'fields not exists' => '数据表字段不存在',
'where express error' => '查询表达式错误', 'where express error' => '查询表达式错误',
'no data to update' => '没有任何数据需要更新', 'no data to update' => '没有任何数据需要更新',
'miss data to insert' => '缺少需要写入的数据', 'miss data to insert' => '缺少需要写入的数据',
'miss complex primary data' => '缺少复合主键数据', 'miss complex primary data' => '缺少复合主键数据',
'miss update condition' => '缺少更新条件', 'miss update condition' => '缺少更新条件',
'model data Not Found' => '模型数据不存在', 'model data Not Found' => '模型数据不存在',
'table data not Found' => '表数据不存在', 'table data not Found' => '表数据不存在',
'delete without condition' => '没有条件不会执行删除操作', 'delete without condition' => '没有条件不会执行删除操作',
'miss relation data' => '缺少关联表数据', 'miss relation data' => '缺少关联表数据',
'tag attr must' => '模板标签属性必须', 'tag attr must' => '模板标签属性必须',
'tag error' => '模板标签错误', 'tag error' => '模板标签错误',
'cache write error' => '缓存写入失败', 'cache write error' => '缓存写入失败',
'sae mc write error' => 'SAE mc 写入错误', 'sae mc write error' => 'SAE mc 写入错误',
'route name not exists' => '路由标识不存在(或参数不够)', 'route name not exists' => '路由标识不存在(或参数不够)',
'invalid request' => '非法请求', 'invalid request' => '非法请求',
'bind attr has exists' => '模型的属性已经存在', 'bind attr has exists' => '模型的属性已经存在',
'relation data not exists' => '关联数据不存在', 'relation data not exists' => '关联数据不存在',
'relation not support' => '关联不支持', 'relation not support' => '关联不支持',
'chunk not support order' => 'Chunk不支持调用order方法',
// 上传错误信息
'unknown upload error' => '未知上传错误!',
'file write error' => '文件写入失败!',
'upload temp dir not found' => '找不到临时文件夹!',
'no file to uploaded' => '没有文件被上传!',
'only the portion of file is uploaded' => '文件只有部分被上传!',
'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!',
'upload write error' => '文件上传保存错误!',
'has the same filename: {:filename}' => '存在同名文件:{:filename}',
'upload illegal files' => '非法上传文件',
'illegal image files' => '非法图片文件',
'extensions to upload is not allowed' => '上传文件后缀不允许',
'mimetype to upload is not allowed' => '上传文件MIME类型不允许!',
'filesize not match' => '上传文件大小不符!',
'directory {:path} creation failed' => '目录 {:path} 创建失败!',
// Validate Error Message
':attribute require' => ':attribute不能为空',
':attribute must be numeric' => ':attribute必须是数字',
':attribute must be integer' => ':attribute必须是整数',
':attribute must be float' => ':attribute必须是浮点数',
':attribute must be bool' => ':attribute必须是布尔值',
':attribute not a valid email address' => ':attribute格式不符',
':attribute not a valid mobile' => ':attribute格式不符',
':attribute must be a array' => ':attribute必须是数组',
':attribute must be yes,on or 1' => ':attribute必须是yes、on或者1',
':attribute not a valid datetime' => ':attribute不是一个有效的日期或时间格式',
':attribute not a valid file' => ':attribute不是有效的上传文件',
':attribute not a valid image' => ':attribute不是有效的图像文件',
':attribute must be alpha' => ':attribute只能是字母',
':attribute must be alpha-numeric' => ':attribute只能是字母和数字',
':attribute must be alpha-numeric, dash, underscore' => ':attribute只能是字母、数字和下划线_及破折号-',
':attribute not a valid domain or ip' => ':attribute不是有效的域名或者IP',
':attribute must be chinese' => ':attribute只能是汉字',
':attribute must be chinese or alpha' => ':attribute只能是汉字、字母',
':attribute must be chinese,alpha-numeric' => ':attribute只能是汉字、字母和数字',
':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
':attribute not a valid url' => ':attribute不是有效的URL地址',
':attribute not a valid ip' => ':attribute不是有效的IP地址',
':attribute must be dateFormat of :rule' => ':attribute必须使用日期格式 :rule',
':attribute must be in :rule' => ':attribute必须在 :rule 范围内',
':attribute be notin :rule' => ':attribute不能在 :rule 范围内',
':attribute must between :1 - :2' => ':attribute只能在 :1 - :2 之间',
':attribute not between :1 - :2' => ':attribute不能在 :1 - :2 之间',
'size of :attribute must be :rule' => ':attribute长度不符合要求 :rule',
'max size of :attribute must be :rule' => ':attribute长度不能超过 :rule',
'min size of :attribute must be :rule' => ':attribute长度不能小于 :rule',
':attribute cannot be less than :rule' => ':attribute日期不能小于 :rule',
':attribute cannot exceed :rule' => ':attribute日期不能超过 :rule',
':attribute not within :rule' => '不在有效期内 :rule',
'access IP is not allowed' => '不允许的IP访问',
'access IP denied' => '禁止的IP访问',
':attribute out of accord with :2' => ':attribute和确认字段:2不一致',
':attribute cannot be same with :2' => ':attribute和比较字段:2不能相同',
':attribute must greater than or equal :rule' => ':attribute必须大于等于 :rule',
':attribute must greater than :rule' => ':attribute必须大于 :rule',
':attribute must less than or equal :rule' => ':attribute必须小于等于 :rule',
':attribute must less than :rule' => ':attribute必须小于 :rule',
':attribute must equal :rule' => ':attribute必须等于 :rule',
':attribute has exists' => ':attribute已存在',
':attribute not conform to the rules' => ':attribute不符合指定规则',
'invalid Request method' => '无效的请求类型',
'invalid token' => '令牌数据无效',
'not conform to the rules' => '规则错误',
]; ];
+252 -179
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,13 +11,14 @@
namespace think; namespace think;
use think\exception\ClassNotFoundException;
use think\exception\HttpException; use think\exception\HttpException;
use think\exception\HttpResponseException; use think\exception\HttpResponseException;
use think\exception\RouteNotFoundException; use think\exception\RouteNotFoundException;
/** /**
* App 应用管理 * App 应用管理
* @author liu21st <liu21st@gmail.com> * @author liu21st <liu21st@gmail.com>
*/ */
class App class App
{ {
@@ -56,24 +57,32 @@ class App
*/ */
protected static $routeMust; protected static $routeMust;
/**
* @var array 请求调度分发
*/
protected static $dispatch; protected static $dispatch;
/**
* @var array 额外加载文件
*/
protected static $file = []; protected static $file = [];
/** /**
* 执行应用程序 * 执行应用程序
* @access public * @access public
* @param Request $request Request对象 * @param Request $request 请求对象
* @return Response * @return Response
* @throws Exception * @throws Exception
*/ */
public static function run(Request $request = null) public static function run(Request $request = null)
{ {
is_null($request) && $request = Request::instance(); $request = is_null($request) ? Request::instance() : $request;
try { try {
$config = self::initCommon(); $config = self::initCommon();
// 模块/控制器绑定
if (defined('BIND_MODULE')) { if (defined('BIND_MODULE')) {
// 模块/控制器绑定
BIND_MODULE && Route::bind(BIND_MODULE); BIND_MODULE && Route::bind(BIND_MODULE);
} elseif ($config['auto_bind_module']) { } elseif ($config['auto_bind_module']) {
// 入口自动绑定 // 入口自动绑定
@@ -87,10 +96,8 @@ class App
// 默认语言 // 默认语言
Lang::range($config['default_lang']); Lang::range($config['default_lang']);
if ($config['lang_switch_on']) { // 开启多语言机制 检测当前语言
// 开启多语言机制 检测当前语言 $config['lang_switch_on'] && Lang::detect();
Lang::detect();
}
$request->langset(Lang::range()); $request->langset(Lang::range());
// 加载系统语言包 // 加载系统语言包
@@ -99,12 +106,16 @@ class App
APP_PATH . 'lang' . DS . $request->langset() . EXT, APP_PATH . 'lang' . DS . $request->langset() . EXT,
]); ]);
// 监听 app_dispatch
Hook::listen('app_dispatch', self::$dispatch);
// 获取应用调度信息 // 获取应用调度信息
$dispatch = self::$dispatch; $dispatch = self::$dispatch;
// 未设置调度信息则进行 URL 路由检测
if (empty($dispatch)) { if (empty($dispatch)) {
// 进行URL路由检测
$dispatch = self::routeCheck($request, $config); $dispatch = self::routeCheck($request, $config);
} }
// 记录当前调度信息 // 记录当前调度信息
$request->dispatch($dispatch); $request->dispatch($dispatch);
@@ -115,10 +126,15 @@ class App
Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info'); Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
} }
// 监听app_begin // 监听 app_begin
Hook::listen('app_begin', $dispatch); Hook::listen('app_begin', $dispatch);
// 请求缓存检查 // 请求缓存检查
$request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); $request->cache(
$config['request_cache'],
$config['request_cache_expire'],
$config['request_cache_except']
);
$data = self::exec($dispatch, $config); $data = self::exec($dispatch, $config);
} catch (HttpResponseException $exception) { } catch (HttpResponseException $exception) {
@@ -133,24 +149,151 @@ class App
$response = $data; $response = $data;
} elseif (!is_null($data)) { } elseif (!is_null($data)) {
// 默认自动识别响应输出类型 // 默认自动识别响应输出类型
$isAjax = $request->isAjax(); $type = $request->isAjax() ?
$type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); Config::get('default_ajax_return') :
Config::get('default_return_type');
$response = Response::create($data, $type); $response = Response::create($data, $type);
} else { } else {
$response = Response::create(); $response = Response::create();
} }
// 监听app_end // 监听 app_end
Hook::listen('app_end', $response); Hook::listen('app_end', $response);
return $response; return $response;
} }
/**
* 初始化应用,并返回配置信息
* @access public
* @return array
*/
public static function initCommon()
{
if (empty(self::$init)) {
if (defined('APP_NAMESPACE')) {
self::$namespace = APP_NAMESPACE;
}
Loader::addNamespace(self::$namespace, APP_PATH);
// 初始化应用
$config = self::init();
self::$suffix = $config['class_suffix'];
// 应用调试模式
self::$debug = Env::get('app_debug', Config::get('app_debug'));
if (!self::$debug) {
ini_set('display_errors', 'Off');
} elseif (!IS_CLI) {
// 重新申请一块比较大的 buffer
if (ob_get_level() > 0) {
$output = ob_get_clean();
}
ob_start();
if (!empty($output)) {
echo $output;
}
}
if (!empty($config['root_namespace'])) {
Loader::addNamespace($config['root_namespace']);
}
// 加载额外文件
if (!empty($config['extra_file_list'])) {
foreach ($config['extra_file_list'] as $file) {
$file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
if (is_file($file) && !isset(self::$file[$file])) {
include $file;
self::$file[$file] = true;
}
}
}
// 设置系统时区
date_default_timezone_set($config['default_timezone']);
// 监听 app_init
Hook::listen('app_init');
self::$init = true;
}
return Config::get();
}
/**
* 初始化应用或模块
* @access public
* @param string $module 模块名
* @return array
*/
private static function init($module = '')
{
// 定位模块目录
$module = $module ? $module . DS : '';
// 加载初始化文件
if (is_file(APP_PATH . $module . 'init' . EXT)) {
include APP_PATH . $module . 'init' . EXT;
} elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
include RUNTIME_PATH . $module . 'init' . EXT;
} else {
// 加载模块配置
$config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
// 读取数据库配置文件
$filename = CONF_PATH . $module . 'database' . CONF_EXT;
Config::load($filename, 'database');
// 读取扩展配置文件
if (is_dir(CONF_PATH . $module . 'extra')) {
$dir = CONF_PATH . $module . 'extra';
$files = scandir($dir);
foreach ($files as $file) {
if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
$filename = $dir . DS . $file;
Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
}
}
}
// 加载应用状态配置
if ($config['app_status']) {
Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
}
// 加载行为扩展文件
if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
Hook::import(include CONF_PATH . $module . 'tags' . EXT);
}
// 加载公共文件
$path = APP_PATH . $module;
if (is_file($path . 'common' . EXT)) {
include $path . 'common' . EXT;
}
// 加载当前模块语言包
if ($module) {
Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
}
}
return Config::get();
}
/** /**
* 设置当前请求的调度信息 * 设置当前请求的调度信息
* @access public * @access public
* @param array|string $dispatch 调度信息 * @param array|string $dispatch 调度信息
* @param string $type 调度类型 * @param string $type 调度类型
* @return void * @return void
*/ */
public static function dispatch($dispatch, $type = 'module') public static function dispatch($dispatch, $type = 'module')
@@ -169,8 +312,10 @@ class App
{ {
$reflect = new \ReflectionFunction($function); $reflect = new \ReflectionFunction($function);
$args = self::bindParams($reflect, $vars); $args = self::bindParams($reflect, $vars);
// 记录执行信息 // 记录执行信息
self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info'); self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
return $reflect->invokeArgs($args); return $reflect->invokeArgs($args);
} }
@@ -190,28 +335,27 @@ class App
// 静态方法 // 静态方法
$reflect = new \ReflectionMethod($method); $reflect = new \ReflectionMethod($method);
} }
$args = self::bindParams($reflect, $vars); $args = self::bindParams($reflect, $vars);
self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info'); self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
return $reflect->invokeArgs(isset($class) ? $class : null, $args); return $reflect->invokeArgs(isset($class) ? $class : null, $args);
} }
/** /**
* 调用反射执行类的实例化 支持依赖注入 * 调用反射执行类的实例化 支持依赖注入
* @access public * @access public
* @param string $class 类名 * @param string $class 类名
* @param array $vars 变量 * @param array $vars 变量
* @return mixed * @return mixed
*/ */
public static function invokeClass($class, $vars = []) public static function invokeClass($class, $vars = [])
{ {
$reflect = new \ReflectionClass($class); $reflect = new \ReflectionClass($class);
$constructor = $reflect->getConstructor(); $constructor = $reflect->getConstructor();
if ($constructor) { $args = $constructor ? self::bindParams($constructor, $vars) : [];
$args = self::bindParams($constructor, $vars);
} else {
$args = [];
}
return $reflect->newInstanceArgs($args); return $reflect->newInstanceArgs($args);
} }
@@ -224,52 +368,58 @@ class App
*/ */
private static function bindParams($reflect, $vars = []) private static function bindParams($reflect, $vars = [])
{ {
// 自动获取请求变量
if (empty($vars)) { if (empty($vars)) {
// 自动获取请求变量 $vars = Config::get('url_param_type') ?
if (Config::get('url_param_type')) { Request::instance()->route() :
$vars = Request::instance()->route(); Request::instance()->param();
} else {
$vars = Request::instance()->param();
}
} }
$args = []; $args = [];
if ($reflect->getNumberOfParameters() > 0) { if ($reflect->getNumberOfParameters() > 0) {
// 判断数组类型 数字数组时按顺序绑定参数 // 判断数组类型 数字数组时按顺序绑定参数
reset($vars); reset($vars);
$type = key($vars) === 0 ? 1 : 0; $type = key($vars) === 0 ? 1 : 0;
$params = $reflect->getParameters();
foreach ($params as $param) { foreach ($reflect->getParameters() as $param) {
$args[] = self::getParamValue($param, $vars, $type); $args[] = self::getParamValue($param, $vars, $type);
} }
} }
return $args; return $args;
} }
/** /**
* 获取参数值 * 获取参数值
* @access private * @access private
* @param \ReflectionParameter $param * @param \ReflectionParameter $param 参数
* @param array $vars 变量 * @param array $vars 变量
* @param string $type * @param string $type 类别
* @return array * @return array
*/ */
private static function getParamValue($param, &$vars, $type) private static function getParamValue($param, &$vars, $type)
{ {
$name = $param->getName(); $name = $param->getName();
$class = $param->getClass(); $class = $param->getClass();
if ($class) { if ($class) {
$className = $class->getName(); $className = $class->getName();
$bind = Request::instance()->$name; $bind = Request::instance()->$name;
if ($bind instanceof $className) { if ($bind instanceof $className) {
$result = $bind; $result = $bind;
} else { } else {
if (method_exists($className, 'invoke')) { if (method_exists($className, 'invoke')) {
$method = new \ReflectionMethod($className, 'invoke'); $method = new \ReflectionMethod($className, 'invoke');
if ($method->isPublic() && $method->isStatic()) { if ($method->isPublic() && $method->isStatic()) {
return $className::invoke(Request::instance()); return $className::invoke(Request::instance());
} }
} }
$result = method_exists($className, 'instance') ? $className::instance() : new $className;
$result = method_exists($className, 'instance') ?
$className::instance() :
new $className;
} }
} elseif (1 == $type && !empty($vars)) { } elseif (1 == $type && !empty($vars)) {
$result = array_shift($vars); $result = array_shift($vars);
@@ -280,65 +430,85 @@ class App
} else { } else {
throw new \InvalidArgumentException('method param miss:' . $name); throw new \InvalidArgumentException('method param miss:' . $name);
} }
return $result; return $result;
} }
/**
* 执行调用分发
* @access protected
* @param array $dispatch 调用信息
* @param array $config 配置信息
* @return Response|mixed
* @throws \InvalidArgumentException
*/
protected static function exec($dispatch, $config) protected static function exec($dispatch, $config)
{ {
switch ($dispatch['type']) { switch ($dispatch['type']) {
case 'redirect': case 'redirect': // 重定向跳转
// 执行重定向跳转 $data = Response::create($dispatch['url'], 'redirect')
$data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']); ->code($dispatch['status']);
break; break;
case 'module': case 'module': // 模块/控制器/操作
// 模块/控制器/操作 $data = self::module(
$data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null); $dispatch['module'],
$config,
isset($dispatch['convert']) ? $dispatch['convert'] : null
);
break; break;
case 'controller': case 'controller': // 执行控制器操作
// 执行控制器操作
$vars = array_merge(Request::instance()->param(), $dispatch['var']); $vars = array_merge(Request::instance()->param(), $dispatch['var']);
$data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']); $data = Loader::action(
$dispatch['controller'],
$vars,
$config['url_controller_layer'],
$config['controller_suffix']
);
break; break;
case 'method': case 'method': // 回调方法
// 执行回调方法
$vars = array_merge(Request::instance()->param(), $dispatch['var']); $vars = array_merge(Request::instance()->param(), $dispatch['var']);
$data = self::invokeMethod($dispatch['method'], $vars); $data = self::invokeMethod($dispatch['method'], $vars);
break; break;
case 'function': case 'function': // 闭包
// 执行闭包
$data = self::invokeFunction($dispatch['function']); $data = self::invokeFunction($dispatch['function']);
break; break;
case 'response': case 'response': // Response 实例
$data = $dispatch['response']; $data = $dispatch['response'];
break; break;
default: default:
throw new \InvalidArgumentException('dispatch type not support'); throw new \InvalidArgumentException('dispatch type not support');
} }
return $data; return $data;
} }
/** /**
* 执行模块 * 执行模块
* @access public * @access public
* @param array $result 模块/控制器/操作 * @param array $result 模块/控制器/操作
* @param array $config 配置参数 * @param array $config 配置参数
* @param bool $convert 是否自动转换控制器和操作名 * @param bool $convert 是否自动转换控制器和操作名
* @return mixed * @return mixed
* @throws HttpException
*/ */
public static function module($result, $config, $convert = null) public static function module($result, $config, $convert = null)
{ {
if (is_string($result)) { if (is_string($result)) {
$result = explode('/', $result); $result = explode('/', $result);
} }
$request = Request::instance(); $request = Request::instance();
if ($config['app_multi_module']) { if ($config['app_multi_module']) {
// 多模块部署 // 多模块部署
$module = strip_tags(strtolower($result[0] ?: $config['default_module'])); $module = strip_tags(strtolower($result[0] ?: $config['default_module']));
$bind = Route::getBind('module'); $bind = Route::getBind('module');
$available = false; $available = false;
if ($bind) { if ($bind) {
// 绑定模块 // 绑定模块
list($bindModule) = explode('/', $bind); list($bindModule) = explode('/', $bind);
if (empty($result[0])) { if (empty($result[0])) {
$module = $bindModule; $module = $bindModule;
$available = true; $available = true;
@@ -354,8 +524,13 @@ class App
// 初始化模块 // 初始化模块
$request->module($module); $request->module($module);
$config = self::init($module); $config = self::init($module);
// 模块请求缓存检查 // 模块请求缓存检查
$request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); $request->cache(
$config['request_cache'],
$config['request_cache_expire'],
$config['request_cache_except']
);
} else { } else {
throw new HttpException(404, 'module not exists:' . $module); throw new HttpException(404, 'module not exists:' . $module);
} }
@@ -364,11 +539,16 @@ class App
$module = ''; $module = '';
$request->module($module); $request->module($module);
} }
// 设置默认过滤机制
$request->filter($config['default_filter']);
// 当前模块路径 // 当前模块路径
App::$modulePath = APP_PATH . ($module ? $module . DS : ''); App::$modulePath = APP_PATH . ($module ? $module . DS : '');
// 是否自动转换控制器和操作名 // 是否自动转换控制器和操作名
$convert = is_bool($convert) ? $convert : $config['url_convert']; $convert = is_bool($convert) ? $convert : $config['url_convert'];
// 获取控制器名 // 获取控制器名
$controller = strip_tags($result[1] ?: $config['default_controller']); $controller = strip_tags($result[1] ?: $config['default_controller']);
$controller = $convert ? strtolower($controller) : $controller; $controller = $convert ? strtolower($controller) : $controller;
@@ -383,10 +563,17 @@ class App
// 监听module_init // 监听module_init
Hook::listen('module_init', $request); Hook::listen('module_init', $request);
$instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']); try {
if (is_null($instance)) { $instance = Loader::controller(
throw new HttpException(404, 'controller not exists:' . Loader::parseName($controller, 1)); $controller,
$config['url_controller_layer'],
$config['controller_suffix'],
$config['empty_controller']
);
} catch (ClassNotFoundException $e) {
throw new HttpException(404, 'controller not exists:' . $e->getClass());
} }
// 获取当前操作名 // 获取当前操作名
$action = $actionName . $config['action_suffix']; $action = $actionName . $config['action_suffix'];
@@ -408,125 +595,11 @@ class App
return self::invokeMethod($call, $vars); return self::invokeMethod($call, $vars);
} }
/**
* 初始化应用
*/
public static function initCommon()
{
if (empty(self::$init)) {
if (defined('APP_NAMESPACE')) {
self::$namespace = APP_NAMESPACE;
}
Loader::addNamespace(self::$namespace, APP_PATH);
// 初始化应用
$config = self::init();
self::$suffix = $config['class_suffix'];
// 应用调试模式
self::$debug = Env::get('app_debug', Config::get('app_debug'));
if (!self::$debug) {
ini_set('display_errors', 'Off');
} elseif (!IS_CLI) {
//重新申请一块比较大的buffer
if (ob_get_level() > 0) {
$output = ob_get_clean();
}
ob_start();
if (!empty($output)) {
echo $output;
}
}
if (!empty($config['root_namespace'])) {
Loader::addNamespace($config['root_namespace']);
}
// 加载额外文件
if (!empty($config['extra_file_list'])) {
foreach ($config['extra_file_list'] as $file) {
$file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
if (is_file($file) && !isset(self::$file[$file])) {
include $file;
self::$file[$file] = true;
}
}
}
// 设置系统时区
date_default_timezone_set($config['default_timezone']);
// 监听app_init
Hook::listen('app_init');
self::$init = true;
}
return Config::get();
}
/**
* 初始化应用或模块
* @access public
* @param string $module 模块名
* @return array
*/
private static function init($module = '')
{
// 定位模块目录
$module = $module ? $module . DS : '';
// 加载初始化文件
if (is_file(APP_PATH . $module . 'init' . EXT)) {
include APP_PATH . $module . 'init' . EXT;
} elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
include RUNTIME_PATH . $module . 'init' . EXT;
} else {
$path = APP_PATH . $module;
// 加载模块配置
$config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
// 读取数据库配置文件
$filename = CONF_PATH . $module . 'database' . CONF_EXT;
Config::load($filename, 'database');
// 读取扩展配置文件
if (is_dir(CONF_PATH . $module . 'extra')) {
$dir = CONF_PATH . $module . 'extra';
$files = scandir($dir);
foreach ($files as $file) {
if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
$filename = $dir . DS . $file;
Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
}
}
}
// 加载应用状态配置
if ($config['app_status']) {
$config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
}
// 加载行为扩展文件
if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
Hook::import(include CONF_PATH . $module . 'tags' . EXT);
}
// 加载公共文件
if (is_file($path . 'common' . EXT)) {
include $path . 'common' . EXT;
}
// 加载当前模块语言包
if ($module) {
Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
}
}
return Config::get();
}
/** /**
* URL路由检测(根据PATH_INFO) * URL路由检测(根据PATH_INFO)
* @access public * @access public
* @param \think\Request $request * @param \think\Request $request 请求实例
* @param array $config * @param array $config 配置信息
* @return array * @return array
* @throws \think\Exception * @throws \think\Exception
*/ */
@@ -535,6 +608,7 @@ class App
$path = $request->path(); $path = $request->path();
$depr = $config['pathinfo_depr']; $depr = $config['pathinfo_depr'];
$result = false; $result = false;
// 路由检测 // 路由检测
$check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
if ($check) { if ($check) {
@@ -542,18 +616,14 @@ class App
if (is_file(RUNTIME_PATH . 'route.php')) { if (is_file(RUNTIME_PATH . 'route.php')) {
// 读取路由缓存 // 读取路由缓存
$rules = include RUNTIME_PATH . 'route.php'; $rules = include RUNTIME_PATH . 'route.php';
if (is_array($rules)) { is_array($rules) && Route::rules($rules);
Route::rules($rules);
}
} else { } else {
$files = $config['route_config_file']; $files = $config['route_config_file'];
foreach ($files as $file) { foreach ($files as $file) {
if (is_file(CONF_PATH . $file . CONF_EXT)) { if (is_file(CONF_PATH . $file . CONF_EXT)) {
// 导入路由配置 // 导入路由配置
$rules = include CONF_PATH . $file . CONF_EXT; $rules = include CONF_PATH . $file . CONF_EXT;
if (is_array($rules)) { is_array($rules) && Route::import($rules);
Route::import($rules);
}
} }
} }
} }
@@ -561,15 +631,18 @@ class App
// 路由检测(根据路由定义返回不同的URL调度) // 路由检测(根据路由定义返回不同的URL调度)
$result = Route::check($request, $path, $depr, $config['url_domain_deploy']); $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
$must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
if ($must && false === $result) { if ($must && false === $result) {
// 路由无效 // 路由无效
throw new RouteNotFoundException(); throw new RouteNotFoundException();
} }
} }
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
if (false === $result) { if (false === $result) {
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
$result = Route::parseUrl($path, $depr, $config['controller_auto_search']); $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
} }
return $result; return $result;
} }
+90 -60
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -14,36 +14,44 @@ namespace think;
class Build class Build
{ {
/** /**
* 根据传入的build资料创建目录和文件 * 根据传入的 build 资料创建目录和文件
* @access protected * @access public
* @param array $build build列表 * @param array $build build 列表
* @param string $namespace 应用类库命名空间 * @param string $namespace 应用类库命名空间
* @param bool $suffix 类库后缀 * @param bool $suffix 类库后缀
* @return void * @return void
* @throws Exception
*/ */
public static function run(array $build = [], $namespace = 'app', $suffix = false) public static function run(array $build = [], $namespace = 'app', $suffix = false)
{ {
// 锁定 // 锁定
$lockfile = APP_PATH . 'build.lock'; $lock = APP_PATH . 'build.lock';
if (is_writable($lockfile)) {
return; // 如果锁定文件不可写(不存在)则进行处理,否则表示已经有程序在处理了
} elseif (!touch($lockfile)) { if (!is_writable($lock)) {
throw new Exception('应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~', 10006); if (!touch($lock)) {
} throw new Exception(
foreach ($build as $module => $list) { '应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~',
if ('__dir__' == $module) { 10006
// 创建目录列表 );
self::buildDir($list);
} elseif ('__file__' == $module) {
// 创建文件列表
self::buildFile($list);
} else {
// 创建模块
self::module($module, $list, $namespace, $suffix);
} }
foreach ($build as $module => $list) {
if ('__dir__' == $module) {
// 创建目录列表
self::buildDir($list);
} elseif ('__file__' == $module) {
// 创建文件列表
self::buildFile($list);
} else {
// 创建模块
self::module($module, $list, $namespace, $suffix);
}
}
// 解除锁定
unlink($lock);
} }
// 解除锁定
unlink($lockfile);
} }
/** /**
@@ -55,10 +63,8 @@ class Build
protected static function buildDir($list) protected static function buildDir($list)
{ {
foreach ($list as $dir) { foreach ($list as $dir) {
if (!is_dir(APP_PATH . $dir)) { // 目录不存在则创建目录
// 创建目录 !is_dir(APP_PATH . $dir) && mkdir(APP_PATH . $dir, 0755, true);
mkdir(APP_PATH . $dir, 0755, true);
}
} }
} }
@@ -71,12 +77,17 @@ class Build
protected static function buildFile($list) protected static function buildFile($list)
{ {
foreach ($list as $file) { foreach ($list as $file) {
// 先创建目录
if (!is_dir(APP_PATH . dirname($file))) { if (!is_dir(APP_PATH . dirname($file))) {
// 创建目录
mkdir(APP_PATH . dirname($file), 0755, true); mkdir(APP_PATH . dirname($file), 0755, true);
} }
// 再创建文件
if (!is_file(APP_PATH . $file)) { if (!is_file(APP_PATH . $file)) {
file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : ''); file_put_contents(
APP_PATH . $file,
'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : ''
);
} }
} }
} }
@@ -84,35 +95,37 @@ class Build
/** /**
* 创建模块 * 创建模块
* @access public * @access public
* @param string $module 模块名 * @param string $module 模块名
* @param array $list build列表 * @param array $list build 列表
* @param string $namespace 应用类库命名空间 * @param string $namespace 应用类库命名空间
* @param bool $suffix 类库后缀 * @param bool $suffix 类库后缀
* @return void * @return void
*/ */
public static function module($module = '', $list = [], $namespace = 'app', $suffix = false) public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)
{ {
$module = $module ? $module : ''; $module = $module ?: '';
if (!is_dir(APP_PATH . $module)) {
// 创建模块目录 // 创建模块目录
mkdir(APP_PATH . $module); !is_dir(APP_PATH . $module) && mkdir(APP_PATH . $module);
}
// 如果不是 runtime 目录则需要创建配置文件和公共文件、创建模块的默认页面
if (basename(RUNTIME_PATH) != $module) { if (basename(RUNTIME_PATH) != $module) {
// 创建配置文件和公共文件
self::buildCommon($module); self::buildCommon($module);
// 创建模块的默认页面
self::buildHello($module, $namespace, $suffix); self::buildHello($module, $namespace, $suffix);
} }
// 未指定文件和目录,则创建默认的模块目录和文件
if (empty($list)) { if (empty($list)) {
// 创建默认的模块目录和文件
$list = [ $list = [
'__file__' => ['config.php', 'common.php'], '__file__' => ['config.php', 'common.php'],
'__dir__' => ['controller', 'model', 'view'], '__dir__' => ['controller', 'model', 'view'],
]; ];
} }
// 创建子目录和文件 // 创建子目录和文件
foreach ($list as $path => $file) { foreach ($list as $path => $file) {
$modulePath = APP_PATH . $module . DS; $modulePath = APP_PATH . $module . DS;
if ('__dir__' == $path) { if ('__dir__' == $path) {
// 生成子目录 // 生成子目录
foreach ($file as $dir) { foreach ($file as $dir) {
@@ -122,16 +135,20 @@ class Build
// 生成(空白)文件 // 生成(空白)文件
foreach ($file as $name) { foreach ($file as $name) {
if (!is_file($modulePath . $name)) { if (!is_file($modulePath . $name)) {
file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : ''); file_put_contents(
$modulePath . $name,
'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : ''
);
} }
} }
} else { } else {
// 生成相关MVC文件 // 生成相关 MVC 文件
foreach ($file as $val) { foreach ($file as $val) {
$val = trim($val); $val = trim($val);
$filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT; $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;
$space = $namespace . '\\' . ($module ? $module . '\\' : '') . $path; $space = $namespace . '\\' . ($module ? $module . '\\' : '') . $path;
$class = $val . ($suffix ? ucfirst($path) : ''); $class = $val . ($suffix ? ucfirst($path) : '');
switch ($path) { switch ($path) {
case 'controller': // 控制器 case 'controller': // 控制器
$content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}"; $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
@@ -159,18 +176,27 @@ class Build
/** /**
* 创建模块的欢迎页面 * 创建模块的欢迎页面
* @access public * @access protected
* @param string $module 模块名 * @param string $module 模块名
* @param string $namespace 应用类库命名空间 * @param string $namespace 应用类库命名空间
* @param bool $suffix 类库后缀 * @param bool $suffix 类库后缀
* @return void * @return void
*/ */
protected static function buildHello($module, $namespace, $suffix = false) protected static function buildHello($module, $namespace, $suffix = false)
{ {
$filename = APP_PATH . ($module ? $module . DS : '') . 'controller' . DS . 'Index' . ($suffix ? 'Controller' : '') . EXT; $filename = APP_PATH . ($module ? $module . DS : '') .
'controller' . DS . 'Index' .
($suffix ? 'Controller' : '') . EXT;
if (!is_file($filename)) { if (!is_file($filename)) {
$content = file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl'); $module = $module ? $module . '\\' : '';
$content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\' : '', 'controller', $suffix ? 'Controller' : ''], $content); $suffix = $suffix ? 'Controller' : '';
$content = str_replace(
['{$app}', '{$module}', '{layer}', '{$suffix}'],
[$namespace, $module, 'controller', $suffix],
file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl')
);
self::checkDirBuild(dirname($filename)); self::checkDirBuild(dirname($filename));
file_put_contents($filename, $content); file_put_contents($filename, $content);
} }
@@ -178,28 +204,32 @@ class Build
/** /**
* 创建模块的公共文件 * 创建模块的公共文件
* @access public * @access protected
* @param string $module 模块名 * @param string $module 模块名
* @return void * @return void
*/ */
protected static function buildCommon($module) protected static function buildCommon($module)
{ {
$filename = CONF_PATH . ($module ? $module . DS : '') . 'config.php'; $config = CONF_PATH . ($module ? $module . DS : '') . 'config.php';
self::checkDirBuild(dirname($filename)); self::checkDirBuild(dirname($config));
if (!is_file($filename)) {
file_put_contents($filename, "<?php\n//配置文件\nreturn [\n\n];"); if (!is_file($config)) {
} file_put_contents($config, "<?php\n//配置文件\nreturn [\n\n];");
$filename = APP_PATH . ($module ? $module . DS : '') . 'common.php';
if (!is_file($filename)) {
file_put_contents($filename, "<?php\n");
} }
$common = APP_PATH . ($module ? $module . DS : '') . 'common.php';
if (!is_file($common)) file_put_contents($common, "<?php\n");
} }
/**
* 创建目录
* @access protected
* @param string $dirname 目录名称
* @return void
*/
protected static function checkDirBuild($dirname) protected static function checkDirBuild($dirname)
{ {
if (!is_dir($dirname)) { !is_dir($dirname) && mkdir($dirname, 0755, true);
mkdir($dirname, 0755, true);
}
} }
} }
+69 -44
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -15,71 +15,86 @@ use think\cache\Driver;
class Cache class Cache
{ {
protected static $instance = [];
public static $readTimes = 0;
public static $writeTimes = 0;
/** /**
* 操作句柄 * @var array 缓存的实例
* @var object
* @access protected
*/ */
protected static $handler; public static $instance = [];
/** /**
* 连接缓存 * @var int 缓存读取次数
*/
public static $readTimes = 0;
/**
* @var int 缓存写入次数
*/
public static $writeTimes = 0;
/**
* @var object 操作句柄
*/
public static $handler;
/**
* 连接缓存驱动
* @access public * @access public
* @param array $options 配置数组 * @param array $options 配置数组
* @param bool|string $name 缓存连接标识 true 强制重新连接 * @param bool|string $name 缓存连接标识 true 强制重新连接
* @return Driver * @return Driver
*/ */
public static function connect(array $options = [], $name = false) public static function connect(array $options = [], $name = false)
{ {
$type = !empty($options['type']) ? $options['type'] : 'File'; $type = !empty($options['type']) ? $options['type'] : 'File';
if (false === $name) { if (false === $name) {
$name = md5(serialize($options)); $name = md5(serialize($options));
} }
if (true === $name || !isset(self::$instance[$name])) { if (true === $name || !isset(self::$instance[$name])) {
$class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type); $class = false === strpos($type, '\\') ?
'\\think\\cache\\driver\\' . ucwords($type) :
$type;
// 记录初始化信息 // 记录初始化信息
App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info'); App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
if (true === $name) { if (true === $name) {
return new $class($options); return new $class($options);
} else {
self::$instance[$name] = new $class($options);
} }
self::$instance[$name] = new $class($options);
} }
return self::$instance[$name]; return self::$instance[$name];
} }
/** /**
* 自动初始化缓存 * 自动初始化缓存
* @access public * @access public
* @param array $options 配置数组 * @param array $options 配置数组
* @return Driver * @return Driver
*/ */
public static function init(array $options = []) public static function init(array $options = [])
{ {
if (is_null(self::$handler)) { if (is_null(self::$handler)) {
// 自动初始化缓存 if (empty($options) && 'complex' == Config::get('cache.type')) {
if (!empty($options)) { $default = Config::get('cache.default');
$connect = self::connect($options); // 获取默认缓存配置,并连接
} elseif ('complex' == Config::get('cache.type')) { $options = Config::get('cache.' . $default['type']) ?: $default;
$connect = self::connect(Config::get('cache.default')); } elseif (empty($options)) {
} else { $options = Config::get('cache');
$connect = self::connect(Config::get('cache'));
} }
self::$handler = $connect;
self::$handler = self::connect($options);
} }
return self::$handler; return self::$handler;
} }
/** /**
* 切换缓存类型 需要配置 cache.type 为 complex * 切换缓存类型 需要配置 cache.type 为 complex
* @access public * @access public
* @param string $name 缓存标识 * @param string $name 缓存标识
* @return Driver * @return Driver
*/ */
public static function store($name = '') public static function store($name = '')
@@ -87,131 +102,141 @@ class Cache
if ('' !== $name && 'complex' == Config::get('cache.type')) { if ('' !== $name && 'complex' == Config::get('cache.type')) {
return self::connect(Config::get('cache.' . $name), strtolower($name)); return self::connect(Config::get('cache.' . $name), strtolower($name));
} }
return self::init(); return self::init();
} }
/** /**
* 判断缓存是否存在 * 判断缓存是否存在
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @return bool * @return bool
*/ */
public static function has($name) public static function has($name)
{ {
self::$readTimes++; self::$readTimes++;
return self::init()->has($name); return self::init()->has($name);
} }
/** /**
* 读取缓存 * 读取缓存
* @access public * @access public
* @param string $name 缓存标识 * @param string $name 缓存标识
* @param mixed $default 默认值 * @param mixed $default 默认值
* @return mixed * @return mixed
*/ */
public static function get($name, $default = false) public static function get($name, $default = false)
{ {
self::$readTimes++; self::$readTimes++;
return self::init()->get($name, $default); return self::init()->get($name, $default);
} }
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存标识 * @param string $name 缓存标识
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param int|null $expire 有效时间 0为永久 * @param int|null $expire 有效时间 0为永久
* @return boolean * @return boolean
*/ */
public static function set($name, $value, $expire = null) public static function set($name, $value, $expire = null)
{ {
self::$writeTimes++; self::$writeTimes++;
return self::init()->set($name, $value, $expire); return self::init()->set($name, $value, $expire);
} }
/** /**
* 自增缓存(针对数值缓存) * 自增缓存(针对数值缓存)
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param int $step 步长 * @param int $step 步长
* @return false|int * @return false|int
*/ */
public static function inc($name, $step = 1) public static function inc($name, $step = 1)
{ {
self::$writeTimes++; self::$writeTimes++;
return self::init()->inc($name, $step); return self::init()->inc($name, $step);
} }
/** /**
* 自减缓存(针对数值缓存) * 自减缓存(针对数值缓存)
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param int $step 步长 * @param int $step 步长
* @return false|int * @return false|int
*/ */
public static function dec($name, $step = 1) public static function dec($name, $step = 1)
{ {
self::$writeTimes++; self::$writeTimes++;
return self::init()->dec($name, $step); return self::init()->dec($name, $step);
} }
/** /**
* 删除缓存 * 删除缓存
* @access public * @access public
* @param string $name 缓存标识 * @param string $name 缓存标识
* @return boolean * @return boolean
*/ */
public static function rm($name) public static function rm($name)
{ {
self::$writeTimes++; self::$writeTimes++;
return self::init()->rm($name); return self::init()->rm($name);
} }
/** /**
* 清除缓存 * 清除缓存
* @access public * @access public
* @param string $tag 标签名 * @param string $tag 标签名
* @return boolean * @return boolean
*/ */
public static function clear($tag = null) public static function clear($tag = null)
{ {
self::$writeTimes++; self::$writeTimes++;
return self::init()->clear($tag); return self::init()->clear($tag);
} }
/** /**
* 读取缓存并删除 * 读取缓存并删除
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @return mixed * @return mixed
*/ */
public static function pull($name) public static function pull($name)
{ {
self::$readTimes++; self::$readTimes++;
self::$writeTimes++; self::$writeTimes++;
return self::init()->pull($name); return self::init()->pull($name);
} }
/** /**
* 如果不存在则写入缓存 * 如果不存在则写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久 * @param int $expire 有效时间 0为永久
* @return mixed * @return mixed
*/ */
public static function remember($name, $value, $expire = null) public static function remember($name, $value, $expire = null)
{ {
self::$readTimes++; self::$readTimes++;
return self::init()->remember($name, $value, $expire); return self::init()->remember($name, $value, $expire);
} }
/** /**
* 缓存标签 * 缓存标签
* @access public * @access public
* @param string $name 标签名 * @param string $name 标签名
* @param string|array $keys 缓存标识 * @param string|array $keys 缓存标识
* @param bool $overlay 是否覆盖 * @param bool $overlay 是否覆盖
* @return Driver * @return Driver
*/ */
public static function tag($name, $keys = null, $overlay = false) public static function tag($name, $keys = null, $overlay = false)
+222 -138
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -19,20 +19,35 @@ use JsonSerializable;
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
{ {
/**
* @var array 数据
*/
protected $items = []; protected $items = [];
/**
* Collection constructor.
* @access public
* @param array $items 数据
*/
public function __construct($items = []) public function __construct($items = [])
{ {
$this->items = $this->convertToArray($items); $this->items = $this->convertToArray($items);
} }
/**
* 创建 Collection 实例
* @access public
* @param array $items 数据
* @return static
*/
public static function make($items = []) public static function make($items = [])
{ {
return new static($items); return new static($items);
} }
/** /**
* 是否为空 * 判断数据是否为空
* @access public
* @return bool * @return bool
*/ */
public function isEmpty() public function isEmpty()
@@ -40,43 +55,33 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
return empty($this->items); return empty($this->items);
} }
/**
* 将数据转成数组
* @access public
* @return array
*/
public function toArray() public function toArray()
{ {
return array_map(function ($value) { return array_map(function ($value) {
return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value; return ($value instanceof Model || $value instanceof self) ?
$value->toArray() :
$value;
}, $this->items); }, $this->items);
} }
/**
* 获取全部的数据
* @access public
* @return array
*/
public function all() public function all()
{ {
return $this->items; return $this->items;
} }
/**
* 合并数组
*
* @param mixed $items
* @return static
*/
public function merge($items)
{
return new static(array_merge($this->items, $this->convertToArray($items)));
}
/**
* 比较数组,返回差集
*
* @param mixed $items
* @return static
*/
public function diff($items)
{
return new static(array_diff($this->items, $this->convertToArray($items)));
}
/** /**
* 交换数组中的键和值 * 交换数组中的键和值
* * @access public
* @return static * @return static
*/ */
public function flip() public function flip()
@@ -85,19 +90,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
/** /**
* 比较数组,返回交集 * 返回数组中所有的键名组成的新 Collection 实例
* * @access public
* @param mixed $items
* @return static
*/
public function intersect($items)
{
return new static(array_intersect($this->items, $this->convertToArray($items)));
}
/**
* 返回数组中所有的键名
*
* @return static * @return static
*/ */
public function keys() public function keys()
@@ -106,8 +100,41 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
/** /**
* 删除数组的最后一个元素(出栈) * 合并数组并返回一个新的 Collection 实例
* * @access public
* @param mixed $items 新的数据
* @return static
*/
public function merge($items)
{
return new static(array_merge($this->items, $this->convertToArray($items)));
}
/**
* 比较数组,返回差集生成的新 Collection 实例
* @access public
* @param mixed $items 做比较的数据
* @return static
*/
public function diff($items)
{
return new static(array_diff($this->items, $this->convertToArray($items)));
}
/**
* 比较数组,返回交集组成的 Collection 新实例
* @access public
* @param mixed $items 比较数据
* @return static
*/
public function intersect($items)
{
return new static(array_intersect($this->items, $this->convertToArray($items)));
}
/**
* 返回并删除数据中的的最后一个元素(出栈)
* @access public
* @return mixed * @return mixed
*/ */
public function pop() public function pop()
@@ -116,30 +143,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
/** /**
* 通过使用用户自定义函数,以字符串返回数组 * 返回并删除数据中首个元素
* * @access public
* @param callable $callback
* @param mixed $initial
* @return mixed
*/
public function reduce(callable $callback, $initial = null)
{
return array_reduce($this->items, $callback, $initial);
}
/**
* 以相反的顺序返回数组。
*
* @return static
*/
public function reverse()
{
return new static(array_reverse($this->items));
}
/**
* 删除数组中首个元素,并返回被删除元素的值
*
* @return mixed * @return mixed
*/ */
public function shift() public function shift()
@@ -148,10 +153,64 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
/** /**
* 把一个数组分割为新的数组块. * 在数组开头插入一个元素
* * @access public
* @param int $size * @param mixed $value 值
* @param bool $preserveKeys * @param mixed $key 键名
* @return void
*/
public function unshift($value, $key = null)
{
if (is_null($key)) {
array_unshift($this->items, $value);
} else {
$this->items = [$key => $value] + $this->items;
}
}
/**
* 在数组结尾插入一个元素
* @access public
* @param mixed $value 值
* @param mixed $key 键名
* @return void
*/
public function push($value, $key = null)
{
if (is_null($key)) {
$this->items[] = $value;
} else {
$this->items[$key] = $value;
}
}
/**
* 通过使用用户自定义函数,以字符串返回数组
* @access public
* @param callable $callback 回调函数
* @param mixed $initial 初始值
* @return mixed
*/
public function reduce(callable $callback, $initial = null)
{
return array_reduce($this->items, $callback, $initial);
}
/**
* 以相反的顺序创建一个新的 Collection 实例
* @access public
* @return static
*/
public function reverse()
{
return new static(array_reverse($this->items));
}
/**
* 把数据分割为新的数组块
* @access public
* @param int $size 分隔长度
* @param bool $preserveKeys 是否保持原数据索引
* @return static * @return static
*/ */
public function chunk($size, $preserveKeys = false) public function chunk($size, $preserveKeys = false)
@@ -166,78 +225,70 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
/** /**
* 在数组开头插入一个元素 * 给数据中的每个元素执行回调
* @param mixed $value * @access public
* @param null $key * @param callable $callback 回调函数
* @return int
*/
public function unshift($value, $key = null)
{
if (is_null($key)) {
array_unshift($this->items, $value);
} else {
$this->items = [$key => $value] + $this->items;
}
}
/**
* 给每个元素执行个回调
*
* @param callable $callback
* @return $this * @return $this
*/ */
public function each(callable $callback) public function each(callable $callback)
{ {
foreach ($this->items as $key => $item) { foreach ($this->items as $key => $item) {
if ($callback($item, $key) === false) { $result = $callback($item, $key);
if (false === $result) {
break; break;
} }
if (!is_object($item)) {
$this->items[$key] = $result;
}
} }
return $this; return $this;
} }
/** /**
* 用回调函数过滤数中的元素 * 用回调函数过滤数中的元素
* @param callable|null $callback * @access public
* @param callable|null $callback 回调函数
* @return static * @return static
*/ */
public function filter(callable $callback = null) public function filter(callable $callback = null)
{ {
if ($callback) { return new static(array_filter($this->items, $callback ?: null));
return new static(array_filter($this->items, $callback));
}
return new static(array_filter($this->items));
} }
/** /**
* 返回数中指定的一列 * 返回数中指定的一列
* @param $column_key * @access public
* @param null $index_key * @param mixed $columnKey 键名
* @param null $indexKey 作为索引值的列
* @return array * @return array
*/ */
public function column($column_key, $index_key = null) public function column($columnKey, $indexKey = null)
{ {
if (function_exists('array_column')) { if (function_exists('array_column')) {
return array_column($this->items, $column_key, $index_key); return array_column($this->items, $columnKey, $indexKey);
} }
$result = []; $result = [];
foreach ($this->items as $row) { foreach ($this->items as $row) {
$key = $value = null; $key = $value = null;
$keySet = $valueSet = false; $keySet = $valueSet = false;
if (null !== $index_key && array_key_exists($index_key, $row)) {
if (null !== $indexKey && array_key_exists($indexKey, $row)) {
$key = (string) $row[$indexKey];
$keySet = true; $keySet = true;
$key = (string) $row[$index_key];
} }
if (null === $column_key) {
if (null === $columnKey) {
$valueSet = true; $valueSet = true;
$value = $row; $value = $row;
} elseif (is_array($row) && array_key_exists($column_key, $row)) { } elseif (is_array($row) && array_key_exists($columnKey, $row)) {
$valueSet = true; $valueSet = true;
$value = $row[$column_key]; $value = $row[$columnKey];
} }
if ($valueSet) { if ($valueSet) {
if ($keySet) { if ($keySet) {
$result[$key] = $value; $result[$key] = $value;
@@ -246,34 +297,30 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
} }
} }
return $result; return $result;
} }
/** /**
* 对数组排序 * 对数据排序,并返回排序后的数据组成的新 Collection 实例
* * @access public
* @param callable|null $callback * @param callable|null $callback 回调函数
* @return static * @return static
*/ */
public function sort(callable $callback = null) public function sort(callable $callback = null)
{ {
$items = $this->items; $items = $this->items;
$callback = $callback ?: function ($a, $b) {
return $a == $b ? 0 : (($a < $b) ? -1 : 1);
};
$callback ? uasort($items, $callback) : uasort($items, function ($a, $b) { uasort($items, $callback);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
return new static($items); return new static($items);
} }
/** /**
* 将数打乱 * 将数打乱后组成新的 Collection 实例
* * @access public
* @return static * @return static
*/ */
public function shuffle() public function shuffle()
@@ -281,16 +328,15 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
$items = $this->items; $items = $this->items;
shuffle($items); shuffle($items);
return new static($items); return new static($items);
} }
/** /**
* 截取数 * 截取数据并返回新的 Collection 实例
* * @access public
* @param int $offset * @param int $offset 起始位置
* @param int $length * @param int $length 截取长度
* @param bool $preserveKeys * @param bool $preserveKeys 是否保持原先的键名
* @return static * @return static
*/ */
public function slice($offset, $length = null, $preserveKeys = false) public function slice($offset, $length = null, $preserveKeys = false)
@@ -298,17 +344,35 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
return new static(array_slice($this->items, $offset, $length, $preserveKeys)); return new static(array_slice($this->items, $offset, $length, $preserveKeys));
} }
// ArrayAccess /**
* 指定的键是否存在
* @access public
* @param mixed $offset 键名
* @return bool
*/
public function offsetExists($offset) public function offsetExists($offset)
{ {
return array_key_exists($offset, $this->items); return array_key_exists($offset, $this->items);
} }
/**
* 获取指定键对应的值
* @access public
* @param mixed $offset 键名
* @return mixed
*/
public function offsetGet($offset) public function offsetGet($offset)
{ {
return $this->items[$offset]; return $this->items[$offset];
} }
/**
* 设置键值
* @access public
* @param mixed $offset 键名
* @param mixed $value 值
* @return void
*/
public function offsetSet($offset, $value) public function offsetSet($offset, $value)
{ {
if (is_null($offset)) { if (is_null($offset)) {
@@ -318,33 +382,51 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
} }
} }
/**
* 删除指定键值
* @access public
* @param mixed $offset 键名
* @return void
*/
public function offsetUnset($offset) public function offsetUnset($offset)
{ {
unset($this->items[$offset]); unset($this->items[$offset]);
} }
//Countable /**
* 统计数据的个数
* @access public
* @return int
*/
public function count() public function count()
{ {
return count($this->items); return count($this->items);
} }
//IteratorAggregate /**
* 获取数据的迭代器
* @access public
* @return ArrayIterator
*/
public function getIterator() public function getIterator()
{ {
return new ArrayIterator($this->items); return new ArrayIterator($this->items);
} }
//JsonSerializable /**
* 将数据反序列化成数组
* @access public
* @return array
*/
public function jsonSerialize() public function jsonSerialize()
{ {
return $this->toArray(); return $this->toArray();
} }
/** /**
* 转换当前数据集为JSON字符串 * 转换当前数据集为 JSON 字符串
* @access public * @access public
* @param integer $options json参数 * @param integer $options json 参数
* @return string * @return string
*/ */
public function toJson($options = JSON_UNESCAPED_UNICODE) public function toJson($options = JSON_UNESCAPED_UNICODE)
@@ -352,22 +434,24 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
return json_encode($this->toArray(), $options); return json_encode($this->toArray(), $options);
} }
/**
* 将数据转换成字符串
* @access public
* @return string
*/
public function __toString() public function __toString()
{ {
return $this->toJson(); return $this->toJson();
} }
/** /**
* 转换成数组 * 将数据转换成数组
* * @access protected
* @param mixed $items * @param mixed $items 数据
* @return array * @return array
*/ */
protected function convertToArray($items) protected function convertToArray($items)
{ {
if ($items instanceof self) { return $items instanceof self ? $items->all() : (array) $items;
return $items->all();
}
return (array) $items;
} }
} }
+103 -59
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -13,70 +13,88 @@ namespace think;
class Config class Config
{ {
// 配置参数 /**
* @var array 配置参数
*/
private static $config = []; private static $config = [];
// 参数作用域
/**
* @var string 参数作用域
*/
private static $range = '_sys_'; private static $range = '_sys_';
// 设定配置参数的作用域 /**
* 设定配置参数的作用域
* @access public
* @param string $range 作用域
* @return void
*/
public static function range($range) public static function range($range)
{ {
self::$range = $range; self::$range = $range;
if (!isset(self::$config[$range])) {
self::$config[$range] = []; if (!isset(self::$config[$range])) self::$config[$range] = [];
}
} }
/** /**
* 解析配置文件或内容 * 解析配置文件或内容
* @param string $config 配置文件路径或内容 * @access public
* @param string $type 配置解析类型 * @param string $config 配置文件路径或内容
* @param string $name 配置名(如设置即表示二级配置) * @param string $type 配置解析类型
* @param string $range 作用域 * @param string $name 配置名(如设置即表示二级配置)
* @param string $range 作用域
* @return mixed * @return mixed
*/ */
public static function parse($config, $type = '', $name = '', $range = '') public static function parse($config, $type = '', $name = '', $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
if (empty($type)) {
$type = pathinfo($config, PATHINFO_EXTENSION); if (empty($type)) $type = pathinfo($config, PATHINFO_EXTENSION);
}
$class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type); $class = false !== strpos($type, '\\') ?
$type :
'\\think\\config\\driver\\' . ucwords($type);
return self::set((new $class())->parse($config), $name, $range); return self::set((new $class())->parse($config), $name, $range);
} }
/** /**
* 加载配置文件(PHP格式) * 加载配置文件(PHP格式)
* @param string $file 配置文件名 * @access public
* @param string $name 配置名(如设置即表示二级配置) * @param string $file 配置文件
* @param string $range 作用域 * @param string $name 配置名(如设置即表示二级配置)
* @param string $range 作用域
* @return mixed * @return mixed
*/ */
public static function load($file, $name = '', $range = '') public static function load($file, $name = '', $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
if (!isset(self::$config[$range])) {
self::$config[$range] = []; if (!isset(self::$config[$range])) self::$config[$range] = [];
}
if (is_file($file)) { if (is_file($file)) {
$name = strtolower($name); $name = strtolower($name);
$type = pathinfo($file, PATHINFO_EXTENSION); $type = pathinfo($file, PATHINFO_EXTENSION);
if ('php' == $type) { if ('php' == $type) {
return self::set(include $file, $name, $range); return self::set(include $file, $name, $range);
} elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
return self::set(yaml_parse_file($file), $name, $range);
} else {
return self::parse($file, $type, $name, $range);
} }
} else {
return self::$config[$range]; if ('yaml' == $type && function_exists('yaml_parse_file')) {
return self::set(yaml_parse_file($file), $name, $range);
}
return self::parse($file, $type, $name, $range);
} }
return self::$config[$range];
} }
/** /**
* 检测配置是否存在 * 检测配置是否存在
* @param string $name 配置参数名(支持二级配置 .号分割) * @access public
* @param string $range 作用域 * @param string $name 配置参数名(支持二级配置 . 号分割)
* @param string $range 作用域
* @return bool * @return bool
*/ */
public static function has($name, $range = '') public static function has($name, $range = '')
@@ -85,82 +103,108 @@ class Config
if (!strpos($name, '.')) { if (!strpos($name, '.')) {
return isset(self::$config[$range][strtolower($name)]); return isset(self::$config[$range][strtolower($name)]);
} else {
// 二维数组设置和获取支持
$name = explode('.', $name, 2);
return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
} }
// 二维数组设置和获取支持
$name = explode('.', $name, 2);
return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
} }
/** /**
* 获取配置参数 为空则获取所有配置 * 获取配置参数 为空则获取所有配置
* @param string $name 配置参数名(支持二级配置 .号分割) * @access public
* @param string $range 作用域 * @param string $name 配置参数名(支持二级配置 . 号分割)
* @param string $range 作用域
* @return mixed * @return mixed
*/ */
public static function get($name = null, $range = '') public static function get($name = null, $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
// 无参数时获取所有 // 无参数时获取所有
if (empty($name) && isset(self::$config[$range])) { if (empty($name) && isset(self::$config[$range])) {
return self::$config[$range]; return self::$config[$range];
} }
// 非二级配置时直接返回
if (!strpos($name, '.')) { if (!strpos($name, '.')) {
$name = strtolower($name); $name = strtolower($name);
return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null; return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;
} else {
// 二维数组设置和获取支持
$name = explode('.', $name, 2);
$name[0] = strtolower($name[0]);
return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null;
} }
// 二维数组设置和获取支持
$name = explode('.', $name, 2);
$name[0] = strtolower($name[0]);
if (!isset(self::$config[$range][$name[0]])) {
// 动态载入额外配置
$module = Request::instance()->module();
$file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT;
is_file($file) && self::load($file, $name[0]);
}
return isset(self::$config[$range][$name[0]][$name[1]]) ?
self::$config[$range][$name[0]][$name[1]] :
null;
} }
/** /**
* 设置配置参数 name为数组则为批量设置 * 设置配置参数 name 为数组则为批量设置
* @param string|array $name 配置参数名(支持二级配置 .号分割) * @access public
* @param mixed $value 配置值 * @param string|array $name 配置参数名(支持二级配置 . 号分割)
* @param string $range 作用域 * @param mixed $value 配置值
* @param string $range 作用域
* @return mixed * @return mixed
*/ */
public static function set($name, $value = null, $range = '') public static function set($name, $value = null, $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
if (!isset(self::$config[$range])) {
self::$config[$range] = []; if (!isset(self::$config[$range])) self::$config[$range] = [];
}
// 字符串则表示单个配置设置
if (is_string($name)) { if (is_string($name)) {
if (!strpos($name, '.')) { if (!strpos($name, '.')) {
self::$config[$range][strtolower($name)] = $value; self::$config[$range][strtolower($name)] = $value;
} else { } else {
// 二维数组设置和获取支持 // 二维数组
$name = explode('.', $name, 2); $name = explode('.', $name, 2);
self::$config[$range][strtolower($name[0])][$name[1]] = $value; self::$config[$range][strtolower($name[0])][$name[1]] = $value;
} }
return;
} elseif (is_array($name)) { return $value;
// 批量设置 }
// 数组则表示批量设置
if (is_array($name)) {
if (!empty($value)) { if (!empty($value)) {
self::$config[$range][$value] = isset(self::$config[$range][$value]) ? self::$config[$range][$value] = isset(self::$config[$range][$value]) ?
array_merge(self::$config[$range][$value], $name) : array_merge(self::$config[$range][$value], $name) :
self::$config[$range][$value] = $name; $name;
return self::$config[$range][$value]; return self::$config[$range][$value];
} else {
return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name));
} }
} else {
// 为空直接返回 已有配置 return self::$config[$range] = array_merge(
return self::$config[$range]; self::$config[$range], array_change_key_case($name)
);
} }
// 为空直接返回已有配置
return self::$config[$range];
} }
/** /**
* 重置配置参数 * 重置配置参数
* @access public
* @param string $range 作用域
* @return void
*/ */
public static function reset($range = '') public static function reset($range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
if (true === $range) { if (true === $range) {
self::$config = []; self::$config = [];
} else { } else {
+243 -118
View File
@@ -20,20 +20,49 @@ use think\console\output\driver\Buffer;
class Console class Console
{ {
/**
* @var string 命令名称
*/
private $name; private $name;
/**
* @var string 命令版本
*/
private $version; private $version;
/** @var Command[] */ /**
* @var Command[] 命令
*/
private $commands = []; private $commands = [];
/**
* @var bool 是否需要帮助信息
*/
private $wantHelps = false; private $wantHelps = false;
/**
* @var bool 是否捕获异常
*/
private $catchExceptions = true; private $catchExceptions = true;
private $autoExit = true;
/**
* @var bool 是否自动退出执行
*/
private $autoExit = true;
/**
* @var InputDefinition 输入定义
*/
private $definition; private $definition;
/**
* @var string 默认执行的命令
*/
private $defaultCommand; private $defaultCommand;
/**
* @var array 默认提供的命令
*/
private static $defaultCommands = [ private static $defaultCommands = [
"think\\console\\command\\Help", "think\\console\\command\\Help",
"think\\console\\command\\Lists", "think\\console\\command\\Lists",
@@ -47,6 +76,12 @@ class Console
"think\\console\\command\\optimize\\Schema", "think\\console\\command\\optimize\\Schema",
]; ];
/**
* Console constructor.
* @access public
* @param string $name 名称
* @param string $version 版本
*/
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
{ {
$this->name = $name; $this->name = $name;
@@ -60,38 +95,44 @@ class Console
} }
} }
/**
* 初始化 Console
* @access public
* @param bool $run 是否运行 Console
* @return int|Console
*/
public static function init($run = true) public static function init($run = true)
{ {
static $console; static $console;
if (!$console) { if (!$console) {
// 实例化console // 实例化 console
$console = new self('Think Console', '0.1'); $console = new self('Think Console', '0.1');
// 读取指令集 // 读取指令集
if (is_file(CONF_PATH . 'command' . EXT)) { if (is_file(CONF_PATH . 'command' . EXT)) {
$commands = include CONF_PATH . 'command' . EXT; $commands = include CONF_PATH . 'command' . EXT;
if (is_array($commands)) { if (is_array($commands)) {
foreach ($commands as $command) { foreach ($commands as $command) {
if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) { class_exists($command) &&
// 注册指令 is_subclass_of($command, "\\think\\console\\Command") &&
$console->add(new $command()); $console->add(new $command()); // 注册指令
}
} }
} }
} }
} }
if ($run) {
// 运行 return $run ? $console->run() : $console;
return $console->run();
} else {
return $console;
}
} }
/** /**
* @param $command * 调用命令
* @param array $parameters * @access public
* @param string $driver * @param string $command
* @return Output|Buffer * @param array $parameters
* @param string $driver
* @return Output
*/ */
public static function call($command, array $parameters = [], $driver = 'buffer') public static function call($command, array $parameters = [], $driver = 'buffer')
{ {
@@ -110,9 +151,9 @@ class Console
/** /**
* 执行当前的指令 * 执行当前的指令
* @access public
* @return int * @return int
* @throws \Exception * @throws \Exception
* @api
*/ */
public function run() public function run()
{ {
@@ -124,27 +165,21 @@ class Console
try { try {
$exitCode = $this->doRun($input, $output); $exitCode = $this->doRun($input, $output);
} catch (\Exception $e) { } catch (\Exception $e) {
if (!$this->catchExceptions) { if (!$this->catchExceptions) throw $e;
throw $e;
}
$output->renderException($e); $output->renderException($e);
$exitCode = $e->getCode(); $exitCode = $e->getCode();
if (is_numeric($exitCode)) { if (is_numeric($exitCode)) {
$exitCode = (int) $exitCode; $exitCode = ((int) $exitCode) ?: 1;
if (0 === $exitCode) {
$exitCode = 1;
}
} else { } else {
$exitCode = 1; $exitCode = 1;
} }
} }
if ($this->autoExit) { if ($this->autoExit) {
if ($exitCode > 255) { if ($exitCode > 255) $exitCode = 255;
$exitCode = 255;
}
exit($exitCode); exit($exitCode);
} }
@@ -154,12 +189,14 @@ class Console
/** /**
* 执行指令 * 执行指令
* @param Input $input * @access public
* @param Output $output * @param Input $input 输入
* @param Output $output 输出
* @return int * @return int
*/ */
public function doRun(Input $input, Output $output) public function doRun(Input $input, Output $output)
{ {
// 获取版本信息
if (true === $input->hasParameterOption(['--version', '-V'])) { if (true === $input->hasParameterOption(['--version', '-V'])) {
$output->writeln($this->getLongVersion()); $output->writeln($this->getLongVersion());
@@ -168,6 +205,7 @@ class Console
$name = $this->getCommandName($input); $name = $this->getCommandName($input);
// 获取帮助信息
if (true === $input->hasParameterOption(['--help', '-h'])) { if (true === $input->hasParameterOption(['--help', '-h'])) {
if (!$name) { if (!$name) {
$name = 'help'; $name = 'help';
@@ -182,25 +220,26 @@ class Console
$input = new Input([$this->defaultCommand]); $input = new Input([$this->defaultCommand]);
} }
$command = $this->find($name); return $this->doRunCommand($this->find($name), $input, $output);
$exitCode = $this->doRunCommand($command, $input, $output);
return $exitCode;
} }
/** /**
* 设置输入参数定义 * 设置输入参数定义
* @param InputDefinition $definition * @access public
* @param InputDefinition $definition 输入定义
* @return $this;
*/ */
public function setDefinition(InputDefinition $definition) public function setDefinition(InputDefinition $definition)
{ {
$this->definition = $definition; $this->definition = $definition;
return $this;
} }
/** /**
* 获取输入参数定义 * 获取输入参数定义
* @return InputDefinition The InputDefinition instance * @access public
* @return InputDefinition
*/ */
public function getDefinition() public function getDefinition()
{ {
@@ -208,8 +247,9 @@ class Console
} }
/** /**
* Gets the help message. * 获取帮助信息
* @return string A help message. * @access public
* @return string
*/ */
public function getHelp() public function getHelp()
{ {
@@ -217,27 +257,34 @@ class Console
} }
/** /**
* 是否捕获异常 * 设置是否捕获异常
* @param bool $boolean * @access public
* @api * @param bool $boolean 是否捕获
* @return $this
*/ */
public function setCatchExceptions($boolean) public function setCatchExceptions($boolean)
{ {
$this->catchExceptions = (bool) $boolean; $this->catchExceptions = (bool) $boolean;
return $this;
} }
/** /**
* 是否自动退出 * 设置是否自动退出
* @param bool $boolean * @access public
* @api * @param bool $boolean 是否自动退出
* @return $this
*/ */
public function setAutoExit($boolean) public function setAutoExit($boolean)
{ {
$this->autoExit = (bool) $boolean; $this->autoExit = (bool) $boolean;
return $this;
} }
/** /**
* 获取名称 * 获取名称
* @access public
* @return string * @return string
*/ */
public function getName() public function getName()
@@ -247,17 +294,21 @@ class Console
/** /**
* 设置名称 * 设置名称
* @param string $name * @access public
* @param string $name 名称
* @return $this
*/ */
public function setName($name) public function setName($name)
{ {
$this->name = $name; $this->name = $name;
return $this;
} }
/** /**
* 获取版本 * 获取版本
* @access public
* @return string * @return string
* @api
*/ */
public function getVersion() public function getVersion()
{ {
@@ -266,21 +317,30 @@ class Console
/** /**
* 设置版本 * 设置版本
* @param string $version * @access public
* @param string $version 版本信息
* @return $this
*/ */
public function setVersion($version) public function setVersion($version)
{ {
$this->version = $version; $this->version = $version;
return $this;
} }
/** /**
* 获取完整的版本号 * 获取完整的版本号
* @access public
* @return string * @return string
*/ */
public function getLongVersion() public function getLongVersion()
{ {
if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion()); return sprintf(
'<info>%s</info> version <comment>%s</comment>',
$this->getName(),
$this->getVersion()
);
} }
return '<info>Console Tool</info>'; return '<info>Console Tool</info>';
@@ -288,7 +348,8 @@ class Console
/** /**
* 注册一个指令 * 注册一个指令
* @param string $name * @access public
* @param string $name 指令名称
* @return Command * @return Command
*/ */
public function register($name) public function register($name)
@@ -297,32 +358,37 @@ class Console
} }
/** /**
* 添加指令 * 批量添加指令
* @param Command[] $commands * @access public
* @param Command[] $commands 指令实例
* @return $this
*/ */
public function addCommands(array $commands) public function addCommands(array $commands)
{ {
foreach ($commands as $command) { foreach ($commands as $command) $this->add($command);
$this->add($command);
} return $this;
} }
/** /**
* 添加一个指令 * 添加一个指令
* @param Command $command * @access public
* @return Command * @param Command $command 命令实例
* @return Command|bool
*/ */
public function add(Command $command) public function add(Command $command)
{ {
$command->setConsole($this);
if (!$command->isEnabled()) { if (!$command->isEnabled()) {
$command->setConsole(null); $command->setConsole(null);
return; return false;
} }
$command->setConsole($this);
if (null === $command->getDefinition()) { if (null === $command->getDefinition()) {
throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); throw new \LogicException(
sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))
);
} }
$this->commands[$command->getName()] = $command; $this->commands[$command->getName()] = $command;
@@ -336,14 +402,17 @@ class Console
/** /**
* 获取指令 * 获取指令
* @param string $name 指令名称 * @access public
* @param string $name 指令名称
* @return Command * @return Command
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function get($name) public function get($name)
{ {
if (!isset($this->commands[$name])) { if (!isset($this->commands[$name])) {
throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); throw new \InvalidArgumentException(
sprintf('The command "%s" does not exist.', $name)
);
} }
$command = $this->commands[$name]; $command = $this->commands[$name];
@@ -363,7 +432,8 @@ class Console
/** /**
* 某个指令是否存在 * 某个指令是否存在
* @param string $name 指令名称 * @access public
* @param string $name 指令名称
* @return bool * @return bool
*/ */
public function has($name) public function has($name)
@@ -373,16 +443,22 @@ class Console
/** /**
* 获取所有的命名空间 * 获取所有的命名空间
* @access public
* @return array * @return array
*/ */
public function getNamespaces() public function getNamespaces()
{ {
$namespaces = []; $namespaces = [];
foreach ($this->commands as $command) { foreach ($this->commands as $command) {
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); $namespaces = array_merge(
$namespaces, $this->extractAllNamespaces($command->getName())
);
foreach ($command->getAliases() as $alias) { foreach ($command->getAliases() as $alias) {
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); $namespaces = array_merge(
$namespaces, $this->extractAllNamespaces($alias)
);
} }
} }
@@ -390,21 +466,25 @@ class Console
} }
/** /**
* 查找注册命名空间中的名称或缩写 * 查找注册命名空间中的名称或缩写
* @access public
* @param string $namespace * @param string $namespace
* @return string * @return string
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function findNamespace($namespace) public function findNamespace($namespace)
{ {
$allNamespaces = $this->getNamespaces(); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
return preg_quote($matches[1]) . '[^:]*'; return preg_quote($matches[1]) . '[^:]*';
}, $namespace); }, $namespace);
$allNamespaces = $this->getNamespaces();
$namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
if (empty($namespaces)) { if (empty($namespaces)) {
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); $message = sprintf(
'There are no commands defined in the "%s" namespace.', $namespace
);
if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
if (1 == count($alternatives)) { if (1 == count($alternatives)) {
@@ -420,8 +500,14 @@ class Console
} }
$exact = in_array($namespace, $namespaces, true); $exact = in_array($namespace, $namespaces, true);
if (count($namespaces) > 1 && !$exact) { if (count($namespaces) > 1 && !$exact) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces)))); throw new \InvalidArgumentException(
sprintf(
'The namespace "%s" is ambiguous (%s).',
$namespace,
$this->getAbbreviationSuggestions(array_values($namespaces)))
);
} }
return $exact ? $namespace : reset($namespaces); return $exact ? $namespace : reset($namespaces);
@@ -429,20 +515,22 @@ class Console
/** /**
* 查找指令 * 查找指令
* @param string $name 名称或者别名 * @access public
* @param string $name 名称或者别名
* @return Command * @return Command
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function find($name) public function find($name)
{ {
$allCommands = array_keys($this->commands); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
return preg_quote($matches[1]) . '[^:]*'; return preg_quote($matches[1]) . '[^:]*';
}, $name); }, $name);
$allCommands = array_keys($this->commands);
$commands = preg_grep('{^' . $expr . '}', $allCommands); $commands = preg_grep('{^' . $expr . '}', $allCommands);
if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) { if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
if (false !== $pos = strrpos($name, ':')) { if (false !== ($pos = strrpos($name, ':'))) {
$this->findNamespace(substr($name, 0, $pos)); $this->findNamespace(substr($name, 0, $pos));
} }
@@ -462,7 +550,7 @@ class Console
if (count($commands) > 1) { if (count($commands) > 1) {
$commandList = $this->commands; $commandList = $this->commands;
$commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) { $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
$commandName = $commandList[$nameOrAlias]->getName(); $commandName = $commandList[$nameOrAlias]->getName();
return $commandName === $nameOrAlias || !in_array($commandName, $commands); return $commandName === $nameOrAlias || !in_array($commandName, $commands);
@@ -473,7 +561,9 @@ class Console
if (count($commands) > 1 && !$exact) { if (count($commands) > 1 && !$exact) {
$suggestions = $this->getAbbreviationSuggestions(array_values($commands)); $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); throw new \InvalidArgumentException(
sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)
);
} }
return $this->get($exact ? $name : reset($commands)); return $this->get($exact ? $name : reset($commands));
@@ -481,21 +571,20 @@ class Console
/** /**
* 获取所有的指令 * 获取所有的指令
* @param string $namespace 命名空间 * @access public
* @param string $namespace 命名空间
* @return Command[] * @return Command[]
* @api
*/ */
public function all($namespace = null) public function all($namespace = null)
{ {
if (null === $namespace) { if (null === $namespace) return $this->commands;
return $this->commands;
}
$commands = []; $commands = [];
foreach ($this->commands as $name => $command) { foreach ($this->commands as $name => $command) {
if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) { $ext = $this->extractNamespace($name, substr_count($namespace, ':') + 1);
$commands[$name] = $command;
} if ($ext === $namespace) $commands[$name] = $command;
} }
return $commands; return $commands;
@@ -503,7 +592,8 @@ class Console
/** /**
* 获取可能的指令名 * 获取可能的指令名
* @param array $names * @access public
* @param array $names 指令名
* @return array * @return array
*/ */
public static function getAbbreviations($names) public static function getAbbreviations($names)
@@ -511,7 +601,7 @@ class Console
$abbrevs = []; $abbrevs = [];
foreach ($names as $name) { foreach ($names as $name) {
for ($len = strlen($name); $len > 0; --$len) { for ($len = strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len); $abbrev = substr($name, 0, $len);
$abbrevs[$abbrev][] = $name; $abbrevs[$abbrev][] = $name;
} }
} }
@@ -520,9 +610,11 @@ class Console
} }
/** /**
* 配置基于用户的参数和选项的输入和输出实例 * 配置基于用户的参数和选项的输入和输出实例
* @param Input $input 输入实例 * @access protected
* @param Output $output 输出实例 * @param Input $input 输入实例
* @param Output $output 输出实例
* @return void
*/ */
protected function configureIO(Input $input, Output $output) protected function configureIO(Input $input, Output $output)
{ {
@@ -551,9 +643,10 @@ class Console
/** /**
* 执行指令 * 执行指令
* @param Command $command 指令实例 * @access protected
* @param Input $input 输入实例 * @param Command $command 指令实例
* @param Output $output 输出实例 * @param Input $input 输入实例
* @param Output $output 输出实例
* @return int * @return int
* @throws \Exception * @throws \Exception
*/ */
@@ -563,8 +656,9 @@ class Console
} }
/** /**
* 获取指令的基础名称 * 获取指令的名称
* @param Input $input * @access protected
* @param Input $input 输入实例
* @return string * @return string
*/ */
protected function getCommandName(Input $input) protected function getCommandName(Input $input)
@@ -574,6 +668,7 @@ class Console
/** /**
* 获取默认输入定义 * 获取默认输入定义
* @access protected
* @return InputDefinition * @return InputDefinition
*/ */
protected function getDefaultInputDefinition() protected function getDefaultInputDefinition()
@@ -591,41 +686,55 @@ class Console
} }
/** /**
* 设置默认命令 * 获取默认命令
* @return Command[] An array of default Command instances * @access protected
* @return Command[]
*/ */
protected function getDefaultCommands() protected function getDefaultCommands()
{ {
$defaultCommands = []; $defaultCommands = [];
foreach (self::$defaultCommands as $classname) { foreach (self::$defaultCommands as $class) {
if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) { if (class_exists($class) && is_subclass_of($class, "think\\console\\Command")) {
$defaultCommands[] = new $classname(); $defaultCommands[] = new $class();
} }
} }
return $defaultCommands; return $defaultCommands;
} }
public static function addDefaultCommands(array $classnames) /**
* 添加默认指令
* @access public
* @param array $classes 指令
* @return void
*/
public static function addDefaultCommands(array $classes)
{ {
self::$defaultCommands = array_merge(self::$defaultCommands, $classnames); self::$defaultCommands = array_merge(self::$defaultCommands, $classes);
} }
/** /**
* 获取可能的建议 * 获取可能的建议
* @param array $abbrevs * @access private
* @param array $abbrevs
* @return string * @return string
*/ */
private function getAbbreviationSuggestions($abbrevs) private function getAbbreviationSuggestions($abbrevs)
{ {
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); return sprintf(
'%s, %s%s',
$abbrevs[0],
$abbrevs[1],
count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''
);
} }
/** /**
* 返回命名空间部分 * 返回指令的命名空间部分
* @param string $name 指令 * @access public
* @param string $limit 部分的命名空间的最大数量 * @param string $name 指令名称
* @param string $limit 部分的命名空间的最大数量
* @return string * @return string
*/ */
public function extractNamespace($name, $limit = null) public function extractNamespace($name, $limit = null)
@@ -638,16 +747,17 @@ class Console
/** /**
* 查找可替代的建议 * 查找可替代的建议
* @param string $name * @access private
* @param array|\Traversable $collection * @param string $name 指令名称
* @param array|\Traversable $collection 建议集合
* @return array * @return array
*/ */
private function findAlternatives($name, $collection) private function findAlternatives($name, $collection)
{ {
$threshold = 1e3; $threshold = 1e3;
$alternatives = []; $alternatives = [];
$collectionParts = []; $collectionParts = [];
foreach ($collection as $item) { foreach ($collection as $item) {
$collectionParts[$item] = explode(':', $item); $collectionParts[$item] = explode(':', $item);
} }
@@ -655,6 +765,7 @@ class Console
foreach (explode(':', $name) as $i => $subname) { foreach (explode(':', $name) as $i => $subname) {
foreach ($collectionParts as $collectionName => $parts) { foreach ($collectionParts as $collectionName => $parts) {
$exists = isset($alternatives[$collectionName]); $exists = isset($alternatives[$collectionName]);
if (!isset($parts[$i]) && $exists) { if (!isset($parts[$i]) && $exists) {
$alternatives[$collectionName] += $threshold; $alternatives[$collectionName] += $threshold;
continue; continue;
@@ -663,8 +774,14 @@ class Console
} }
$lev = levenshtein($subname, $parts[$i]); $lev = levenshtein($subname, $parts[$i]);
if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
$alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; if ($lev <= strlen($subname) / 3 ||
'' !== $subname &&
false !== strpos($parts[$i], $subname)
) {
$alternatives[$collectionName] = $exists ?
$alternatives[$collectionName] + $lev :
$lev;
} elseif ($exists) { } elseif ($exists) {
$alternatives[$collectionName] += $threshold; $alternatives[$collectionName] += $threshold;
} }
@@ -673,14 +790,18 @@ class Console
foreach ($collection as $item) { foreach ($collection as $item) {
$lev = levenshtein($name, $item); $lev = levenshtein($name, $item);
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; $alternatives[$item] = isset($alternatives[$item]) ?
$alternatives[$item] - $lev :
$lev;
} }
} }
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
return $lev < 2 * $threshold; return $lev < 2 * $threshold;
}); });
asort($alternatives); asort($alternatives);
return array_keys($alternatives); return array_keys($alternatives);
@@ -688,24 +809,28 @@ class Console
/** /**
* 设置默认的指令 * 设置默认的指令
* @param string $commandName The Command name * @access public
* @param string $commandName 指令名称
* @return $this
*/ */
public function setDefaultCommand($commandName) public function setDefaultCommand($commandName)
{ {
$this->defaultCommand = $commandName; $this->defaultCommand = $commandName;
return $this;
} }
/** /**
* 返回所有的命名空间 * 返回所有的命名空间
* @param string $name * @access private
* @param string $name 指令名称
* @return array * @return array
*/ */
private function extractAllNamespaces($name) private function extractAllNamespaces($name)
{ {
$parts = explode(':', $name, -1);
$namespaces = []; $namespaces = [];
foreach ($parts as $part) { foreach (explode(':', $name, -1) as $part) {
if (count($namespaces)) { if (count($namespaces)) {
$namespaces[] = end($namespaces) . ':' . $part; $namespaces[] = end($namespaces) . ':' . $part;
} else { } else {
+63 -52
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,46 +11,49 @@
namespace think; namespace think;
\think\Loader::import('controller/Jump', TRAIT_PATH, EXT);
use think\exception\ValidateException; use think\exception\ValidateException;
use traits\controller\Jump;
Loader::import('controller/Jump', TRAIT_PATH, EXT);
class Controller class Controller
{ {
use \traits\controller\Jump; use Jump;
/** /**
* @var \think\View 视图类实例 * @var \think\View 视图类实例
*/ */
protected $view; protected $view;
/** /**
* @var \think\Request Request实例 * @var \think\Request Request 实例
*/ */
protected $request; protected $request;
// 验证失败是否抛出异常
/**
* @var bool 验证失败是否抛出异常
*/
protected $failException = false; protected $failException = false;
// 是否批量验证
/**
* @var bool 是否批量验证
*/
protected $batchValidate = false; protected $batchValidate = false;
/** /**
* 前置操作方法列表 * @var array 前置操作方法列表
* @var array $beforeActionList
* @access protected
*/ */
protected $beforeActionList = []; protected $beforeActionList = [];
/** /**
* 构造方法 * 构造方法
* @param Request $request Request对象
* @access public * @access public
* @param Request $request Request 对象
*/ */
public function __construct(Request $request = null) public function __construct(Request $request = null)
{ {
if (is_null($request)) { $this->view = View::instance(Config::get('template'), Config::get('view_replace_str'));
$request = Request::instance(); $this->request = is_null($request) ? Request::instance() : $request;
}
$this->view = View::instance(Config::get('template'), Config::get('view_replace_str'));
$this->request = $request;
// 控制器初始化 // 控制器初始化
$this->_initialize(); $this->_initialize();
@@ -65,7 +68,10 @@ class Controller
} }
} }
// 初始化 /**
* 初始化操作
* @access protected
*/
protected function _initialize() protected function _initialize()
{ {
} }
@@ -73,8 +79,9 @@ class Controller
/** /**
* 前置操作 * 前置操作
* @access protected * @access protected
* @param string $method 前置操作方法名 * @param string $method 前置操作方法名
* @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]] * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
* @return void
*/ */
protected function beforeAction($method, $options = []) protected function beforeAction($method, $options = [])
{ {
@@ -82,6 +89,7 @@ class Controller
if (is_string($options['only'])) { if (is_string($options['only'])) {
$options['only'] = explode(',', $options['only']); $options['only'] = explode(',', $options['only']);
} }
if (!in_array($this->request->action(), $options['only'])) { if (!in_array($this->request->action(), $options['only'])) {
return; return;
} }
@@ -89,6 +97,7 @@ class Controller
if (is_string($options['except'])) { if (is_string($options['except'])) {
$options['except'] = explode(',', $options['except']); $options['except'] = explode(',', $options['except']);
} }
if (in_array($this->request->action(), $options['except'])) { if (in_array($this->request->action(), $options['except'])) {
return; return;
} }
@@ -100,10 +109,10 @@ class Controller
/** /**
* 加载模板输出 * 加载模板输出
* @access protected * @access protected
* @param string $template 模板文件名 * @param string $template 模板文件名
* @param array $vars 模板输出变量 * @param array $vars 模板输出变量
* @param array $replace 模板替换 * @param array $replace 模板替换
* @param array $config 模板参数 * @param array $config 模板参数
* @return mixed * @return mixed
*/ */
protected function fetch($template = '', $vars = [], $replace = [], $config = []) protected function fetch($template = '', $vars = [], $replace = [], $config = [])
@@ -114,10 +123,10 @@ class Controller
/** /**
* 渲染内容输出 * 渲染内容输出
* @access protected * @access protected
* @param string $content 模板内容 * @param string $content 模板内容
* @param array $vars 模板输出变量 * @param array $vars 模板输出变量
* @param array $replace 替换内容 * @param array $replace 替换内容
* @param array $config 模板参数 * @param array $config 模板参数
* @return mixed * @return mixed
*/ */
protected function display($content = '', $vars = [], $replace = [], $config = []) protected function display($content = '', $vars = [], $replace = [], $config = [])
@@ -128,24 +137,28 @@ class Controller
/** /**
* 模板变量赋值 * 模板变量赋值
* @access protected * @access protected
* @param mixed $name 要显示的模板变量 * @param mixed $name 要显示的模板变量
* @param mixed $value 变量的值 * @param mixed $value 变量的值
* @return void * @return $this
*/ */
protected function assign($name, $value = '') protected function assign($name, $value = '')
{ {
$this->view->assign($name, $value); $this->view->assign($name, $value);
return $this;
} }
/** /**
* 初始化模板引擎 * 初始化模板引擎
* @access protected * @access protected
* @param array|string $engine 引擎参数 * @param array|string $engine 引擎参数
* @return void * @return $this
*/ */
protected function engine($engine) protected function engine($engine)
{ {
$this->view->engine($engine); $this->view->engine($engine);
return $this;
} }
/** /**
@@ -157,17 +170,18 @@ class Controller
protected function validateFailException($fail = true) protected function validateFailException($fail = true)
{ {
$this->failException = $fail; $this->failException = $fail;
return $this; return $this;
} }
/** /**
* 验证数据 * 验证数据
* @access protected * @access protected
* @param array $data 数据 * @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组 * @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息 * @param array $message 提示信息
* @param bool $batch 是否批量验证 * @param bool $batch 是否批量验证
* @param mixed $callback 回调方法(闭包) * @param mixed $callback 回调方法(闭包)
* @return array|string|true * @return array|string|true
* @throws ValidateException * @throws ValidateException
*/ */
@@ -177,24 +191,21 @@ class Controller
$v = Loader::validate(); $v = Loader::validate();
$v->rule($validate); $v->rule($validate);
} else { } else {
// 支持场景
if (strpos($validate, '.')) { if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate); list($validate, $scene) = explode('.', $validate);
} }
$v = Loader::validate($validate); $v = Loader::validate($validate);
if (!empty($scene)) {
$v->scene($scene); !empty($scene) && $v->scene($scene);
}
}
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
if (is_array($message)) {
$v->message($message);
} }
// 批量验证
if ($batch || $this->batchValidate) $v->batch(true);
// 设置错误信息
if (is_array($message)) $v->message($message);
// 使用回调验证
if ($callback && is_callable($callback)) { if ($callback && is_callable($callback)) {
call_user_func_array($callback, [$v, &$data]); call_user_func_array($callback, [$v, &$data]);
} }
@@ -202,11 +213,11 @@ class Controller
if (!$v->check($data)) { if (!$v->check($data)) {
if ($this->failException) { if ($this->failException) {
throw new ValidateException($v->getError()); throw new ValidateException($v->getError());
} else {
return $v->getError();
} }
} else {
return true; return $v->getError();
} }
return true;
} }
} }
+104 -60
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -13,28 +13,28 @@ namespace think;
class Cookie class Cookie
{ {
/**
* @var array cookie 设置参数
*/
protected static $config = [ protected static $config = [
// cookie 名称前缀 'prefix' => '', // cookie 名称前缀
'prefix' => '', 'expire' => 0, // cookie 保存时间
// cookie 保存时间 'path' => '/', // cookie 保存路径
'expire' => 0, 'domain' => '', // cookie 有效域名
// cookie 保存路径 'secure' => false, // cookie 启用安全传输
'path' => '/', 'httponly' => false, // httponly 设置
// cookie 有效域名 'setcookie' => true, // 是否使用 setcookie
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => '',
// 是否使用 setcookie
'setcookie' => true,
]; ];
/**
* @var bool 是否完成初始化了
*/
protected static $init; protected static $init;
/** /**
* Cookie初始化 * Cookie初始化
* @param array $config * @access public
* @param array $config 配置参数
* @return void * @return void
*/ */
public static function init(array $config = []) public static function init(array $config = [])
@@ -42,39 +42,43 @@ class Cookie
if (empty($config)) { if (empty($config)) {
$config = Config::get('cookie'); $config = Config::get('cookie');
} }
self::$config = array_merge(self::$config, array_change_key_case($config)); self::$config = array_merge(self::$config, array_change_key_case($config));
if (!empty(self::$config['httponly'])) { if (!empty(self::$config['httponly'])) {
ini_set('session.cookie_httponly', 1); ini_set('session.cookie_httponly', 1);
} }
self::$init = true; self::$init = true;
} }
/** /**
* 设置或者获取cookie作用域(前缀) * 设置或者获取 cookie 作用域(前缀)
* @param string $prefix * @access public
* @return string|void * @param string $prefix 前缀
* @return string|
*/ */
public static function prefix($prefix = '') public static function prefix($prefix = '')
{ {
if (empty($prefix)) { if (empty($prefix)) {
return self::$config['prefix']; return self::$config['prefix'];
} }
self::$config['prefix'] = $prefix;
return self::$config['prefix'] = $prefix;
} }
/** /**
* Cookie 设置、获取、删除 * Cookie 设置、获取、删除
* * @access public
* @param string $name cookie名称 * @param string $name cookie 名称
* @param mixed $value cookie值 * @param mixed $value cookie
* @param mixed $option 可选参数 可能会是 null|integer|string * @param mixed $option 可选参数 可能会是 null|integer|string
* * @return void
* @return mixed
* @internal param mixed $options cookie参数
*/ */
public static function set($name, $value = '', $option = null) public static function set($name, $value = '', $option = null)
{ {
!isset(self::$init) && self::init(); !isset(self::$init) && self::init();
// 参数设置(会覆盖黙认设置) // 参数设置(会覆盖黙认设置)
if (!is_null($option)) { if (!is_null($option)) {
if (is_numeric($option)) { if (is_numeric($option)) {
@@ -82,28 +86,40 @@ class Cookie
} elseif (is_string($option)) { } elseif (is_string($option)) {
parse_str($option, $option); parse_str($option, $option);
} }
$config = array_merge(self::$config, array_change_key_case($option)); $config = array_merge(self::$config, array_change_key_case($option));
} else { } else {
$config = self::$config; $config = self::$config;
} }
$name = $config['prefix'] . $name; $name = $config['prefix'] . $name;
// 设置cookie
// 设置 cookie
if (is_array($value)) { if (is_array($value)) {
array_walk_recursive($value, 'self::jsonFormatProtect', 'encode'); array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');
$value = 'think:' . json_encode($value); $value = 'think:' . json_encode($value);
} }
$expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
$expire = !empty($config['expire']) ?
$_SERVER['REQUEST_TIME'] + intval($config['expire']) :
0;
if ($config['setcookie']) { if ($config['setcookie']) {
setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']); setcookie(
$name, $value, $expire, $config['path'], $config['domain'],
$config['secure'], $config['httponly']
);
} }
$_COOKIE[$name] = $value; $_COOKIE[$name] = $value;
} }
/** /**
* 永久保存Cookie数据 * 永久保存 Cookie 数据
* @param string $name cookie名称 * @access public
* @param mixed $value cookie * @param string $name cookie 名称
* @param mixed $option 可选参数 可能会是 null|integer|string * @param mixed $value cookie 值
* @param mixed $option 可选参数 可能会是 null|integer|string
* @return void * @return void
*/ */
public static function forever($name, $value = '', $option = null) public static function forever($name, $value = '', $option = null)
@@ -111,33 +127,39 @@ class Cookie
if (is_null($option) || is_numeric($option)) { if (is_null($option) || is_numeric($option)) {
$option = []; $option = [];
} }
$option['expire'] = 315360000; $option['expire'] = 315360000;
self::set($name, $value, $option); self::set($name, $value, $option);
} }
/** /**
* 判断Cookie数据 * 判断是否有 Cookie 数据
* @param string $name cookie名称 * @access public
* @param string|null $prefix cookie前缀 * @param string $name cookie 名称
* @param string|null $prefix cookie 前缀
* @return bool * @return bool
*/ */
public static function has($name, $prefix = null) public static function has($name, $prefix = null)
{ {
!isset(self::$init) && self::init(); !isset(self::$init) && self::init();
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
$name = $prefix . $name;
return isset($_COOKIE[$name]); return isset($_COOKIE[$prefix . $name]);
} }
/** /**
* Cookie获取 * 获取 Cookie 的值
* @param string $name cookie名称 * @access public
* @param string|null $prefix cookie前缀 * @param string $name cookie 名称
* @param string|null $prefix cookie 前缀
* @return mixed * @return mixed
*/ */
public static function get($name = '', $prefix = null) public static function get($name = '', $prefix = null)
{ {
!isset(self::$init) && self::init(); !isset(self::$init) && self::init();
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
$key = $prefix . $name; $key = $prefix . $name;
@@ -145,80 +167,102 @@ class Cookie
// 获取全部 // 获取全部
if ($prefix) { if ($prefix) {
$value = []; $value = [];
foreach ($_COOKIE as $k => $val) { foreach ($_COOKIE as $k => $val) {
if (0 === strpos($k, $prefix)) { if (0 === strpos($k, $prefix)) {
$value[$k] = $val; $value[$k] = $val;
} }
} }
} else { } else {
$value = $_COOKIE; $value = $_COOKIE;
} }
} elseif (isset($_COOKIE[$key])) { } elseif (isset($_COOKIE[$key])) {
$value = $_COOKIE[$key]; $value = $_COOKIE[$key];
if (0 === strpos($value, 'think:')) { if (0 === strpos($value, 'think:')) {
$value = substr($value, 6); $value = json_decode(substr($value, 6), true);
$value = json_decode($value, true);
array_walk_recursive($value, 'self::jsonFormatProtect', 'decode'); array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
} }
} else { } else {
$value = null; $value = null;
} }
return $value; return $value;
} }
/** /**
* Cookie删除 * 删除 Cookie
* @param string $name cookie名称 * @access public
* @param string|null $prefix cookie前缀 * @param string $name cookie 名称
* @return mixed * @param string|null $prefix cookie 前缀
* @return void
*/ */
public static function delete($name, $prefix = null) public static function delete($name, $prefix = null)
{ {
!isset(self::$init) && self::init(); !isset(self::$init) && self::init();
$config = self::$config; $config = self::$config;
$prefix = !is_null($prefix) ? $prefix : $config['prefix']; $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
$name = $prefix . $name; $name = $prefix . $name;
if ($config['setcookie']) { if ($config['setcookie']) {
setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']); setcookie(
$name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'],
$config['domain'], $config['secure'], $config['httponly']
);
} }
// 删除指定cookie
// 删除指定 cookie
unset($_COOKIE[$name]); unset($_COOKIE[$name]);
} }
/** /**
* Cookie清空 * 清除指定前缀的所有 cookie
* @param string|null $prefix cookie前缀 * @access public
* @return mixed * @param string|null $prefix cookie 前缀
* @return void
*/ */
public static function clear($prefix = null) public static function clear($prefix = null)
{ {
// 清除指定前缀的所有cookie
if (empty($_COOKIE)) { if (empty($_COOKIE)) {
return; return;
} }
!isset(self::$init) && self::init(); !isset(self::$init) && self::init();
// 要删除的cookie前缀,不指定则删除config设置的指定前缀
// 要删除的 cookie 前缀,不指定则删除 config 设置的指定前缀
$config = self::$config; $config = self::$config;
$prefix = !is_null($prefix) ? $prefix : $config['prefix']; $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
if ($prefix) { if ($prefix) {
// 如果前缀为空字符串将不作处理直接返回
foreach ($_COOKIE as $key => $val) { foreach ($_COOKIE as $key => $val) {
if (0 === strpos($key, $prefix)) { if (0 === strpos($key, $prefix)) {
if ($config['setcookie']) { if ($config['setcookie']) {
setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']); setcookie(
$key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'],
$config['domain'], $config['secure'], $config['httponly']
);
} }
unset($_COOKIE[$key]); unset($_COOKIE[$key]);
} }
} }
} }
return;
} }
private static function jsonFormatProtect(&$val, $key, $type = 'encode') /**
* json 转换时的格式保护
* @access protected
* @param mixed $val 要转换的值
* @param string $key 键名
* @param string $type 转换类别
* @return void
*/
protected static function jsonFormatProtect(&$val, $key, $type = 'encode')
{ {
if (!empty($val) && true !== $val) { if (!empty($val) && true !== $val) {
$val = 'decode' == $type ? urldecode($val) : urlencode($val); $val = 'decode' == $type ? urldecode($val) : urlencode($val);
} }
} }
} }
+53 -26
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -49,19 +49,26 @@ use think\db\Query;
*/ */
class Db class Db
{ {
// 数据库连接实例 /**
* @var Connection[] 数据库连接实例
*/
private static $instance = []; private static $instance = [];
// 查询次数
/**
* @var int 查询次数
*/
public static $queryTimes = 0; public static $queryTimes = 0;
// 执行次数
/**
* @var int 执行次数
*/
public static $executeTimes = 0; public static $executeTimes = 0;
/** /**
* 数据库初始化 并取得数据库类实例 * 数据库初始化并取得数据库类实例
* @static
* @access public * @access public
* @param mixed $config 连接配置 * @param mixed $config 连接配置
* @param bool|string $name 连接标识 true 强制重新连接 * @param bool|string $name 连接标识 true 强制重新连接
* @return Connection * @return Connection
* @throws Exception * @throws Exception
*/ */
@@ -70,31 +77,48 @@ class Db
if (false === $name) { if (false === $name) {
$name = md5(serialize($config)); $name = md5(serialize($config));
} }
if (true === $name || !isset(self::$instance[$name])) { if (true === $name || !isset(self::$instance[$name])) {
// 解析连接参数 支持数组和字符串 // 解析连接参数 支持数组和字符串
$options = self::parseConfig($config); $options = self::parseConfig($config);
if (empty($options['type'])) { if (empty($options['type'])) {
throw new \InvalidArgumentException('Undefined db type'); throw new \InvalidArgumentException('Undefined db type');
} }
$class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']);
$class = false !== strpos($options['type'], '\\') ?
$options['type'] :
'\\think\\db\\connector\\' . ucwords($options['type']);
// 记录初始化信息 // 记录初始化信息
if (App::$debug) { if (App::$debug) {
Log::record('[ DB ] INIT ' . $options['type'], 'info'); Log::record('[ DB ] INIT ' . $options['type'], 'info');
} }
if (true === $name) { if (true === $name) {
return new $class($options); $name = md5(serialize($config));
} else {
self::$instance[$name] = new $class($options);
} }
self::$instance[$name] = new $class($options);
} }
return self::$instance[$name]; return self::$instance[$name];
} }
/**
* 清除连接实例
* @access public
* @return void
*/
public static function clear()
{
self::$instance = [];
}
/** /**
* 数据库连接参数解析 * 数据库连接参数解析
* @static
* @access private * @access private
* @param mixed $config * @param mixed $config 连接参数
* @return array * @return array
*/ */
private static function parseConfig($config) private static function parseConfig($config)
@@ -102,30 +126,27 @@ class Db
if (empty($config)) { if (empty($config)) {
$config = Config::get('database'); $config = Config::get('database');
} elseif (is_string($config) && false === strpos($config, '/')) { } elseif (is_string($config) && false === strpos($config, '/')) {
// 支持读取配置参数 $config = Config::get($config); // 支持读取配置参数
$config = Config::get($config);
}
if (is_string($config)) {
return self::parseDsn($config);
} else {
return $config;
} }
return is_string($config) ? self::parseDsn($config) : $config;
} }
/** /**
* DSN解析 * DSN 解析
* 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8 * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8
* @static
* @access private * @access private
* @param string $dsnStr * @param string $dsnStr 数据库 DSN 字符串解析
* @return array * @return array
*/ */
private static function parseDsn($dsnStr) private static function parseDsn($dsnStr)
{ {
$info = parse_url($dsnStr); $info = parse_url($dsnStr);
if (!$info) { if (!$info) {
return []; return [];
} }
$dsn = [ $dsn = [
'type' => $info['scheme'], 'type' => $info['scheme'],
'username' => isset($info['user']) ? $info['user'] : '', 'username' => isset($info['user']) ? $info['user'] : '',
@@ -141,13 +162,19 @@ class Db
} else { } else {
$dsn['params'] = []; $dsn['params'] = [];
} }
return $dsn; return $dsn;
} }
// 调用驱动类的方法 /**
* 调用驱动类的方法
* @access public
* @param string $method 方法名
* @param array $params 参数
* @return mixed
*/
public static function __callStatic($method, $params) public static function __callStatic($method, $params)
{ {
// 自动初始化数据库
return call_user_func_array([self::connect(), $method], $params); return call_user_func_array([self::connect(), $method], $params);
} }
} }
+84 -44
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -16,21 +16,27 @@ use think\response\Redirect;
class Debug class Debug
{ {
// 区间时间信息 /**
* @var array 区间时间信息
*/
protected static $info = []; protected static $info = [];
// 区间内存信息
/**
* @var array 区间内存信息
*/
protected static $mem = []; protected static $mem = [];
/** /**
* 记录时间(微秒)和内存使用情况 * 记录时间(微秒)和内存使用情况
* @param string $name 标记位置 * @access public
* @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存 * @param string $name 标记位置
* @return mixed * @param mixed $value 标记值(留空则取当前 time 表示仅记录时间 否则同时记录时间和内存)
* @return void
*/ */
public static function remark($name, $value = '') public static function remark($name, $value = '')
{ {
// 记录时间和内存使用
self::$info[$name] = is_float($value) ? $value : microtime(true); self::$info[$name] = is_float($value) ? $value : microtime(true);
if ('time' != $value) { if ('time' != $value) {
self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage(); self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage();
self::$mem['peak'][$name] = memory_get_peak_usage(); self::$mem['peak'][$name] = memory_get_peak_usage();
@@ -39,23 +45,26 @@ class Debug
/** /**
* 统计某个区间的时间(微秒)使用情况 返回值以秒为单位 * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
* @param string $start 开始标签 * @access public
* @param string $end 结束标签 * @param string $start 开始标签
* @param integer|string $dec 小数位 * @param string $end 结束标签
* @return integer * @param integer $dec 小数位
* @return string
*/ */
public static function getRangeTime($start, $end, $dec = 6) public static function getRangeTime($start, $end, $dec = 6)
{ {
if (!isset(self::$info[$end])) { if (!isset(self::$info[$end])) {
self::$info[$end] = microtime(true); self::$info[$end] = microtime(true);
} }
return number_format((self::$info[$end] - self::$info[$start]), $dec); return number_format((self::$info[$end] - self::$info[$start]), $dec);
} }
/** /**
* 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位 * 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
* @param integer|string $dec 小数位 * @access public
* @return integer * @param integer $dec 小数位
* @return string
*/ */
public static function getUseTime($dec = 6) public static function getUseTime($dec = 6)
{ {
@@ -64,6 +73,7 @@ class Debug
/** /**
* 获取当前访问的吞吐率情况 * 获取当前访问的吞吐率情况
* @access public
* @return string * @return string
*/ */
public static function getThroughputRate() public static function getThroughputRate()
@@ -73,9 +83,10 @@ class Debug
/** /**
* 记录区间的内存使用情况 * 记录区间的内存使用情况
* @param string $start 开始标签 * @access public
* @param string $end 结束标签 * @param string $start 开始标签
* @param integer|string $dec 小数位 * @param string $end 结束标签
* @param integer $dec 小数位
* @return string * @return string
*/ */
public static function getRangeMem($start, $end, $dec = 2) public static function getRangeMem($start, $end, $dec = 2)
@@ -83,19 +94,23 @@ class Debug
if (!isset(self::$mem['mem'][$end])) { if (!isset(self::$mem['mem'][$end])) {
self::$mem['mem'][$end] = memory_get_usage(); self::$mem['mem'][$end] = memory_get_usage();
} }
$size = self::$mem['mem'][$end] - self::$mem['mem'][$start]; $size = self::$mem['mem'][$end] - self::$mem['mem'][$start];
$a = ['B', 'KB', 'MB', 'GB', 'TB']; $a = ['B', 'KB', 'MB', 'GB', 'TB'];
$pos = 0; $pos = 0;
while ($size >= 1024) { while ($size >= 1024) {
$size /= 1024; $size /= 1024;
$pos++; $pos++;
} }
return round($size, $dec) . " " . $a[$pos]; return round($size, $dec) . " " . $a[$pos];
} }
/** /**
* 统计从开始到统计时的内存使用情况 * 统计从开始到统计时的内存使用情况
* @param integer|string $dec 小数位 * @access public
* @param integer $dec 小数位
* @return string * @return string
*/ */
public static function getUseMem($dec = 2) public static function getUseMem($dec = 2)
@@ -103,103 +118,128 @@ class Debug
$size = memory_get_usage() - THINK_START_MEM; $size = memory_get_usage() - THINK_START_MEM;
$a = ['B', 'KB', 'MB', 'GB', 'TB']; $a = ['B', 'KB', 'MB', 'GB', 'TB'];
$pos = 0; $pos = 0;
while ($size >= 1024) { while ($size >= 1024) {
$size /= 1024; $size /= 1024;
$pos++; $pos++;
} }
return round($size, $dec) . " " . $a[$pos]; return round($size, $dec) . " " . $a[$pos];
} }
/** /**
* 统计区间的内存峰值情况 * 统计区间的内存峰值情况
* @param string $start 开始标签 * @access public
* @param string $end 结束标签 * @param string $start 开始标签
* @param integer|string $dec 小数位 * @param string $end 结束标签
* @return mixed * @param integer $dec 小数位
* @return string
*/ */
public static function getMemPeak($start, $end, $dec = 2) public static function getMemPeak($start, $end, $dec = 2)
{ {
if (!isset(self::$mem['peak'][$end])) { if (!isset(self::$mem['peak'][$end])) {
self::$mem['peak'][$end] = memory_get_peak_usage(); self::$mem['peak'][$end] = memory_get_peak_usage();
} }
$size = self::$mem['peak'][$end] - self::$mem['peak'][$start]; $size = self::$mem['peak'][$end] - self::$mem['peak'][$start];
$a = ['B', 'KB', 'MB', 'GB', 'TB']; $a = ['B', 'KB', 'MB', 'GB', 'TB'];
$pos = 0; $pos = 0;
while ($size >= 1024) { while ($size >= 1024) {
$size /= 1024; $size /= 1024;
$pos++; $pos++;
} }
return round($size, $dec) . " " . $a[$pos]; return round($size, $dec) . " " . $a[$pos];
} }
/** /**
* 获取文件加载信息 * 获取文件加载信息
* @param bool $detail 是否显示详细 * @access public
* @param bool $detail 是否显示详细
* @return integer|array * @return integer|array
*/ */
public static function getFile($detail = false) public static function getFile($detail = false)
{ {
$files = get_included_files();
if ($detail) { if ($detail) {
$files = get_included_files(); $info = [];
$info = [];
foreach ($files as $key => $file) { foreach ($files as $file) {
$info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
} }
return $info; return $info;
} }
return count(get_included_files());
return count($files);
} }
/** /**
* 浏览器友好的变量输出 * 浏览器友好的变量输出
* @param mixed $var 变量 * @access public
* @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 * @param mixed $var 变量
* @param string $label 标签 默认为空 * @param boolean $echo 是否输出(默认为 true,为 false 则返回输出字符串)
* @param integer $flags htmlspecialchars flags * @param string|null $label 标签(默认为空)
* @return void|string * @param integer $flags htmlspecialchars 的标志
* @return null|string
*/ */
public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE) public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
{ {
$label = (null === $label) ? '' : rtrim($label) . ':'; $label = (null === $label) ? '' : rtrim($label) . ':';
ob_start(); ob_start();
var_dump($var); var_dump($var);
$output = ob_get_clean(); $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', ob_get_clean());
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
if (IS_CLI) { if (IS_CLI) {
$output = PHP_EOL . $label . $output . PHP_EOL; $output = PHP_EOL . $label . $output . PHP_EOL;
} else { } else {
if (!extension_loaded('xdebug')) { if (!extension_loaded('xdebug')) {
$output = htmlspecialchars($output, $flags); $output = htmlspecialchars($output, $flags);
} }
$output = '<pre>' . $label . $output . '</pre>'; $output = '<pre>' . $label . $output . '</pre>';
} }
if ($echo) { if ($echo) {
echo($output); echo($output);
return; return;
} else {
return $output;
} }
return $output;
} }
/**
* 调试信息注入到响应中
* @access public
* @param Response $response 响应实例
* @param string $content 返回的字符串
* @return void
*/
public static function inject(Response $response, &$content) public static function inject(Response $response, &$content)
{ {
$config = Config::get('trace'); $config = Config::get('trace');
$type = isset($config['type']) ? $config['type'] : 'Html'; $type = isset($config['type']) ? $config['type'] : 'Html';
$request = Request::instance(); $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
$class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
unset($config['type']); unset($config['type']);
if (class_exists($class)) {
$trace = new $class($config); if (!class_exists($class)) {
} else {
throw new ClassNotFoundException('class not exists:' . $class, $class); throw new ClassNotFoundException('class not exists:' . $class, $class);
} }
/** @var \think\debug\Console|\think\debug\Html $trace */
$trace = new $class($config);
if ($response instanceof Redirect) { if ($response instanceof Redirect) {
//TODO 记录 // TODO 记录
} else { } else {
$output = $trace->output($response, Log::getLog()); $output = $trace->output($response, Log::getLog());
if (is_string($output)) { if (is_string($output)) {
// trace调试信息注入 // trace 调试信息注入
$pos = strripos($content, '</body>'); $pos = strripos($content, '</body>');
if (false !== $pos) { if (false !== $pos) {
$content = substr($content, 0, $pos) . $output . substr($content, $pos); $content = substr($content, 0, $pos) . $output . substr($content, $pos);
+8 -5
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -15,22 +15,25 @@ class Env
{ {
/** /**
* 获取环境变量值 * 获取环境变量值
* @param string $name 环境变量名(支持二级 .号分割) * @access public
* @param string $default 默认值 * @param string $name 环境变量名(支持二级 . 号分割)
* @param string $default 默认值
* @return mixed * @return mixed
*/ */
public static function get($name, $default = null) public static function get($name, $default = null)
{ {
$result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name))); $result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name)));
if (false !== $result) { if (false !== $result) {
if ('false' === $result) { if ('false' === $result) {
$result = false; $result = false;
} elseif ('true' === $result) { } elseif ('true' === $result) {
$result = true; $result = true;
} }
return $result; return $result;
} else {
return $default;
} }
return $default;
} }
} }
+47 -28
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -20,6 +20,7 @@ class Error
{ {
/** /**
* 注册异常处理 * 注册异常处理
* @access public
* @return void * @return void
*/ */
public static function register() public static function register()
@@ -31,8 +32,10 @@ class Error
} }
/** /**
* Exception Handler * 异常处理
* @param \Exception|\Throwable $e * @access public
* @param \Exception|\Throwable $e 异常
* @return void
*/ */
public static function appException($e) public static function appException($e)
{ {
@@ -40,44 +43,50 @@ class Error
$e = new ThrowableError($e); $e = new ThrowableError($e);
} }
self::getExceptionHandler()->report($e); $handler = self::getExceptionHandler();
$handler->report($e);
if (IS_CLI) { if (IS_CLI) {
self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); $handler->renderForConsole(new ConsoleOutput, $e);
} else { } else {
self::getExceptionHandler()->render($e)->send(); $handler->render($e)->send();
} }
} }
/** /**
* Error Handler * 错误处理
* @param integer $errno 错误编号 * @access public
* @param integer $errstr 详细错误信息 * @param integer $errno 错误编号
* @param string $errfile 出错的文件 * @param integer $errstr 详细错误信息
* @param integer $errline 出错行号 * @param string $errfile 出错的文件
* @param array $errcontext * @param integer $errline 出错行号
* @return void
* @throws ErrorException * @throws ErrorException
*/ */
public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = []) public static function appError($errno, $errstr, $errfile = '', $errline = 0)
{ {
$exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext); $exception = new ErrorException($errno, $errstr, $errfile, $errline);
// 符合异常处理的则将错误信息托管至 think\exception\ErrorException
if (error_reporting() & $errno) { if (error_reporting() & $errno) {
// 将错误信息托管至 think\exception\ErrorException
throw $exception; throw $exception;
} else {
self::getExceptionHandler()->report($exception);
} }
self::getExceptionHandler()->report($exception);
} }
/** /**
* Shutdown Handler * 异常中止处理
* @access public
* @return void
*/ */
public static function appShutdown() public static function appShutdown()
{ {
// 将错误信息托管至 think\ErrorException
if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {
// 将错误信息托管至think\ErrorException self::appException(new ErrorException(
$exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); $error['type'], $error['message'], $error['file'], $error['line']
));
self::appException($exception);
} }
// 写入日志 // 写入日志
@@ -86,8 +95,8 @@ class Error
/** /**
* 确定错误类型是否致命 * 确定错误类型是否致命
* * @access protected
* @param int $type * @param int $type 错误类型
* @return bool * @return bool
*/ */
protected static function isFatal($type) protected static function isFatal($type)
@@ -96,22 +105,32 @@ class Error
} }
/** /**
* Get an instance of the exception handler. * 获取异常处理的实例
* * @access public
* @return Handle * @return Handle
*/ */
public static function getExceptionHandler() public static function getExceptionHandler()
{ {
static $handle; static $handle;
if (!$handle) { if (!$handle) {
// 异常处理handle // 异常处理 handle
$class = Config::get('exception_handle'); $class = Config::get('exception_handle');
if ($class && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) {
if ($class && is_string($class) && class_exists($class) &&
is_subclass_of($class, "\\think\\exception\\Handle")
) {
$handle = new $class; $handle = new $class;
} else { } else {
$handle = new Handle; $handle = new Handle;
if ($class instanceof \Closure) {
$handle->setRender($class);
}
} }
} }
return $handle; return $handle;
} }
} }
+11 -10
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -13,15 +13,13 @@ namespace think;
class Exception extends \Exception class Exception extends \Exception
{ {
/** /**
* 保存异常页面显示的额外Debug数据 * @var array 保存异常页面显示的额外 Debug 数据
* @var array
*/ */
protected $data = []; protected $data = [];
/** /**
* 设置异常额外的Debug数据 * 设置异常额外的 Debug 数据
* 数据将会显示为下面的格式 * 数据将会显示为下面的格式
* *
* Exception Data * Exception Data
@@ -33,8 +31,10 @@ class Exception extends \Exception
* key1 value1 * key1 value1
* key2 value2 * key2 value2
* *
* @param string $label 数据分类,用于异常页面显示 * @access protected
* @param array $data 需要显示的数据,必须为关联数组 * @param string $label 数据分类,用于异常页面显示
* @param array $data 需要显示的数据,必须为关联数组
* @return void
*/ */
final protected function setData($label, array $data) final protected function setData($label, array $data)
{ {
@@ -42,13 +42,14 @@ class Exception extends \Exception
} }
/** /**
* 获取异常额外Debug数据 * 获取异常额外 Debug 数据
* 主要用于输出到异常页面便于调试 * 主要用于输出到异常页面便于调试
* @return array 由setData设置的Debug数据 * @access public
* @return array
*/ */
final public function getData() final public function getData()
{ {
return $this->data; return $this->data;
} }
} }
+155 -87
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -16,25 +16,51 @@ use SplFileObject;
class File extends SplFileObject class File extends SplFileObject
{ {
/** /**
* 错误信息 * @var string 错误信息
* @var string
*/ */
private $error = ''; private $error = '';
// 当前完整文件名
/**
* @var string 当前完整文件名
*/
protected $filename; protected $filename;
// 上传文件名
/**
* @var string 上传文件名
*/
protected $saveName; protected $saveName;
// 文件上传命名规则
/**
* @var string 文件上传命名规则
*/
protected $rule = 'date'; protected $rule = 'date';
// 文件上传验证规则
/**
* @var array 文件上传验证规则
*/
protected $validate = []; protected $validate = [];
// 单元测试
/**
* @var bool 单元测试
*/
protected $isTest; protected $isTest;
// 上传文件信息
/**
* @var array 上传文件信息
*/
protected $info; protected $info;
// 文件hash信息
/**
* @var array 文件 hash 信息
*/
protected $hash = []; protected $hash = [];
/**
* File constructor.
* @access public
* @param string $filename 文件名称
* @param string $mode 访问模式
*/
public function __construct($filename, $mode = 'r') public function __construct($filename, $mode = 'r')
{ {
parent::__construct($filename, $mode); parent::__construct($filename, $mode);
@@ -42,30 +68,35 @@ class File extends SplFileObject
} }
/** /**
* 是否测试 * 设置是否是单元测试
* @param bool $test 是否测试 * @access public
* @param bool $test 是否是测试
* @return $this * @return $this
*/ */
public function isTest($test = false) public function isTest($test = false)
{ {
$this->isTest = $test; $this->isTest = $test;
return $this; return $this;
} }
/** /**
* 设置上传信息 * 设置上传信息
* @param array $info 上传文件信息 * @access public
* @param array $info 上传文件信息
* @return $this * @return $this
*/ */
public function setUploadInfo($info) public function setUploadInfo($info)
{ {
$this->info = $info; $this->info = $info;
return $this; return $this;
} }
/** /**
* 获取上传文件的信息 * 获取上传文件的信息
* @param string $name * @access public
* @param string $name 信息名称
* @return array|string * @return array|string
*/ */
public function getInfo($name = '') public function getInfo($name = '')
@@ -75,6 +106,7 @@ class File extends SplFileObject
/** /**
* 获取上传文件的文件名 * 获取上传文件的文件名
* @access public
* @return string * @return string
*/ */
public function getSaveName() public function getSaveName()
@@ -84,93 +116,101 @@ class File extends SplFileObject
/** /**
* 设置上传文件的保存文件名 * 设置上传文件的保存文件名
* @param string $saveName * @access public
* @param string $saveName 保存名称
* @return $this * @return $this
*/ */
public function setSaveName($saveName) public function setSaveName($saveName)
{ {
$this->saveName = $saveName; $this->saveName = $saveName;
return $this; return $this;
} }
/** /**
* 获取文件的哈希散列值 * 获取文件的哈希散列值
* @return $string * @access public
* @param string $type 类型
* @return string
*/ */
public function hash($type = 'sha1') public function hash($type = 'sha1')
{ {
if (!isset($this->hash[$type])) { if (!isset($this->hash[$type])) {
$this->hash[$type] = hash_file($type, $this->filename); $this->hash[$type] = hash_file($type, $this->filename);
} }
return $this->hash[$type]; return $this->hash[$type];
} }
/** /**
* 检查目录是否可写 * 检查目录是否可写
* @param string $path 目录 * @access protected
* @param string $path 目录
* @return boolean * @return boolean
*/ */
protected function checkPath($path) protected function checkPath($path)
{ {
if (is_dir($path)) { if (is_dir($path) || mkdir($path, 0755, true)) {
return true; return true;
} }
if (mkdir($path, 0755, true)) { $this->error = ['directory {:path} creation failed', ['path' => $path]];
return true;
} else { return false;
$this->error = "目录 {$path} 创建失败!";
return false;
}
} }
/** /**
* 获取文件类型信息 * 获取文件类型信息
* @access public
* @return string * @return string
*/ */
public function getMime() public function getMime()
{ {
$finfo = finfo_open(FILEINFO_MIME_TYPE); $finfo = finfo_open(FILEINFO_MIME_TYPE);
return finfo_file($finfo, $this->filename); return finfo_file($finfo, $this->filename);
} }
/** /**
* 设置文件的命名规则 * 设置文件的命名规则
* @param string $rule 文件命名规则 * @access public
* @param string $rule 文件命名规则
* @return $this * @return $this
*/ */
public function rule($rule) public function rule($rule)
{ {
$this->rule = $rule; $this->rule = $rule;
return $this; return $this;
} }
/** /**
* 设置上传文件的验证规则 * 设置上传文件的验证规则
* @param array $rule 验证规则 * @access public
* @param array $rule 验证规则
* @return $this * @return $this
*/ */
public function validate($rule = []) public function validate(array $rule = [])
{ {
$this->validate = $rule; $this->validate = $rule;
return $this; return $this;
} }
/** /**
* 检测是否合法的上传文件 * 检测是否合法的上传文件
* @access public
* @return bool * @return bool
*/ */
public function isValid() public function isValid()
{ {
if ($this->isTest) { return $this->isTest ? is_file($this->filename) : is_uploaded_file($this->filename);
return is_file($this->filename);
}
return is_uploaded_file($this->filename);
} }
/** /**
* 检测上传文件 * 检测上传文件
* @param array $rule 验证规则 * @access public
* @param array $rule 验证规则
* @return bool * @return bool
*/ */
public function check($rule = []) public function check($rule = [])
@@ -179,25 +219,25 @@ class File extends SplFileObject
/* 检查文件大小 */ /* 检查文件大小 */
if (isset($rule['size']) && !$this->checkSize($rule['size'])) { if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
$this->error = '上传文件大小不符!'; $this->error = 'filesize not match';
return false; return false;
} }
/* 检查文件Mime类型 */ /* 检查文件 Mime 类型 */
if (isset($rule['type']) && !$this->checkMime($rule['type'])) { if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
$this->error = '上传文件MIME类型不允许!'; $this->error = 'mimetype to upload is not allowed';
return false; return false;
} }
/* 检查文件后缀 */ /* 检查文件后缀 */
if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) { if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
$this->error = '上传文件后缀不允许'; $this->error = 'extensions to upload is not allowed';
return false; return false;
} }
/* 检查图像文件 */ /* 检查图像文件 */
if (!$this->checkImg()) { if (!$this->checkImg()) {
$this->error = '非法图像文件!'; $this->error = 'illegal image files';
return false; return false;
} }
@@ -206,7 +246,8 @@ class File extends SplFileObject
/** /**
* 检测上传文件后缀 * 检测上传文件后缀
* @param array|string $ext 允许后缀 * @access public
* @param array|string $ext 允许后缀
* @return bool * @return bool
*/ */
public function checkExt($ext) public function checkExt($ext)
@@ -214,73 +255,76 @@ class File extends SplFileObject
if (is_string($ext)) { if (is_string($ext)) {
$ext = explode(',', $ext); $ext = explode(',', $ext);
} }
$extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
if (!in_array($extension, $ext)) {
return false; return in_array($extension, $ext);
}
return true;
} }
/** /**
* 检测图像文件 * 检测图像文件
* @access public
* @return bool * @return bool
*/ */
public function checkImg() public function checkImg()
{ {
$extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
/* 对图像文件进行严格检测 */
if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6])) { // 如果上传的不是图片,或者是图片而且后缀确实符合图片类型则返回 true
return false; return !in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) || in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13]);
}
return true;
} }
// 判断图像类型 /**
* 判断图像类型
* @access protected
* @param string $image 图片名称
* @return bool|int
*/
protected function getImageType($image) protected function getImageType($image)
{ {
if (function_exists('exif_imagetype')) { if (function_exists('exif_imagetype')) {
return exif_imagetype($image); return exif_imagetype($image);
} else { }
try {
$info = getimagesize($image); $info = getimagesize($image);
return $info[2]; return $info ? $info[2] : false;
} catch (\Exception $e) {
return false;
} }
} }
/** /**
* 检测上传文件大小 * 检测上传文件大小
* @param integer $size 最大大小 * @access public
* @param integer $size 最大大小
* @return bool * @return bool
*/ */
public function checkSize($size) public function checkSize($size)
{ {
if ($this->getSize() > $size) { return $this->getSize() <= $size;
return false;
}
return true;
} }
/** /**
* 检测上传文件类型 * 检测上传文件类型
* @param array|string $mime 允许类型 * @access public
* @param array|string $mime 允许类型
* @return bool * @return bool
*/ */
public function checkMime($mime) public function checkMime($mime)
{ {
if (is_string($mime)) { $mime = is_string($mime) ? explode(',', $mime) : $mime;
$mime = explode(',', $mime);
} return in_array(strtolower($this->getMime()), $mime);
if (!in_array(strtolower($this->getMime()), $mime)) {
return false;
}
return true;
} }
/** /**
* 移动文件 * 移动文件
* @param string $path 保存路径 * @access public
* @param string|bool $savename 保存的文件名 默认自动生成 * @param string $path 保存路径
* @param boolean $replace 同名文件是否覆盖 * @param string|bool $savename 保存的文件名 默认自动生成
* @return false|File false-失败 否则返回File实例 * @param boolean $replace 同名文件是否覆盖
* @return false|File
*/ */
public function move($path, $savename = true, $replace = true) public function move($path, $savename = true, $replace = true)
{ {
@@ -292,7 +336,7 @@ class File extends SplFileObject
// 检测合法性 // 检测合法性
if (!$this->isValid()) { if (!$this->isValid()) {
$this->error = '非法上传文件'; $this->error = 'upload illegal files';
return false; return false;
} }
@@ -300,6 +344,7 @@ class File extends SplFileObject
if (!$this->check()) { if (!$this->check()) {
return false; return false;
} }
$path = rtrim($path, DS) . DS; $path = rtrim($path, DS) . DS;
// 文件保存命名规则 // 文件保存命名规则
$saveName = $this->buildSaveName($savename); $saveName = $this->buildSaveName($savename);
@@ -310,9 +355,9 @@ class File extends SplFileObject
return false; return false;
} }
/* 不覆盖同名文件 */ // 不覆盖同名文件
if (!$replace && is_file($filename)) { if (!$replace && is_file($filename)) {
$this->error = '存在同名文件' . $filename; $this->error = ['has the same filename: {:filename}', ['filename' => $filename]];
return false; return false;
} }
@@ -320,25 +365,27 @@ class File extends SplFileObject
if ($this->isTest) { if ($this->isTest) {
rename($this->filename, $filename); rename($this->filename, $filename);
} elseif (!move_uploaded_file($this->filename, $filename)) { } elseif (!move_uploaded_file($this->filename, $filename)) {
$this->error = '文件上传保存错误!'; $this->error = 'upload write error';
return false; return false;
} }
// 返回 File对象实例
// 返回 File 对象实例
$file = new self($filename); $file = new self($filename);
$file->setSaveName($saveName); $file->setSaveName($saveName)->setUploadInfo($this->info);
$file->setUploadInfo($this->info);
return $file; return $file;
} }
/** /**
* 获取保存文件名 * 获取保存文件名
* @param string|bool $savename 保存的文件名 默认自动生成 * @access protected
* @param string|bool $savename 保存的文件名 默认自动生成
* @return string * @return string
*/ */
protected function buildSaveName($savename) protected function buildSaveName($savename)
{ {
// 自动生成文件名
if (true === $savename) { if (true === $savename) {
// 自动生成文件名
if ($this->rule instanceof \Closure) { if ($this->rule instanceof \Closure) {
$savename = call_user_func_array($this->rule, [$this]); $savename = call_user_func_array($this->rule, [$this]);
} else { } else {
@@ -357,52 +404,73 @@ class File extends SplFileObject
} }
} }
} }
} elseif ('' === $savename) { } elseif ('' === $savename || false === $savename) {
$savename = $this->getInfo('name'); $savename = $this->getInfo('name');
} }
if (!strpos($savename, '.')) { if (!strpos($savename, '.')) {
$savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION); $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
} }
return $savename; return $savename;
} }
/** /**
* 获取错误代码信息 * 获取错误代码信息
* @param int $errorNo 错误号 * @access private
* @param int $errorNo 错误号
* @return $this
*/ */
private function error($errorNo) private function error($errorNo)
{ {
switch ($errorNo) { switch ($errorNo) {
case 1: case 1:
case 2: case 2:
$this->error = '上传文件大小超过了最大值!'; $this->error = 'upload File size exceeds the maximum value';
break; break;
case 3: case 3:
$this->error = '文件只有部分被上传!'; $this->error = 'only the portion of file is uploaded';
break; break;
case 4: case 4:
$this->error = '没有文件被上传!'; $this->error = 'no file to uploaded';
break; break;
case 6: case 6:
$this->error = '找不到临时文件夹!'; $this->error = 'upload temp dir not found';
break; break;
case 7: case 7:
$this->error = '文件写入失败!'; $this->error = 'file write error';
break; break;
default: default:
$this->error = '未知上传错误!'; $this->error = 'unknown upload error';
} }
return $this;
} }
/** /**
* 获取错误信息 * 获取错误信息(支持多语言)
* @return mixed * @access public
* @return string
*/ */
public function getError() public function getError()
{ {
return $this->error; if (is_array($this->error)) {
list($msg, $vars) = $this->error;
} else {
$msg = $this->error;
$vars = [];
}
return Lang::has($msg) ? Lang::get($msg, $vars) : $msg;
} }
/**
* 魔法方法,获取文件的 hash 值
* @access public
* @param string $method 方法名
* @param mixed $args 调用参数
* @return string
*/
public function __call($method, $args) public function __call($method, $args)
{ {
return $this->hash($method); return $this->hash($method);
+37 -25
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -13,19 +13,23 @@ namespace think;
class Hook class Hook
{ {
/**
* @var array 标签
*/
private static $tags = []; private static $tags = [];
/** /**
* 动态添加行为扩展到某个标签 * 动态添加行为扩展到某个标签
* @param string $tag 标签名称 * @access public
* @param mixed $behavior 行为名称 * @param string $tag 标签名称
* @param bool $first 是否放到开头执行 * @param mixed $behavior 行为名称
* @param bool $first 是否放到开头执行
* @return void * @return void
*/ */
public static function add($tag, $behavior, $first = false) public static function add($tag, $behavior, $first = false)
{ {
isset(self::$tags[$tag]) || self::$tags[$tag] = []; isset(self::$tags[$tag]) || self::$tags[$tag] = [];
if (is_array($behavior) && !is_callable($behavior)) { if (is_array($behavior) && !is_callable($behavior)) {
if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) { if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
unset($behavior['_overlay']); unset($behavior['_overlay']);
@@ -43,8 +47,10 @@ class Hook
/** /**
* 批量导入插件 * 批量导入插件
* @param array $tags 插件信息 * @access public
* @param boolean $recursive 是否递归合并 * @param array $tags 插件信息
* @param boolean $recursive 是否递归合并
* @return void
*/ */
public static function import(array $tags, $recursive = true) public static function import(array $tags, $recursive = true)
{ {
@@ -59,55 +65,59 @@ class Hook
/** /**
* 获取插件信息 * 获取插件信息
* @param string $tag 插件位置 留空获取全部 * @access public
* @param string $tag 插件位置(留空获取全部)
* @return array * @return array
*/ */
public static function get($tag = '') public static function get($tag = '')
{ {
if (empty($tag)) { if (empty($tag)) {
//获取全部的插件信息
return self::$tags; return self::$tags;
} else {
return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
} }
return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
} }
/** /**
* 监听标签的行为 * 监听标签的行为
* @param string $tag 标签名称 * @access public
* @param mixed $params 传入参数 * @param string $tag 标签名称
* @param mixed $extra 额外参数 * @param mixed $params 传入参数
* @param bool $once 只获取一个有效返回值 * @param mixed $extra 额外参数
* @param bool $once 只获取一个有效返回值
* @return mixed * @return mixed
*/ */
public static function listen($tag, &$params = null, $extra = null, $once = false) public static function listen($tag, &$params = null, $extra = null, $once = false)
{ {
$results = []; $results = [];
$tags = static::get($tag);
foreach ($tags as $key => $name) { foreach (static::get($tag) as $key => $name) {
$results[$key] = self::exec($name, $tag, $params, $extra); $results[$key] = self::exec($name, $tag, $params, $extra);
if (false === $results[$key]) {
// 如果返回false 则中断行为执行 // 如果返回 false,或者仅获取一个有效返回则中断行为执行
break; if (false === $results[$key] || (!is_null($results[$key]) && $once)) {
} elseif (!is_null($results[$key]) && $once) {
break; break;
} }
} }
return $once ? end($results) : $results; return $once ? end($results) : $results;
} }
/** /**
* 执行某个行为 * 执行某个行为
* @param mixed $class 要执行的行为 * @access public
* @param string $tag 方法名(标签名) * @param mixed $class 要执行的行为
* @param Mixed $params 传人的参数 * @param string $tag 方法名(标签名)
* @param mixed $extra 额外参数 * @param mixed $params 传人的参数
* @param mixed $extra 额外参数
* @return mixed * @return mixed
*/ */
public static function exec($class, $tag = '', &$params = null, $extra = null) public static function exec($class, $tag = '', &$params = null, $extra = null)
{ {
App::$debug && Debug::remark('behavior_start', 'time'); App::$debug && Debug::remark('behavior_start', 'time');
$method = Loader::parseName($tag, 1, false); $method = Loader::parseName($tag, 1, false);
if ($class instanceof \Closure) { if ($class instanceof \Closure) {
$result = call_user_func_array($class, [ & $params, $extra]); $result = call_user_func_array($class, [ & $params, $extra]);
$class = 'Closure'; $class = 'Closure';
@@ -126,10 +136,12 @@ class Hook
$method = ($tag && is_callable([$obj, $method])) ? $method : 'run'; $method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
$result = $obj->$method($params, $extra); $result = $obj->$method($params, $extra);
} }
if (App::$debug) { if (App::$debug) {
Debug::remark('behavior_end', 'time'); Debug::remark('behavior_end', 'time');
Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info'); Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
} }
return $result; return $result;
} }
+91 -46
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -13,114 +13,148 @@ namespace think;
class Lang class Lang
{ {
// 语言数据 /**
* @var array 语言数据
*/
private static $lang = []; private static $lang = [];
// 语言作用域
private static $range = 'zh-cn';
// 语言自动侦测的变量
protected static $langDetectVar = 'lang';
// 语言Cookie变量
protected static $langCookieVar = 'think_var';
// 语言Cookie的过期时间
protected static $langCookieExpire = 3600;
// 允许语言列表
protected static $allowLangList = [];
// Accept-Language转义为对应语言包名称 系统默认配置
protected static $acceptLanguage = [
'zh-hans-cn' => 'zh-cn',
];
// 设定当前的语言 /**
* @var string 语言作用域
*/
private static $range = 'zh-cn';
/**
* @var string 语言自动侦测的变量
*/
protected static $langDetectVar = 'lang';
/**
* @var string 语言 Cookie 变量
*/
protected static $langCookieVar = 'think_var';
/**
* @var int 语言 Cookie 的过期时间
*/
protected static $langCookieExpire = 3600;
/**
* @var array 允许语言列表
*/
protected static $allowLangList = [];
/**
* @var array Accept-Language 转义为对应语言包名称 系统默认配置
*/
protected static $acceptLanguage = ['zh-hans-cn' => 'zh-cn'];
/**
* 设定当前的语言
* @access public
* @param string $range 语言作用域
* @return string
*/
public static function range($range = '') public static function range($range = '')
{ {
if ('' == $range) { if ($range) {
return self::$range;
} else {
self::$range = $range; self::$range = $range;
} }
return self::$range; return self::$range;
} }
/** /**
* 设置语言定义(不区分大小写) * 设置语言定义(不区分大小写)
* @param string|array $name 语言变量 * @access public
* @param string $value 语言 * @param string|array $name 语言变量
* @param string $range 语言作用域 * @param string $value 语言
* @param string $range 语言作用域
* @return mixed * @return mixed
*/ */
public static function set($name, $value = null, $range = '') public static function set($name, $value = null, $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
// 批量定义
if (!isset(self::$lang[$range])) { if (!isset(self::$lang[$range])) {
self::$lang[$range] = []; self::$lang[$range] = [];
} }
if (is_array($name)) { if (is_array($name)) {
return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range]; return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range];
} else {
return self::$lang[$range][strtolower($name)] = $value;
} }
return self::$lang[$range][strtolower($name)] = $value;
} }
/** /**
* 加载语言定义(不区分大小写) * 加载语言定义(不区分大小写)
* @param string $file 语言文件 * @access public
* @param string $range 语言作用域 * @param array|string $file 语言文件
* @param string $range 语言作用域
* @return mixed * @return mixed
*/ */
public static function load($file, $range = '') public static function load($file, $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
$file = is_string($file) ? [$file] : $file;
if (!isset(self::$lang[$range])) { if (!isset(self::$lang[$range])) {
self::$lang[$range] = []; self::$lang[$range] = [];
} }
// 批量定义
if (is_string($file)) {
$file = [$file];
}
$lang = []; $lang = [];
foreach ($file as $_file) { foreach ($file as $_file) {
if (is_file($_file)) { if (is_file($_file)) {
// 记录加载信息 // 记录加载信息
App::$debug && Log::record('[ LANG ] ' . $_file, 'info'); App::$debug && Log::record('[ LANG ] ' . $_file, 'info');
$_lang = include $_file; $_lang = include $_file;
if (is_array($_lang)) { if (is_array($_lang)) {
$lang = array_change_key_case($_lang) + $lang; $lang = array_change_key_case($_lang) + $lang;
} }
} }
} }
if (!empty($lang)) { if (!empty($lang)) {
self::$lang[$range] = $lang + self::$lang[$range]; self::$lang[$range] = $lang + self::$lang[$range];
} }
return self::$lang[$range]; return self::$lang[$range];
} }
/** /**
* 获取语言定义(不区分大小写) * 获取语言定义(不区分大小写)
* @param string|null $name 语言变量 * @access public
* @param string $range 语言作用域 * @param string|null $name 语言变量
* @param string $range 语言作用域
* @return mixed * @return mixed
*/ */
public static function has($name, $range = '') public static function has($name, $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
return isset(self::$lang[$range][strtolower($name)]); return isset(self::$lang[$range][strtolower($name)]);
} }
/** /**
* 获取语言定义(不区分大小写) * 获取语言定义(不区分大小写)
* @param string|null $name 语言变量 * @access public
* @param array $vars 变量替换 * @param string|null $name 语言变量
* @param string $range 语言作用域 * @param array $vars 变量替换
* @param string $range 语言作用域
* @return mixed * @return mixed
*/ */
public static function get($name = null, $vars = [], $range = '') public static function get($name = null, $vars = [], $range = '')
{ {
$range = $range ?: self::$range; $range = $range ?: self::$range;
// 空参数返回所有定义 // 空参数返回所有定义
if (empty($name)) { if (empty($name)) {
return self::$lang[$range]; return self::$lang[$range];
} }
$key = strtolower($name); $key = strtolower($name);
$value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name; $value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name;
@@ -145,42 +179,50 @@ class Lang
} }
} }
return $value; return $value;
} }
/** /**
* 自动侦测设置获取语言选择 * 自动侦测设置获取语言选择
* @access public
* @return string * @return string
*/ */
public static function detect() public static function detect()
{ {
// 自动侦测设置获取语言选择
$langSet = ''; $langSet = '';
if (isset($_GET[self::$langDetectVar])) { if (isset($_GET[self::$langDetectVar])) {
// url中设置了语言变量 // url 中设置了语言变量
$langSet = strtolower($_GET[self::$langDetectVar]); $langSet = strtolower($_GET[self::$langDetectVar]);
} elseif (isset($_COOKIE[self::$langCookieVar])) {
// Cookie 中设置了语言变量
$langSet = strtolower($_COOKIE[self::$langCookieVar]);
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// 自动侦测浏览器语言 // 自动侦测浏览器语言
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
$langSet = strtolower($matches[1]); $langSet = strtolower($matches[1]);
$acceptLangs = Config::get('header_accept_lang'); $acceptLangs = Config::get('header_accept_lang');
if (isset($acceptLangs[$langSet])) { if (isset($acceptLangs[$langSet])) {
$langSet = $acceptLangs[$langSet]; $langSet = $acceptLangs[$langSet];
} elseif (isset(self::$acceptLanguage[$langSet])) { } elseif (isset(self::$acceptLanguage[$langSet])) {
$langSet = self::$acceptLanguage[$langSet]; $langSet = self::$acceptLanguage[$langSet];
} }
} }
// 合法的语言
if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) { if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
// 合法的语言
self::$range = $langSet ?: self::$range; self::$range = $langSet ?: self::$range;
} }
return self::$range; return self::$range;
} }
/** /**
* 设置语言自动侦测的变量 * 设置语言自动侦测的变量
* @param string $var 变量名称 * @access public
* @param string $var 变量名称
* @return void * @return void
*/ */
public static function setLangDetectVar($var) public static function setLangDetectVar($var)
@@ -189,8 +231,9 @@ class Lang
} }
/** /**
* 设置语言的cookie保存变量 * 设置语言的 cookie 保存变量
* @param string $var 变量名称 * @access public
* @param string $var 变量名称
* @return void * @return void
*/ */
public static function setLangCookieVar($var) public static function setLangCookieVar($var)
@@ -199,8 +242,9 @@ class Lang
} }
/** /**
* 设置语言的cookie的过期时间 * 设置语言的 cookie 的过期时间
* @param string $expire 过期时间 * @access public
* @param string $expire 过期时间
* @return void * @return void
*/ */
public static function setLangCookieExpire($expire) public static function setLangCookieExpire($expire)
@@ -210,7 +254,8 @@ class Lang
/** /**
* 设置允许的语言列表 * 设置允许的语言列表
* @param array $list 语言列表 * @access public
* @param array $list 语言列表
* @return void * @return void
*/ */
public static function setAllowLangList($list) public static function setAllowLangList($list)
+270 -181
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -15,26 +15,57 @@ use think\exception\ClassNotFoundException;
class Loader class Loader
{ {
/**
* @var array 实例数组
*/
protected static $instance = []; protected static $instance = [];
// 类名映射
/**
* @var array 类名映射
*/
protected static $map = []; protected static $map = [];
// 命名空间别名 /**
* @var array 命名空间别名
*/
protected static $namespaceAlias = []; protected static $namespaceAlias = [];
// PSR-4 /**
* @var array PSR-4 命名空间前缀长度映射
*/
private static $prefixLengthsPsr4 = []; private static $prefixLengthsPsr4 = [];
private static $prefixDirsPsr4 = [];
private static $fallbackDirsPsr4 = [];
// PSR-0 /**
private static $prefixesPsr0 = []; * @var array PSR-4 的加载目录
*/
private static $prefixDirsPsr4 = [];
/**
* @var array PSR-4 加载失败的回退目录
*/
private static $fallbackDirsPsr4 = [];
/**
* @var array PSR-0 命名空间前缀映射
*/
private static $prefixesPsr0 = [];
/**
* @var array PSR-0 加载失败的回退目录
*/
private static $fallbackDirsPsr0 = []; private static $fallbackDirsPsr0 = [];
// 自动加载的文件 /**
* @var array 自动加载的文件
*/
private static $autoloadFiles = []; private static $autoloadFiles = [];
// 自动加载 /**
* 自动加载
* @access public
* @param string $class 类名
* @return bool
*/
public static function autoload($class) public static function autoload($class)
{ {
// 检测命名空间别名 // 检测命名空间别名
@@ -49,33 +80,33 @@ class Loader
} }
if ($file = self::findFile($class)) { if ($file = self::findFile($class)) {
// 非 Win 环境不严格区分大小写
// Win环境严格区分大小写 if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) {
if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) { __include_file($file);
return false; return true;
} }
__include_file($file);
return true;
} }
return false;
} }
/** /**
* 查找文件 * 查找文件
* @param $class * @access private
* @return bool * @param string $class 类名
* @return bool|string
*/ */
private static function findFile($class) private static function findFile($class)
{ {
// 类库映射
if (!empty(self::$map[$class])) { if (!empty(self::$map[$class])) {
// 类库映射
return self::$map[$class]; return self::$map[$class];
} }
// 查找 PSR-4 // 查找 PSR-4
$logicalPathPsr4 = strtr($class, '\\', DS) . EXT; $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
$first = $class[0];
$first = $class[0];
if (isset(self::$prefixLengthsPsr4[$first])) { if (isset(self::$prefixLengthsPsr4[$first])) {
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) { if (0 === strpos($class, $prefix)) {
@@ -97,7 +128,7 @@ class Loader
// 查找 PSR-0 // 查找 PSR-0
if (false !== $pos = strrpos($class, '\\')) { if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name // namespace class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
} else { } else {
@@ -124,10 +155,17 @@ class Loader
} }
} }
// 找不到则设置映射为 false 并返回
return self::$map[$class] = false; return self::$map[$class] = false;
} }
// 注册classmap /**
* 注册 classmap
* @access public
* @param string|array $class 类名
* @param string $map 映射
* @return void
*/
public static function addClassMap($class, $map = '') public static function addClassMap($class, $map = '')
{ {
if (is_array($class)) { if (is_array($class)) {
@@ -137,7 +175,13 @@ class Loader
} }
} }
// 注册命名空间 /**
* 注册命名空间
* @access public
* @param string|array $namespace 命名空间
* @param string $path 路径
* @return void
*/
public static function addNamespace($namespace, $path = '') public static function addNamespace($namespace, $path = '')
{ {
if (is_array($namespace)) { if (is_array($namespace)) {
@@ -149,84 +193,77 @@ class Loader
} }
} }
// 添加Ps0空间 /**
* 添加 PSR-0 命名空间
* @access private
* @param array|string $prefix 空间前缀
* @param array $paths 路径
* @param bool $prepend 预先设置的优先级更高
* @return void
*/
private static function addPsr0($prefix, $paths, $prepend = false) private static function addPsr0($prefix, $paths, $prepend = false)
{ {
if (!$prefix) { if (!$prefix) {
if ($prepend) { self::$fallbackDirsPsr0 = $prepend ?
self::$fallbackDirsPsr0 = array_merge( array_merge((array) $paths, self::$fallbackDirsPsr0) :
(array) $paths, array_merge(self::$fallbackDirsPsr0, (array) $paths);
self::$fallbackDirsPsr0
);
} else {
self::$fallbackDirsPsr0 = array_merge(
self::$fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset(self::$prefixesPsr0[$first][$prefix])) {
self::$prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
self::$prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
self::$prefixesPsr0[$first][$prefix]
);
} else { } else {
self::$prefixesPsr0[$first][$prefix] = array_merge( $first = $prefix[0];
self::$prefixesPsr0[$first][$prefix],
(array) $paths if (!isset(self::$prefixesPsr0[$first][$prefix])) {
); self::$prefixesPsr0[$first][$prefix] = (array) $paths;
} else {
self::$prefixesPsr0[$first][$prefix] = $prepend ?
array_merge((array) $paths, self::$prefixesPsr0[$first][$prefix]) :
array_merge(self::$prefixesPsr0[$first][$prefix], (array) $paths);
}
} }
} }
// 添加Psr4空间 /**
* 添加 PSR-4 空间
* @access private
* @param array|string $prefix 空间前缀
* @param string $paths 路径
* @param bool $prepend 预先设置的优先级更高
* @return void
*/
private static function addPsr4($prefix, $paths, $prepend = false) private static function addPsr4($prefix, $paths, $prepend = false)
{ {
if (!$prefix) { if (!$prefix) {
// Register directories for the root namespace. // Register directories for the root namespace.
if ($prepend) { self::$fallbackDirsPsr4 = $prepend ?
self::$fallbackDirsPsr4 = array_merge( array_merge((array) $paths, self::$fallbackDirsPsr4) :
(array) $paths, array_merge(self::$fallbackDirsPsr4, (array) $paths);
self::$fallbackDirsPsr4
);
} else {
self::$fallbackDirsPsr4 = array_merge(
self::$fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) { } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace. // Register directories for a new namespace.
$length = strlen($prefix); $length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) { if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); throw new \InvalidArgumentException(
"A non-empty PSR-4 prefix must end with a namespace separator."
);
} }
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
self::$prefixDirsPsr4[$prefix] = (array) $paths; self::$prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
self::$prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
self::$prefixDirsPsr4[$prefix]
);
} else { } else {
self::$prefixDirsPsr4[$prefix] = $prepend ?
// Prepend directories for an already registered namespace.
array_merge((array) $paths, self::$prefixDirsPsr4[$prefix]) :
// Append directories for an already registered namespace. // Append directories for an already registered namespace.
self::$prefixDirsPsr4[$prefix] = array_merge( array_merge(self::$prefixDirsPsr4[$prefix], (array) $paths);
self::$prefixDirsPsr4[$prefix],
(array) $paths
);
} }
} }
// 注册命名空间别名 /**
* 注册命名空间别名
* @access public
* @param array|string $namespace 命名空间
* @param string $original 源文件
* @return void
*/
public static function addNamespaceAlias($namespace, $original = '') public static function addNamespaceAlias($namespace, $original = '')
{ {
if (is_array($namespace)) { if (is_array($namespace)) {
@@ -236,32 +273,43 @@ class Loader
} }
} }
// 注册自动加载机制 /**
public static function register($autoload = '') * 注册自动加载机制
* @access public
* @param callable $autoload 自动加载处理方法
* @return void
*/
public static function register($autoload = null)
{ {
// 注册系统自动加载 // 注册系统自动加载
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
// 注册命名空间定义 // 注册命名空间定义
self::addNamespace([ self::addNamespace([
'think' => LIB_PATH . 'think' . DS, 'think' => LIB_PATH . 'think' . DS,
'behavior' => LIB_PATH . 'behavior' . DS, 'behavior' => LIB_PATH . 'behavior' . DS,
'traits' => LIB_PATH . 'traits' . DS, 'traits' => LIB_PATH . 'traits' . DS,
]); ]);
// 加载类库映射文件 // 加载类库映射文件
if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {
self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
} }
// Composer自动加载支持 // Composer 自动加载支持
if (is_dir(VENDOR_PATH . 'composer')) { if (is_dir(VENDOR_PATH . 'composer')) {
self::registerComposerLoader(); self::registerComposerLoader();
} }
// 自动加载extend目录 // 自动加载 extend 目录
self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
} }
// 注册composer自动加载 /**
* 注册 composer 自动加载
* @access private
* @return void
*/
private static function registerComposerLoader() private static function registerComposerLoader()
{ {
if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) { if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {
@@ -283,6 +331,7 @@ class Loader
if ($classMap) { if ($classMap) {
self::addClassMap($classMap); self::addClassMap($classMap);
} }
} }
if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {
@@ -297,17 +346,19 @@ class Loader
} }
/** /**
* 导入所需的类库 同javaImport 本函数有缓存功能 * 导入所需的类库 同 JavaImport 本函数有缓存功能
* @param string $class 类库命名空间字符串 * @access public
* @param string $baseUrl 起始路径 * @param string $class 类库命名空间字符串
* @param string $ext 导入的文件扩展名 * @param string $baseUrl 起始路径
* @return boolean * @param string $ext 导入的文件扩展名
* @return bool
*/ */
public static function import($class, $baseUrl = '', $ext = EXT) public static function import($class, $baseUrl = '', $ext = EXT)
{ {
static $_file = []; static $_file = [];
$key = $class . $baseUrl; $key = $class . $baseUrl;
$class = str_replace(['.', '#'], [DS, '.'], $class); $class = str_replace(['.', '#'], [DS, '.'], $class);
if (isset($_file[$key])) { if (isset($_file[$key])) {
return true; return true;
} }
@@ -319,7 +370,7 @@ class Loader
// 注册的命名空间 // 注册的命名空间
$baseUrl = self::$prefixDirsPsr4[$name . '\\']; $baseUrl = self::$prefixDirsPsr4[$name . '\\'];
} elseif ('@' == $name) { } elseif ('@' == $name) {
//加载当前模块应用类库 // 加载当前模块应用类库
$baseUrl = App::$modulePath; $baseUrl = App::$modulePath;
} elseif (is_dir(EXTEND_PATH . $name)) { } elseif (is_dir(EXTEND_PATH . $name)) {
$baseUrl = EXTEND_PATH . $name . DS; $baseUrl = EXTEND_PATH . $name . DS;
@@ -330,11 +381,11 @@ class Loader
} elseif (substr($baseUrl, -1) != DS) { } elseif (substr($baseUrl, -1) != DS) {
$baseUrl .= DS; $baseUrl .= DS;
} }
// 如果类存在 则导入类库文件
// 如果类存在则导入类库文件
if (is_array($baseUrl)) { if (is_array($baseUrl)) {
foreach ($baseUrl as $path) { foreach ($baseUrl as $path) {
$filename = $path . DS . $class . $ext; if (is_file($filename = $path . DS . $class . $ext)) {
if (is_file($filename)) {
break; break;
} }
} }
@@ -342,135 +393,154 @@ class Loader
$filename = $baseUrl . $class . $ext; $filename = $baseUrl . $class . $ext;
} }
if (!empty($filename) && is_file($filename)) { if (!empty($filename) &&
// 开启调试模式Win环境严格区分大小写 is_file($filename) &&
if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) { (!IS_WIN || pathinfo($filename, PATHINFO_FILENAME) == pathinfo(realpath($filename), PATHINFO_FILENAME))
return false; ) {
}
__include_file($filename); __include_file($filename);
$_file[$key] = true; $_file[$key] = true;
return true; return true;
} }
return false; return false;
} }
/** /**
* 实例化(分层)模型 * 实例化(分层)模型
* @param string $name Model名称 * @access public
* @param string $layer 业务层名称 * @param string $name Model名称
* @param bool $appendSuffix 是否添加类名后缀 * @param string $layer 业务层名称
* @param string $common 公共模块名 * @param bool $appendSuffix 是否添加类名后缀
* @return Object * @param string $common 公共模块名
* @return object
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common') public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
{ {
$guid = $name . $layer; $uid = $name . $layer;
if (isset(self::$instance[$guid])) {
return self::$instance[$guid]; if (isset(self::$instance[$uid])) {
} return self::$instance[$uid];
if (false !== strpos($name, '\\')) {
$class = $name;
$module = Request::instance()->module();
} else {
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name, 2);
} else {
$module = Request::instance()->module();
}
$class = self::parseClass($module, $layer, $name, $appendSuffix);
} }
list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
if (class_exists($class)) { if (class_exists($class)) {
$model = new $class(); $model = new $class();
} else { } else {
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
if (class_exists($class)) { if (class_exists($class)) {
$model = new $class(); $model = new $class();
} else { } else {
throw new ClassNotFoundException('class not exists:' . $class, $class); throw new ClassNotFoundException('class not exists:' . $class, $class);
} }
} }
self::$instance[$guid] = $model;
return $model; return self::$instance[$uid] = $model;
} }
/** /**
* 实例化(分层)控制器 格式:[模块名/]控制器名 * 实例化(分层)控制器 格式:[模块名/]控制器名
* @param string $name 资源地址 * @access public
* @param string $layer 控制层名称 * @param string $name 资源地址
* @param bool $appendSuffix 是否添加类名后缀 * @param string $layer 控制层名称
* @param string $empty 空控制器名称 * @param bool $appendSuffix 是否添加类名后缀
* @return Object|false * @param string $empty 空控制器名称
* @return object
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
{ {
if (false !== strpos($name, '\\')) { list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
$class = $name;
$module = Request::instance()->module();
} else {
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name);
} else {
$module = Request::instance()->module();
}
$class = self::parseClass($module, $layer, $name, $appendSuffix);
}
if (class_exists($class)) { if (class_exists($class)) {
return App::invokeClass($class); return App::invokeClass($class);
} elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {
return new $emptyClass(Request::instance());
} }
if ($empty) {
$emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix);
if (class_exists($emptyClass)) {
return new $emptyClass(Request::instance());
}
}
throw new ClassNotFoundException('class not exists:' . $class, $class);
} }
/** /**
* 实例化验证类 格式:[模块名/]验证器名 * 实例化验证类 格式:[模块名/]验证器名
* @param string $name 资源地址 * @access public
* @param string $layer 验证层名称 * @param string $name 资源地址
* @param bool $appendSuffix 是否添加类名后缀 * @param string $layer 验证层名称
* @param string $common 公共模块名 * @param bool $appendSuffix 是否添加类名后缀
* @return Object|false * @param string $common 公共模块名
* @return object|false
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common') public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
{ {
$name = $name ?: Config::get('default_validate'); $name = $name ?: Config::get('default_validate');
if (empty($name)) { if (empty($name)) {
return new Validate; return new Validate;
} }
$guid = $name . $layer;
if (isset(self::$instance[$guid])) { $uid = $name . $layer;
return self::$instance[$guid]; if (isset(self::$instance[$uid])) {
} return self::$instance[$uid];
if (false !== strpos($name, '\\')) {
$class = $name;
$module = Request::instance()->module();
} else {
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name);
} else {
$module = Request::instance()->module();
}
$class = self::parseClass($module, $layer, $name, $appendSuffix);
} }
list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
if (class_exists($class)) { if (class_exists($class)) {
$validate = new $class; $validate = new $class;
} else { } else {
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
if (class_exists($class)) { if (class_exists($class)) {
$validate = new $class; $validate = new $class;
} else { } else {
throw new ClassNotFoundException('class not exists:' . $class, $class); throw new ClassNotFoundException('class not exists:' . $class, $class);
} }
} }
self::$instance[$guid] = $validate;
return $validate; return self::$instance[$uid] = $validate;
}
/**
* 解析模块和类名
* @access protected
* @param string $name 资源地址
* @param string $layer 验证层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return array
*/
protected static function getModuleAndClass($name, $layer, $appendSuffix)
{
if (false !== strpos($name, '\\')) {
$module = Request::instance()->module();
$class = $name;
} else {
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name, 2);
} else {
$module = Request::instance()->module();
}
$class = self::parseClass($module, $layer, $name, $appendSuffix);
}
return [$module, $class];
} }
/** /**
* 数据库初始化 并取得数据库类实例 * 数据库初始化 并取得数据库类实例
* @param mixed $config 数据库配置 * @access public
* @param bool|string $name 连接标识 true 强制重新连接 * @param mixed $config 数据库配置
* @param bool|string $name 连接标识 true 强制重新连接
* @return \think\db\Connection * @return \think\db\Connection
*/ */
public static function db($config = [], $name = false) public static function db($config = [], $name = false)
@@ -480,10 +550,11 @@ class Loader
/** /**
* 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
* @param string $url 调用地址 * @access public
* @param string|array $vars 调用参数 支持字符串和数组 * @param string $url 调用地址
* @param string $layer 调用的控制层名称 * @param string|array $vars 调用参数 支持字符串和数组
* @param bool $appendSuffix 是否添加类名后缀 * @param string $layer 要调用的控制层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return mixed * @return mixed
*/ */
public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
@@ -492,6 +563,7 @@ class Loader
$action = $info['basename']; $action = $info['basename'];
$module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller(); $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
$class = self::controller($module, $layer, $appendSuffix); $class = self::controller($module, $layer, $appendSuffix);
if ($class) { if ($class) {
if (is_scalar($vars)) { if (is_scalar($vars)) {
if (strpos($vars, '=')) { if (strpos($vars, '=')) {
@@ -500,16 +572,20 @@ class Loader
$vars = [$vars]; $vars = [$vars];
} }
} }
return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars); return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
} }
return false;
} }
/** /**
* 字符串命名风格转换 * 字符串命名风格转换
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 * type 0 将 Java 风格转换为 C 的风格 1 将 C 风格转换为 Java 的风格
* @param string $name 字符串 * @access public
* @param integer $type 转换类型 * @param string $name 字符串
* @param bool $ucfirst 首字母是否大写(驼峰规则) * @param integer $type 转换类型
* @param bool $ucfirst 首字母是否大写(驼峰规则)
* @return string * @return string
*/ */
public static function parseName($name, $type = 0, $ucfirst = true) public static function parseName($name, $type = 0, $ucfirst = true)
@@ -518,31 +594,38 @@ class Loader
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
return strtoupper($match[1]); return strtoupper($match[1]);
}, $name); }, $name);
return $ucfirst ? ucfirst($name) : lcfirst($name); return $ucfirst ? ucfirst($name) : lcfirst($name);
} else {
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
} }
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
} }
/** /**
* 解析应用类的类名 * 解析应用类的类名
* @param string $module 模块名 * @access public
* @param string $layer 层名 controller model ... * @param string $module 模块名
* @param string $name 类名 * @param string $layer 层名 controller model ...
* @param bool $appendSuffix * @param string $name 类名
* @param bool $appendSuffix 是否添加类名后缀
* @return string * @return string
*/ */
public static function parseClass($module, $layer, $name, $appendSuffix = false) public static function parseClass($module, $layer, $name, $appendSuffix = false)
{ {
$name = str_replace(['/', '.'], '\\', $name);
$array = explode('\\', $name); $array = explode('\\', str_replace(['/', '.'], '\\', $name));
$class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); $class = self::parseName(array_pop($array), 1);
$class = $class . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');
$path = $array ? implode('\\', $array) . '\\' : ''; $path = $array ? implode('\\', $array) . '\\' : '';
return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
return App::$namespace . '\\' .
($module ? $module . '\\' : '') .
$layer . '\\' . $path . $class;
} }
/** /**
* 初始化类的实例 * 初始化类的实例
* @access public
* @return void * @return void
*/ */
public static function clearInstance() public static function clearInstance()
@@ -551,10 +634,11 @@ class Loader
} }
} }
// 作用范围隔离
/** /**
* 作用范围隔离 * include
* * @param string $file 文件路径
* @param $file
* @return mixed * @return mixed
*/ */
function __include_file($file) function __include_file($file)
@@ -562,6 +646,11 @@ function __include_file($file)
return include $file; return include $file;
} }
/**
* require
* @param string $file 文件路径
* @return mixed
*/
function __require_file($file) function __require_file($file)
{ {
return require $file; return require $file;
+107 -83
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -17,12 +17,12 @@ use think\exception\ClassNotFoundException;
* Class Log * Class Log
* @package think * @package think
* *
* @method void log($msg) static * @method void log($msg) static 记录一般日志
* @method void error($msg) static * @method void error($msg) static 记录错误日志
* @method void info($msg) static * @method void info($msg) static 记录一般信息日志
* @method void sql($msg) static * @method void sql($msg) static 记录 SQL 查询日志
* @method void notice($msg) static * @method void notice($msg) static 记录提示日志
* @method void alert($msg) static * @method void alert($msg) static 记录报警日志
*/ */
class Log class Log
{ {
@@ -34,41 +34,60 @@ class Log
const ALERT = 'alert'; const ALERT = 'alert';
const DEBUG = 'debug'; const DEBUG = 'debug';
// 日志信息 /**
* @var array 日志信息
*/
protected static $log = []; protected static $log = [];
// 配置参数
/**
* @var array 配置参数
*/
protected static $config = []; protected static $config = [];
// 日志类型
/**
* @var array 日志类型
*/
protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug']; protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
// 日志写入驱动
/**
* @var log\driver\File|log\driver\Test|log\driver\Socket 日志写入驱动
*/
protected static $driver; protected static $driver;
// 当前日志授权key /**
* @var string 当前日志授权 key
*/
protected static $key; protected static $key;
/** /**
* 日志初始化 * 日志初始化
* @param array $config * @access public
* @param array $config 配置参数
* @return void
*/ */
public static function init($config = []) public static function init($config = [])
{ {
$type = isset($config['type']) ? $config['type'] : 'File'; $type = isset($config['type']) ? $config['type'] : 'File';
$class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type); $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
self::$config = $config; self::$config = $config;
unset($config['type']); unset($config['type']);
if (class_exists($class)) { if (class_exists($class)) {
self::$driver = new $class($config); self::$driver = new $class($config);
} else { } else {
throw new ClassNotFoundException('class not exists:' . $class, $class); throw new ClassNotFoundException('class not exists:' . $class, $class);
} }
// 记录初始化信息 // 记录初始化信息
App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info'); App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');
} }
/** /**
* 获取日志信息 * 获取日志信息
* @param string $type 信息类型 * @access public
* @return array * @param string $type 信息类型
* @return array|string
*/ */
public static function getLog($type = '') public static function getLog($type = '')
{ {
@@ -77,21 +96,22 @@ class Log
/** /**
* 记录调试信息 * 记录调试信息
* @param mixed $msg 调试信息 * @access public
* @param string $type 信息类型 * @param mixed $msg 调试信息
* @param string $type 信息类型
* @return void * @return void
*/ */
public static function record($msg, $type = 'log') public static function record($msg, $type = 'log')
{ {
self::$log[$type][] = $msg; self::$log[$type][] = $msg;
if (IS_CLI) {
// 命令行下面日志写入改进 // 命令行下面日志写入改进
self::save(); IS_CLI && self::save();
}
} }
/** /**
* 清空日志信息 * 清空日志信息
* @access public
* @return void * @return void
*/ */
public static function clear() public static function clear()
@@ -100,8 +120,9 @@ class Log
} }
/** /**
* 当前日志记录的授权key * 设置当前日志记录的授权 key
* @param string $key 授权key * @access public
* @param string $key 授权 key
* @return void * @return void
*/ */
public static function key($key) public static function key($key)
@@ -111,102 +132,105 @@ class Log
/** /**
* 检查日志写入权限 * 检查日志写入权限
* @param array $config 当前日志配置参数 * @access public
* @param array $config 当前日志配置参数
* @return bool * @return bool
*/ */
public static function check($config) public static function check($config)
{ {
if (self::$key && !empty($config['allow_key']) && !in_array(self::$key, $config['allow_key'])) { return !self::$key || empty($config['allow_key']) || in_array(self::$key, $config['allow_key']);
return false;
}
return true;
} }
/** /**
* 保存调试信息 * 保存调试信息
* @access public
* @return bool * @return bool
*/ */
public static function save() public static function save()
{ {
if (!empty(self::$log)) { // 没有需要保存的记录则直接返回
if (is_null(self::$driver)) { if (empty(self::$log)) {
self::init(Config::get('log')); return true;
}
if (!self::check(self::$config)) {
// 检测日志写入权限
return false;
}
if (empty(self::$config['level'])) {
// 获取全部日志
$log = self::$log;
if (!App::$debug && isset($log['debug'])) {
unset($log['debug']);
}
} else {
// 记录允许级别
$log = [];
foreach (self::$config['level'] as $level) {
if (isset(self::$log[$level])) {
$log[$level] = self::$log[$level];
}
}
}
$result = self::$driver->save($log);
if ($result) {
self::$log = [];
}
Hook::listen('log_write_done', $log);
return $result;
} }
return true;
is_null(self::$driver) && self::init(Config::get('log'));
// 检测日志写入权限
if (!self::check(self::$config)) {
return false;
}
if (empty(self::$config['level'])) {
// 获取全部日志
$log = self::$log;
if (!App::$debug && isset($log['debug'])) {
unset($log['debug']);
}
} else {
// 记录允许级别
$log = [];
foreach (self::$config['level'] as $level) {
if (isset(self::$log[$level])) {
$log[$level] = self::$log[$level];
}
}
}
if ($result = self::$driver->save($log)) {
self::$log = [];
}
Hook::listen('log_write_done', $log);
return $result;
} }
/** /**
* 实时写入日志信息 并支持行为 * 实时写入日志信息 并支持行为
* @param mixed $msg 调试信息 * @access public
* @param string $type 信息类型 * @param mixed $msg 调试信息
* @param bool $force 是否强制写入 * @param string $type 信息类型
* @param bool $force 是否强制写入
* @return bool * @return bool
*/ */
public static function write($msg, $type = 'log', $force = false) public static function write($msg, $type = 'log', $force = false)
{ {
$log = self::$log; $log = self::$log;
// 封装日志信息
if (true === $force || empty(self::$config['level'])) { // 如果不是强制写入,而且信息类型不在可记录的类别中则直接返回 false 不做记录
$log[$type][] = $msg; if (true !== $force && !empty(self::$config['level']) && !in_array($type, self::$config['level'])) {
} elseif (in_array($type, self::$config['level'])) {
$log[$type][] = $msg;
} else {
return false; return false;
} }
// 监听log_write // 封装日志信息
$log[$type][] = $msg;
// 监听 log_write
Hook::listen('log_write', $log); Hook::listen('log_write', $log);
if (is_null(self::$driver)) {
self::init(Config::get('log')); is_null(self::$driver) && self::init(Config::get('log'));
}
// 写入日志 // 写入日志
$result = self::$driver->save($log); if ($result = self::$driver->save($log)) {
if ($result) {
self::$log = []; self::$log = [];
} }
return $result; return $result;
} }
/** /**
* 静态调用 * 静态方法调用
* @param $method * @access public
* @param $args * @param string $method 调用方法
* @return mixed * @param mixed $args 参数
* @return void
*/ */
public static function __callStatic($method, $args) public static function __callStatic($method, $args)
{ {
if (in_array($method, self::$type)) { if (in_array($method, self::$type)) {
array_push($args, $method); array_push($args, $method);
return call_user_func_array('\\think\\Log::record', $args);
call_user_func_array('\\think\\Log::record', $args);
} }
} }
+165 -77
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,6 +11,7 @@
namespace think; namespace think;
use BadMethodCallException;
use InvalidArgumentException; use InvalidArgumentException;
use think\db\Query; use think\db\Query;
use think\exception\ValidateException; use think\exception\ValidateException;
@@ -56,6 +57,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
protected $pk; protected $pk;
// 数据表字段信息 留空则自动获取 // 数据表字段信息 留空则自动获取
protected $field = []; protected $field = [];
// 数据排除字段
protected $except = [];
// 数据废弃字段
protected $disuse = [];
// 只读字段 // 只读字段
protected $readonly = []; protected $readonly = [];
// 显示属性 // 显示属性
@@ -89,6 +94,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
protected $type = []; protected $type = [];
// 是否为更新数据 // 是否为更新数据
protected $isUpdate = false; protected $isUpdate = false;
// 是否强制更新所有数据
protected $force = false;
// 更新条件 // 更新条件
protected $updateWhere; protected $updateWhere;
// 验证失败是否抛出异常 // 验证失败是否抛出异常
@@ -121,6 +128,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
} else { } else {
$this->data = $data; $this->data = $data;
} }
if ($this->disuse) {
// 废弃字段
foreach ((array) $this->disuse as $key) {
if (array_key_exists($key, $this->data)) {
unset($this->data[$key]);
}
}
}
// 记录原始数据 // 记录原始数据
$this->origin = $this->data; $this->origin = $this->data;
@@ -261,7 +278,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
public function setParent($model) public function setParent($model)
{ {
$this->parent = $model; $this->parent = $model;
return $this; return $this;
} }
@@ -336,6 +352,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
return $this; return $this;
} }
/**
* 更新是否强制写入数据 而不做比较
* @access public
* @param bool $force
* @return $this
*/
public function force($force = true)
{
$this->force = $force;
return $this;
}
/** /**
* 修改器 设置数据对象值 * 修改器 设置数据对象值
* @access public * @access public
@@ -353,7 +381,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
// 检测修改器 // 检测修改器
$method = 'set' . Loader::parseName($name, 1) . 'Attr'; $method = 'set' . Loader::parseName($name, 1) . 'Attr';
if (method_exists($this, $method)) { if (method_exists($this, $method)) {
$value = $this->$method($value, array_merge($this->data, $data)); $value = $this->$method($value, array_merge($this->data, $data), $this->relation);
} elseif (isset($this->type[$name])) { } elseif (isset($this->type[$name])) {
// 类型转换 // 类型转换
$value = $this->writeTransform($value, $this->type[$name]); $value = $this->writeTransform($value, $this->type[$name]);
@@ -532,7 +560,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
// 检测属性获取器 // 检测属性获取器
$method = 'get' . Loader::parseName($name, 1) . 'Attr'; $method = 'get' . Loader::parseName($name, 1) . 'Attr';
if (method_exists($this, $method)) { if (method_exists($this, $method)) {
$value = $this->$method($value, $this->data); $value = $this->$method($value, $this->data, $this->relation);
} elseif (isset($this->type[$name])) { } elseif (isset($this->type[$name])) {
// 类型转换 // 类型转换
$value = $this->readTransform($value, $this->type[$name]); $value = $this->readTransform($value, $this->type[$name]);
@@ -567,6 +595,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* @access public * @access public
* @param Relation $modelRelation 模型关联对象 * @param Relation $modelRelation 模型关联对象
* @return mixed * @return mixed
* @throws BadMethodCallException
*/ */
protected function getRelationData(Relation $modelRelation) protected function getRelationData(Relation $modelRelation)
{ {
@@ -574,7 +603,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$value = $this->parent; $value = $this->parent;
} else { } else {
// 首先获取关联数据 // 首先获取关联数据
$value = $modelRelation->getRelation(); if (method_exists($modelRelation, 'getRelation')) {
$value = $modelRelation->getRelation();
} else {
throw new BadMethodCallException('method not exists:' . get_class($modelRelation) . '-> getRelation');
}
} }
return $value; return $value;
} }
@@ -686,7 +719,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
if (isset($this->data[$key])) { if (isset($this->data[$key])) {
throw new Exception('bind attr has exists:' . $key); throw new Exception('bind attr has exists:' . $key);
} else { } else {
$this->data[$key] = $model->$attr; $this->data[$key] = $model->getAttr($attr);
} }
} }
} }
@@ -820,7 +853,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$relation = $this->getAttr($key); $relation = $this->getAttr($key);
$item[$key] = $relation->append([$attr])->toArray(); $item[$key] = $relation->append([$attr])->toArray();
} else { } else {
$item[$name] = $this->getAttr($name); $relation = Loader::parseName($name, 1, false);
if (method_exists($this, $relation)) {
$modelRelation = $this->$relation();
$value = $this->getRelationData($modelRelation);
if (method_exists($modelRelation, 'getBindAttr')) {
$bindAttr = $modelRelation->getBindAttr();
if ($bindAttr) {
foreach ($bindAttr as $key => $attr) {
$key = is_numeric($key) ? $attr : $key;
if (isset($this->data[$key])) {
throw new Exception('bind attr has exists:' . $key);
} else {
$item[$key] = $value ? $value->getAttr($attr) : null;
}
}
continue;
}
}
$item[$name] = $value;
} else {
$item[$name] = $this->getAttr($name);
}
} }
} }
} }
@@ -927,6 +982,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
*/ */
public function save($data = [], $where = [], $sequence = null) public function save($data = [], $where = [], $sequence = null)
{ {
if (is_string($data)) {
$sequence = $data;
$data = [];
}
if (!empty($data)) { if (!empty($data)) {
// 数据自动验证 // 数据自动验证
if (!$this->validateData($data)) { if (!$this->validateData($data)) {
@@ -937,7 +997,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$this->setAttr($key, $value, $data); $this->setAttr($key, $value, $data);
} }
if (!empty($where)) { if (!empty($where)) {
$this->isUpdate = true; $this->isUpdate = true;
$this->updateWhere = $where;
} }
} }
@@ -1009,12 +1070,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
} }
} }
if (is_string($pk) && isset($data[$pk])) { $array = [];
if (!isset($where[$pk])) {
unset($where); foreach ((array) $pk as $key) {
$where[$pk] = $data[$pk]; if (isset($data[$key])) {
$array[$key] = $data[$key];
unset($data[$key]);
} }
unset($data[$pk]); }
if (!empty($array)) {
$where = $array;
} }
// 检测字段 // 检测字段
@@ -1056,16 +1122,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
// 检测字段 // 检测字段
$allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert)); $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));
if (!empty($allowFields)) { if (!empty($allowFields)) {
$result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data); $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data, false, false, $sequence);
} else { } else {
$result = $this->getQuery()->insert($this->data); $result = $this->getQuery()->insert($this->data, false, false, $sequence);
} }
// 获取自动增长主键 // 获取自动增长主键
if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) { if ($result && $insertId = $this->getQuery()->getLastInsID($sequence)) {
$insertId = $this->getQuery()->getLastInsID($sequence); foreach ((array) $pk as $key) {
if ($insertId) { if (!isset($this->data[$key]) || '' == $this->data[$key]) {
$this->data[$pk] = $insertId; $this->data[$key] = $insertId;
}
} }
} }
@@ -1094,19 +1161,26 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
protected function checkAllowField($auto = []) protected function checkAllowField($auto = [])
{ {
if (!empty($this->field)) { if (true === $this->field) {
if (!empty($this->origin)) { $this->field = $this->getQuery()->getTableInfo('', 'fields');
$this->field = array_keys($this->origin); $field = $this->field;
$field = $this->field; } elseif (!empty($this->field)) {
} elseif (true === $this->field) { $field = array_merge($this->field, $auto);
$this->field = $this->getQuery()->getTableInfo('', 'fields'); if ($this->autoWriteTimestamp) {
$field = $this->field; array_push($field, $this->createTime, $this->updateTime);
} else {
$field = array_merge($this->field, $auto);
} }
} elseif (!empty($this->except)) {
$fields = $this->getQuery()->getTableInfo('', 'fields');
$field = array_diff($fields, (array) $this->except);
$this->field = $field;
} else { } else {
$field = []; $field = [];
} }
if ($this->disuse) {
// 废弃字段
$field = array_diff($field, (array) $this->disuse);
}
return $field; return $field;
} }
@@ -1132,12 +1206,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
*/ */
public function getChangedData() public function getChangedData()
{ {
$data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) { if ($this->force) {
if ((empty($b) || empty($b)) && $a !== $b) { $data = $this->data;
return 1; } else {
} $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
return is_object($a) || $a != $b ? 1 : 0; if ((empty($a) || empty($b)) && $a !== $b) {
}); return 1;
}
return is_object($a) || $a != $b ? 1 : 0;
});
}
if (!empty($this->readonly)) { if (!empty($this->readonly)) {
// 只读字段不允许更新 // 只读字段不允许更新
@@ -1162,16 +1240,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
*/ */
public function setInc($field, $step = 1, $lazyTime = 0) public function setInc($field, $step = 1, $lazyTime = 0)
{ {
// 删除条件 // 更新条件
$pk = $this->getPk(); $where = $this->getWhere();
if (is_string($pk) && isset($this->data[$pk])) {
$where = [$pk => $this->data[$pk]];
} elseif (!empty($this->updateWhere)) {
$where = $this->updateWhere;
} else {
$where = null;
}
$result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime); $result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime);
if (true !== $result) { if (true !== $result) {
@@ -1191,6 +1261,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* @throws Exception * @throws Exception
*/ */
public function setDec($field, $step = 1, $lazyTime = 0) public function setDec($field, $step = 1, $lazyTime = 0)
{
// 更新条件
$where = $this->getWhere();
$result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);
if (true !== $result) {
$this->data[$field] -= $step;
}
return $result;
}
/**
* 获取更新条件
* @access protected
* @return mixed
*/
protected function getWhere()
{ {
// 删除条件 // 删除条件
$pk = $this->getPk(); $pk = $this->getPk();
@@ -1202,13 +1289,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
} else { } else {
$where = null; $where = null;
} }
return $where;
$result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);
if (true !== $result) {
$this->data[$field] -= $step;
}
return $result;
} }
/** /**
@@ -1240,14 +1321,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$auto = true; $auto = true;
} }
foreach ($dataSet as $key => $data) { foreach ($dataSet as $key => $data) {
if (!empty($auto) && isset($data[$pk])) { if ($this->isUpdate || (!empty($auto) && isset($data[$pk]))) {
$result[$key] = self::update($data, [], $this->field); $result[$key] = self::update($data, [], $this->field);
} else { } else {
$result[$key] = self::create($data, $this->field); $result[$key] = self::create($data, $this->field);
} }
} }
$db->commit(); $db->commit();
return $result; return $this->toCollection($result);
} catch (\Exception $e) { } catch (\Exception $e) {
$db->rollback(); $db->rollback();
throw $e; throw $e;
@@ -1257,7 +1338,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
/** /**
* 设置允许写入的字段 * 设置允许写入的字段
* @access public * @access public
* @param mixed $field 允许写入的字段 如果为true只允许写入数据表字段 * @param string|array $field 允许写入的字段 如果为true只允许写入数据表字段
* @return $this * @return $this
*/ */
public function allowField($field) public function allowField($field)
@@ -1269,6 +1350,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
return $this; return $this;
} }
/**
* 设置排除写入的字段
* @access public
* @param string|array $field 排除允许写入的字段
* @return $this
*/
public function except($field)
{
if (is_string($field)) {
$field = explode(',', $field);
}
$this->except = $field;
return $this;
}
/** /**
* 设置只读字段 * 设置只读字段
* @access public * @access public
@@ -1336,14 +1432,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
} }
// 删除条件 // 删除条件
$pk = $this->getPk(); $where = $this->getWhere();
if (is_string($pk) && isset($this->data[$pk])) {
$where = [$pk => $this->data[$pk]];
} elseif (!empty($this->updateWhere)) {
$where = $this->updateWhere;
} else {
$where = null;
}
// 删除当前模型数据 // 删除当前模型数据
$result = $this->getQuery()->where($where)->delete(); $result = $this->getQuery()->where($where)->delete();
@@ -1614,14 +1703,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
{ {
$model = new static(); $model = new static();
$query = $model->db(); $query = $model->db();
if (is_array($data) && key($data) !== 0) { if (empty($data) && 0 !== $data) {
return 0;
} elseif (is_array($data) && key($data) !== 0) {
$query->where($data); $query->where($data);
$data = null; $data = null;
} elseif ($data instanceof \Closure) { } elseif ($data instanceof \Closure) {
call_user_func_array($data, [ & $query]); call_user_func_array($data, [ & $query]);
$data = null; $data = null;
} elseif (empty($data) && 0 !== $data) {
return 0;
} }
$resultSet = $query->select($data); $resultSet = $query->select($data);
$count = 0; $count = 0;
@@ -1668,7 +1757,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* 设置是否使用全局查询范围 * 设置是否使用全局查询范围
* @param bool $use 是否启用全局查询范围 * @param bool $use 是否启用全局查询范围
* @access public * @access public
* @return Model * @return Query
*/ */
public static function useGlobalScope($use) public static function useGlobalScope($use)
{ {
@@ -1697,13 +1786,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param string $relation 关联方法名 * @param string $relation 关联方法名
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Relation|Query * @return Relation|Query
*/ */
public static function hasWhere($relation, $where = []) public static function hasWhere($relation, $where = [], $fields = null)
{ {
return (new static())->$relation()->hasWhere($where); return (new static())->$relation()->hasWhere($where, $fields);
} }
/** /**
@@ -1860,7 +1950,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* @access public * @access public
* @param string $model 模型名 * @param string $model 模型名
* @param string $foreignKey 关联外键 * @param string $foreignKey 关联外键
* @param string $localKey 关联主键 * @param string $localKey 当前模型主键
* @param array $alias 别名定义(已经废弃) * @param array $alias 别名定义(已经废弃)
* @param string $joinType JOIN类型 * @param string $joinType JOIN类型
* @return HasOne * @return HasOne
@@ -1900,7 +1990,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* @access public * @access public
* @param string $model 模型名 * @param string $model 模型名
* @param string $foreignKey 关联外键 * @param string $foreignKey 关联外键
* @param string $localKey 关联主键 * @param string $localKey 当前模型主键
* @return HasMany * @return HasMany
*/ */
public function hasMany($model, $foreignKey = '', $localKey = '') public function hasMany($model, $foreignKey = '', $localKey = '')
@@ -1919,7 +2009,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
* @param string $through 中间模型名 * @param string $through 中间模型名
* @param string $foreignKey 关联外键 * @param string $foreignKey 关联外键
* @param string $throughKey 关联外键 * @param string $throughKey 关联外键
* @param string $localKey 关联主键 * @param string $localKey 当前模型主键
* @return HasManyThrough * @return HasManyThrough
*/ */
public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '') public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')
@@ -1969,7 +2059,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$trace = debug_backtrace(false, 2); $trace = debug_backtrace(false, 2);
$morph = Loader::parseName($trace[1]['function']); $morph = Loader::parseName($trace[1]['function']);
} }
$type = $type ?: Loader::parseName($this->name); $type = $type ?: get_class($this);
if (is_array($morph)) { if (is_array($morph)) {
list($morphType, $foreignKey) = $morph; list($morphType, $foreignKey) = $morph;
} else { } else {
@@ -1995,7 +2085,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$trace = debug_backtrace(false, 2); $trace = debug_backtrace(false, 2);
$morph = Loader::parseName($trace[1]['function']); $morph = Loader::parseName($trace[1]['function']);
} }
$type = $type ?: Loader::parseName($this->name); $type = $type ?: get_class($this);
if (is_array($morph)) { if (is_array($morph)) {
list($morphType, $foreignKey) = $morph; list($morphType, $foreignKey) = $morph;
} else { } else {
@@ -2033,7 +2123,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
public function __call($method, $args) public function __call($method, $args)
{ {
$query = $this->db(true, false); $query = $this->db(true, false);
if (method_exists($this, 'scope' . $method)) { if (method_exists($this, 'scope' . $method)) {
// 动态调用命名范围 // 动态调用命名范围
$method = 'scope' . $method; $method = 'scope' . $method;
@@ -2049,7 +2138,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
{ {
$model = new static(); $model = new static();
$query = $model->db(); $query = $model->db();
if (method_exists($model, 'scope' . $method)) { if (method_exists($model, 'scope' . $method)) {
// 动态调用命名范围 // 动态调用命名范围
$method = 'scope' . $method; $method = 'scope' . $method;
+30 -16
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -49,6 +49,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
'fragment' => '', 'fragment' => '',
]; ];
/** @var mixed simple模式下的下个元素 */
protected $nextItem;
public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
{ {
$this->options = array_merge($this->options, $options); $this->options = array_merge($this->options, $options);
@@ -65,7 +68,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
if ($simple) { if ($simple) {
$this->currentPage = $this->setCurrentPage($currentPage); $this->currentPage = $this->setCurrentPage($currentPage);
$this->hasMore = count($items) > ($this->listRows); $this->hasMore = count($items) > ($this->listRows);
$items = $items->slice(0, $this->listRows); if ($this->hasMore) {
$this->nextItem = $items->slice($this->listRows, 1);
}
$items = $items->slice(0, $this->listRows);
} else { } else {
$this->total = $total; $this->total = $total;
$this->lastPage = (int) ceil($total / $listRows); $this->lastPage = (int) ceil($total / $listRows);
@@ -135,9 +141,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
*/ */
public static function getCurrentPage($varPage = 'page', $default = 1) public static function getCurrentPage($varPage = 'page', $default = 1)
{ {
$page = Request::instance()->request($varPage); $page = (int) Request::instance()->param($varPage);
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { if (filter_var($page, FILTER_VALIDATE_INT) !== false && $page >= 1) {
return $page; return $page;
} }
@@ -282,8 +288,11 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
public function each(callable $callback) public function each(callable $callback)
{ {
foreach ($this->items as $key => $item) { foreach ($this->items as $key => $item) {
if ($callback($item, $key) === false) { $result = $callback($item, $key);
if (false === $result) {
break; break;
} elseif (!is_object($item)) {
$this->items[$key] = $result;
} }
} }
@@ -356,19 +365,24 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
public function toArray() public function toArray()
{ {
try { if ($this->simple) {
$total = $this->total(); return [
} catch (\DomainException $e) { 'per_page' => $this->listRows,
$total = null; 'current_page' => $this->currentPage,
'has_more' => $this->hasMore,
'next_item' => $this->nextItem,
'data' => $this->items->toArray(),
];
} else {
return [
'total' => $this->total,
'per_page' => $this->listRows,
'current_page' => $this->currentPage,
'last_page' => $this->lastPage,
'data' => $this->items->toArray(),
];
} }
return [
'total' => $total,
'per_page' => $this->listRows(),
'current_page' => $this->currentPage(),
'last_page' => $this->lastPage,
'data' => $this->items->toArray(),
];
} }
/** /**
+20 -6
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -59,6 +59,11 @@ class Request
*/ */
protected $routeInfo = []; protected $routeInfo = [];
/**
* @var array 环境变量
*/
protected $env;
/** /**
* @var array 当前调度信息 * @var array 当前调度信息
*/ */
@@ -1088,7 +1093,7 @@ class Request
public function filterExp(&$value) public function filterExp(&$value)
{ {
// 过滤查询特殊字符 // 过滤查询特殊字符
if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) { if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {
$value .= ' '; $value .= ' ';
} }
// TODO 其他安全过滤 // TODO 其他安全过滤
@@ -1260,7 +1265,7 @@ class Request
* @param boolean $adv 是否进行高级模式获取(有可能被伪装) * @param boolean $adv 是否进行高级模式获取(有可能被伪装)
* @return mixed * @return mixed
*/ */
public function ip($type = 0, $adv = false) public function ip($type = 0, $adv = true)
{ {
$type = $type ? 1 : 0; $type = $type ? 1 : 0;
static $ip = null; static $ip = null;
@@ -1337,6 +1342,9 @@ class Request
*/ */
public function host() public function host()
{ {
if (isset($_SERVER['HTTP_X_REAL_HOST'])) {
return $_SERVER['HTTP_X_REAL_HOST'];
}
return $this->server('HTTP_HOST'); return $this->server('HTTP_HOST');
} }
@@ -1529,10 +1537,16 @@ class Request
* @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id
* @param mixed $expire 缓存有效期 * @param mixed $expire 缓存有效期
* @param array $except 缓存排除 * @param array $except 缓存排除
* @param string $tag 缓存标签
* @return void * @return void
*/ */
public function cache($key, $expire = null, $except = []) public function cache($key, $expire = null, $except = [], $tag = null)
{ {
if (!is_array($except)) {
$tag = $except;
$except = [];
}
if (false !== $key && $this->isGet() && !$this->isCheckCache) { if (false !== $key && $this->isGet() && !$this->isCheckCache) {
// 标记请求缓存检查 // 标记请求缓存检查
$this->isCheckCache = true; $this->isCheckCache = true;
@@ -1586,7 +1600,7 @@ class Request
$response = Response::create($content)->header($header); $response = Response::create($content)->header($header);
throw new \think\exception\HttpResponseException($response); throw new \think\exception\HttpResponseException($response);
} else { } else {
$this->cache = [$key, $expire]; $this->cache = [$key, $expire, $tag];
} }
} }
} }
@@ -1604,7 +1618,7 @@ class Request
/** /**
* 设置当前请求绑定的对象实例 * 设置当前请求绑定的对象实例
* @access public * @access public
* @param string $name 绑定的对象标识 * @param string|array $name 绑定的对象标识
* @param mixed $obj 绑定的对象实例 * @param mixed $obj 绑定的对象实例
* @return mixed * @return mixed
*/ */
+2 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -106,7 +106,7 @@ class Response
$this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; $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['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'; $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]); Cache::tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]);
} }
} }
+15 -9
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -255,9 +255,11 @@ class Route
$option1 = array_merge($option, $val[1]); $option1 = array_merge($option, $val[1]);
$pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []); $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []);
} else { } else {
$route = $val; $option1 = null;
$pattern1 = null;
$route = $val;
} }
self::setRule($key, $route, $type, isset($option1) ? $option1 : $option, isset($pattern1) ? $pattern1 : $pattern, $group); self::setRule($key, $route, $type, !is_null($option1) ? $option1 : $option, !is_null($pattern1) ? $pattern1 : $pattern, $group);
} }
} else { } else {
self::setRule($rule, $route, $type, $option, $pattern, $group); self::setRule($rule, $route, $type, $option, $pattern, $group);
@@ -333,9 +335,9 @@ class Route
if ('*' == $type) { if ('*' == $type) {
// 注册路由快捷方式 // 注册路由快捷方式
foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) { foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
if (self::$domain) { if (self::$domain && !isset(self::$rules['domain'][self::$domain][$method][$rule])) {
self::$rules['domain'][self::$domain][$method][$rule] = true; self::$rules['domain'][self::$domain][$method][$rule] = true;
} else { } elseif (!self::$domain && !isset(self::$rules[$method][$rule])) {
self::$rules[$method][$rule] = true; self::$rules[$method][$rule] = true;
} }
} }
@@ -428,7 +430,8 @@ class Route
self::$rules['*'][$name]['pattern'] = $pattern; self::$rules['*'][$name]['pattern'] = $pattern;
} }
} else { } else {
$item = []; $item = [];
$completeMatch = Config::get('route_complete_match');
foreach ($routes as $key => $val) { foreach ($routes as $key => $val) {
if (is_numeric($key)) { if (is_numeric($key)) {
$key = array_shift($val); $key = array_shift($val);
@@ -447,6 +450,8 @@ class Route
// 是否完整匹配 // 是否完整匹配
$options['complete_match'] = true; $options['complete_match'] = true;
$key = substr($key, 0, -1); $key = substr($key, 0, -1);
} elseif ($completeMatch) {
$options['complete_match'] = true;
} }
$key = trim($key, '/'); $key = trim($key, '/');
$vars = self::parseVar($key); $vars = self::parseVar($key);
@@ -1507,12 +1512,13 @@ class Route
if ($request->isGet() && isset($option['cache'])) { if ($request->isGet() && isset($option['cache'])) {
$cache = $option['cache']; $cache = $option['cache'];
if (is_array($cache)) { if (is_array($cache)) {
list($key, $expire) = $cache; list($key, $expire, $tag) = array_pad($cache, 3, null);
} else { } else {
$key = str_replace('|', '/', $pathinfo); $key = str_replace('|', '/', $pathinfo);
$expire = $cache; $expire = $cache;
$tag = null;
} }
$request->cache($key, $expire); $request->cache($key, $expire, $tag);
} }
return $result; return $result;
} }
@@ -1543,7 +1549,7 @@ class Route
/** /**
* 解析URL地址中的参数Request对象 * 解析URL地址中的参数Request对象
* @access private * @access private
* @param string $rule 路由规则 * @param string $url 路由规则
* @param array $var 变量 * @param array $var 变量
* @return void * @return void
*/ */
+4 -3
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -25,6 +25,7 @@ class Session
*/ */
public static function prefix($prefix = '') public static function prefix($prefix = '')
{ {
empty(self::$init) && self::boot();
if (empty($prefix) && null !== $prefix) { if (empty($prefix) && null !== $prefix) {
return self::$prefix; return self::$prefix;
} else { } else {
@@ -56,7 +57,7 @@ class Session
$isDoStart = true; $isDoStart = true;
} }
if (isset($config['prefix']) && (self::$prefix === '' || self::$prefix === null)) { if (isset($config['prefix']) && ('' === self::$prefix || null === self::$prefix)) {
self::$prefix = $config['prefix']; self::$prefix = $config['prefix'];
} }
if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) { if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {
@@ -347,7 +348,7 @@ class Session
* @param bool $delete 是否删除关联会话文件 * @param bool $delete 是否删除关联会话文件
* @return void * @return void
*/ */
private static function regenerate($delete = false) public static function regenerate($delete = false)
{ {
session_regenerate_id($delete); session_regenerate_id($delete);
} }
+14 -16
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -12,6 +12,7 @@
namespace think; namespace think;
use think\exception\TemplateNotFoundException; use think\exception\TemplateNotFoundException;
use think\template\TagLib;
/** /**
* ThinkPHP分离出来的模板引擎 * ThinkPHP分离出来的模板引擎
@@ -59,6 +60,7 @@ class Template
/** /**
* 构造函数 * 构造函数
* @access public * @access public
* @param array $config
*/ */
public function __construct(array $config = []) public function __construct(array $config = [])
{ {
@@ -120,7 +122,7 @@ class Template
* 模板引擎配置项 * 模板引擎配置项
* @access public * @access public
* @param array|string $config * @param array|string $config
* @return void|array * @return string|void|array
*/ */
public function config($config) public function config($config)
{ {
@@ -183,7 +185,7 @@ class Template
} }
$template = $this->parseTemplateFile($template); $template = $this->parseTemplateFile($template);
if ($template) { if ($template) {
$cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($template) . '.' . ltrim($this->config['cache_suffix'], '.'); $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
if (!$this->checkCache($cacheFile)) { if (!$this->checkCache($cacheFile)) {
// 缓存无效 重新模板编译 // 缓存无效 重新模板编译
$content = file_get_contents($template); $content = file_get_contents($template);
@@ -234,7 +236,7 @@ class Template
* @access public * @access public
* @param mixed $name 布局模板名称 false 则关闭布局 * @param mixed $name 布局模板名称 false 则关闭布局
* @param string $replace 布局模板内容替换标识 * @param string $replace 布局模板内容替换标识
* @return object * @return Template
*/ */
public function layout($name, $replace = '') public function layout($name, $replace = '')
{ {
@@ -688,6 +690,7 @@ class Template
} else { } else {
$className = '\\think\\template\\taglib\\' . ucwords($tagLib); $className = '\\think\\template\\taglib\\' . ucwords($tagLib);
} }
/** @var Taglib $tLib */
$tLib = new $className($this); $tLib = new $className($this);
$tLib->parseTag($content, $hide ? '' : $tagLib); $tLib->parseTag($content, $hide ? '' : $tagLib);
return; return;
@@ -763,31 +766,26 @@ class Template
} else { } else {
if (isset($array[1])) { if (isset($array[1])) {
$this->parseVar($array[2]); $this->parseVar($array[2]);
$_name = ' && ' . $name . $array[1] . $array[2]; $express = $name . $array[1] . $array[2];
} else { } else {
$_name = ''; $express = false;
} }
// $name为数组 // $name为数组
switch ($first) { switch ($first) {
case '?': case '?':
// {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx
$str = '<?php echo isset(' . $name . ')' . $_name . ' ? ' . $name . ' : ' . substr($str, 1) . '; ?>'; $str = '<?php echo ' . ($express ?: 'isset(' . $name . ')') . '?' . $name . ':' . substr($str, 1) . '; ?>';
break; break;
case '=': case '=':
// {$varname?='xxx'} $varname为真时才输出xxx // {$varname?='xxx'} $varname为真时才输出xxx
$str = '<?php if(!empty(' . $name . ')' . $_name . ') echo ' . substr($str, 1) . '; ?>'; $str = '<?php if(' . ($express ?: '!empty(' . $name . ')') . ') echo ' . substr($str, 1) . '; ?>';
break; break;
case ':': case ':':
// {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx
$str = '<?php echo !empty(' . $name . ')' . $_name . '?' . $name . $str . '; ?>'; $str = '<?php echo ' . ($express ?: '!empty(' . $name . ')') . '?' . $name . $str . '; ?>';
break; break;
default: default:
if (strpos($str, ':')) { $str = '<?php echo ' . ($express ?: '!empty(' . $name . ')') . '?' . $str . '; ?>';
// {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b
$str = '<?php echo !empty(' . $name . ')' . $_name . '?' . $str . '; ?>';
} else {
$str = '<?php echo ' . $_name . '?' . $str . '; ?>';
}
} }
} }
} else { } else {
@@ -1075,7 +1073,7 @@ class Template
} else { } else {
$path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path']; $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path'];
} }
$template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.'); $template = realpath($path . $template . '.' . ltrim($this->config['view_suffix'], '.'));
} }
if (is_file($template)) { if (is_file($template)) {
+6 -5
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -118,7 +118,7 @@ class Url
$type = Route::getBind('type'); $type = Route::getBind('type');
if ($type) { if ($type) {
$bind = Route::getBind($type); $bind = Route::getBind($type);
if (0 === strpos($url, $bind)) { if ($bind && 0 === strpos($url, $bind)) {
$url = substr($url, strlen($bind) + 1); $url = substr($url, strlen($bind) + 1);
} }
} }
@@ -135,7 +135,7 @@ class Url
if (!empty($vars)) { if (!empty($vars)) {
// 添加参数 // 添加参数
if (Config::get('url_common_param')) { if (Config::get('url_common_param')) {
$vars = urldecode(http_build_query($vars)); $vars = http_build_query($vars);
$url .= $suffix . '?' . $vars . $anchor; $url .= $suffix . '?' . $vars . $anchor;
} else { } else {
$paramType = Config::get('url_param_type'); $paramType = Config::get('url_param_type');
@@ -272,7 +272,7 @@ class Url
$domain .= '.' . $rootDomain; $domain .= '.' . $rootDomain;
} }
} }
if (false !== strpos($domain, ':')) { if (false !== strpos($domain, '://')) {
$scheme = ''; $scheme = '';
} else { } else {
$scheme = $request->isSsl() || Config::get('is_https') ? 'https://' : 'http://'; $scheme = $request->isSsl() || Config::get('is_https') ? 'https://' : 'http://';
@@ -300,9 +300,10 @@ class Url
if (empty($pattern)) { if (empty($pattern)) {
return [$url, $domain, $suffix]; return [$url, $domain, $suffix];
} }
$type = Config::get('url_common_param');
foreach ($pattern as $key => $val) { foreach ($pattern as $key => $val) {
if (isset($vars[$key])) { if (isset($vars[$key])) {
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url); $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url);
unset($vars[$key]); unset($vars[$key]);
$result = [$url, $domain, $suffix]; $result = [$url, $domain, $suffix];
} elseif (2 == $val) { } elseif (2 == $val) {
+152 -101
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -36,54 +36,55 @@ class Validate
// 验证规则默认提示信息 // 验证规则默认提示信息
protected static $typeMsg = [ protected static $typeMsg = [
'require' => ':attribute不能为空', 'require' => ':attribute require',
'number' => ':attribute必须是数字', 'number' => ':attribute must be numeric',
'float' => ':attribute必须是浮点数', 'integer' => ':attribute must be integer',
'boolean' => ':attribute必须是布尔值', 'float' => ':attribute must be float',
'email' => ':attribute格式不符', 'boolean' => ':attribute must be bool',
'array' => ':attribute必须是数组', 'email' => ':attribute not a valid email address',
'accepted' => ':attribute必须是yes、on或者1', 'mobile' => ':attribute not a valid mobile',
'date' => ':attribute格式不符合', 'array' => ':attribute must be a array',
'file' => ':attribute不是有效的上传文件', 'accepted' => ':attribute must be yes,on or 1',
'image' => ':attribute不是有效的图像文件', 'date' => ':attribute not a valid datetime',
'alpha' => ':attribute只能是字母', 'file' => ':attribute not a valid file',
'alphaNum' => ':attribute只能是字母和数字', 'image' => ':attribute not a valid image',
'alphaDash' => ':attribute只能是字母、数字和下划线_及破折号-', 'alpha' => ':attribute must be alpha',
'activeUrl' => ':attribute不是有效的域名或者IP', 'alphaNum' => ':attribute must be alpha-numeric',
'chs' => ':attribute只能是汉字', 'alphaDash' => ':attribute must be alpha-numeric, dash, underscore',
'chsAlpha' => ':attribute只能是汉字、字母', 'activeUrl' => ':attribute not a valid domain or ip',
'chsAlphaNum' => ':attribute只能是汉字、字母和数字', 'chs' => ':attribute must be chinese',
'chsDash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-', 'chsAlpha' => ':attribute must be chinese or alpha',
'url' => ':attribute不是有效的URL地址', 'chsAlphaNum' => ':attribute must be chinese,alpha-numeric',
'ip' => ':attribute不是有效的IP地址', 'chsDash' => ':attribute must be chinese,alpha-numeric,underscore, dash',
'dateFormat' => ':attribute必须使用日期格式 :rule', 'url' => ':attribute not a valid url',
'in' => ':attribute必须在 :rule 范围内', 'ip' => ':attribute not a valid ip',
'notIn' => ':attribute不能在 :rule 范围内', 'dateFormat' => ':attribute must be dateFormat of :rule',
'between' => ':attribute只能在 :1 - :2 之间', 'in' => ':attribute must be in :rule',
'notBetween' => ':attribute不能在 :1 - :2 之间', 'notIn' => ':attribute be notin :rule',
'length' => ':attribute长度不符合要求 :rule', 'between' => ':attribute must between :1 - :2',
'max' => ':attribute长度不能超过 :rule', 'notBetween' => ':attribute not between :1 - :2',
'min' => ':attribute长度不能小于 :rule', 'length' => 'size of :attribute must be :rule',
'after' => ':attribute日期不能小于 :rule', 'max' => 'max size of :attribute must be :rule',
'before' => ':attribute日期不能超过 :rule', 'min' => 'min size of :attribute must be :rule',
'expire' => '不在有效期内 :rule', 'after' => ':attribute cannot be less than :rule',
'allowIp' => '不允许的IP访问', 'before' => ':attribute cannot exceed :rule',
'denyIp' => '禁止的IP访问', 'expire' => ':attribute not within :rule',
'confirm' => ':attribute和确认字段:2不一致', 'allowIp' => 'access IP is not allowed',
'different' => ':attribute和比较字段:2不能相同', 'denyIp' => 'access IP denied',
'egt' => ':attribute必须大于等于 :rule', 'confirm' => ':attribute out of accord with :2',
'gt' => ':attribute必须大于 :rule', 'different' => ':attribute cannot be same with :2',
'elt' => ':attribute必须小于等于 :rule', 'egt' => ':attribute must greater than or equal :rule',
'lt' => ':attribute必须小于 :rule', 'gt' => ':attribute must greater than :rule',
'eq' => ':attribute必须等于 :rule', 'elt' => ':attribute must less than or equal :rule',
'unique' => ':attribute已存在', 'lt' => ':attribute must less than :rule',
'regex' => ':attribute不符合指定规则', 'eq' => ':attribute must equal :rule',
'method' => '无效的请求类型', 'unique' => ':attribute has exists',
'token' => '令牌数据无效', 'regex' => ':attribute not conform to the rules',
'fileSize' => '上传文件大小不符', 'method' => 'invalid Request method',
'fileExt' => '上传文件后缀不符', 'token' => 'invalid token',
'fileMime' => '上传文件类型不符', 'fileSize' => 'filesize not match',
'fileExt' => 'extensions to upload is not allowed',
'fileMime' => 'mimetype to upload is not allowed',
]; ];
// 当前验证场景 // 当前验证场景
@@ -339,6 +340,41 @@ class Validate
return !empty($this->error) ? false : true; return !empty($this->error) ? false : true;
} }
/**
* 根据验证规则验证数据
* @access protected
* @param mixed $value 字段值
* @param mixed $rules 验证规则
* @return bool
*/
protected function checkRule($value, $rules)
{
if ($rules instanceof \Closure) {
return call_user_func_array($rules, [$value]);
} elseif (is_string($rules)) {
$rules = explode('|', $rules);
}
foreach ($rules as $key => $rule) {
if ($rule instanceof \Closure) {
$result = call_user_func_array($rule, [$value]);
} else {
// 判断验证类型
list($type, $rule) = $this->getValidateType($key, $rule);
$callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type];
$result = call_user_func_array($callback, [$value, $rule]);
}
if (true !== $result) {
return $result;
}
}
return true;
}
/** /**
* 验证单个字段规则 * 验证单个字段规则
* @access protected * @access protected
@@ -363,25 +399,7 @@ class Validate
$info = is_numeric($key) ? '' : $key; $info = is_numeric($key) ? '' : $key;
} else { } else {
// 判断验证类型 // 判断验证类型
if (is_numeric($key)) { list($type, $rule, $info) = $this->getValidateType($key, $rule);
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;
}
} else {
$info = $type = $key;
}
// 如果不是require 有数据才会行验证 // 如果不是require 有数据才会行验证
if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
@@ -417,6 +435,39 @@ class Validate
return $result; return $result;
} }
/**
* 获取当前验证类型及规则
* @access public
* @param mixed $key
* @param mixed $rule
* @return array
*/
protected function getValidateType($key, $rule)
{
// 判断验证类型
if (!is_numeric($key)) {
return [$key, $rule, $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;
}
return [$type, $rule, $info];
}
/** /**
* 验证是否和某个字段的值一致 * 验证是否和某个字段的值一致
* @access protected * @access protected
@@ -632,8 +683,12 @@ class Validate
if (function_exists('exif_imagetype')) { if (function_exists('exif_imagetype')) {
return exif_imagetype($image); return exif_imagetype($image);
} else { } else {
$info = getimagesize($image); try {
return $info[2]; $info = getimagesize($image);
return $info ? $info[2] : false;
} catch (\Exception $e) {
return false;
}
} }
} }
@@ -676,21 +731,17 @@ class Validate
*/ */
protected function fileExt($file, $rule) protected function fileExt($file, $rule)
{ {
if (!($file instanceof File)) {
return false;
}
if (is_string($rule)) {
$rule = explode(',', $rule);
}
if (is_array($file)) { if (is_array($file)) {
foreach ($file as $item) { foreach ($file as $item) {
if (!$item->checkExt($rule)) { if (!($item instanceof File) || !$item->checkExt($rule)) {
return false; return false;
} }
} }
return true; return true;
} else { } elseif ($file instanceof File) {
return $file->checkExt($rule); return $file->checkExt($rule);
} else {
return false;
} }
} }
@@ -703,21 +754,17 @@ class Validate
*/ */
protected function fileMime($file, $rule) protected function fileMime($file, $rule)
{ {
if (!($file instanceof File)) {
return false;
}
if (is_string($rule)) {
$rule = explode(',', $rule);
}
if (is_array($file)) { if (is_array($file)) {
foreach ($file as $item) { foreach ($file as $item) {
if (!$item->checkMime($rule)) { if (!($item instanceof File) || !$item->checkMime($rule)) {
return false; return false;
} }
} }
return true; return true;
} else { } elseif ($file instanceof File) {
return $file->checkMime($rule); return $file->checkMime($rule);
} else {
return false;
} }
} }
@@ -730,18 +777,17 @@ class Validate
*/ */
protected function fileSize($file, $rule) protected function fileSize($file, $rule)
{ {
if (!($file instanceof File)) {
return false;
}
if (is_array($file)) { if (is_array($file)) {
foreach ($file as $item) { foreach ($file as $item) {
if (!$item->checkSize($rule)) { if (!($item instanceof File) || !$item->checkSize($rule)) {
return false; return false;
} }
} }
return true; return true;
} else { } elseif ($file instanceof File) {
return $file->checkSize($rule); return $file->checkSize($rule);
} else {
return false;
} }
} }
@@ -841,13 +887,14 @@ class Validate
$map[$key] = $data[$field]; $map[$key] = $data[$field];
} }
$pk = strval(isset($rule[3]) ? $rule[3] : $db->getPk()); $pk = isset($rule[3]) ? $rule[3] : $db->getPk();
if (isset($rule[2])) { if (is_string($pk)) {
$map[$pk] = ['neq', $rule[2]]; if (isset($rule[2])) {
} elseif (isset($data[$pk])) { $map[$pk] = ['neq', $rule[2]];
$map[$pk] = ['neq', $data[$pk]]; } elseif (isset($data[$pk])) {
$map[$pk] = ['neq', $data[$pk]];
}
} }
if ($db->where($map)->field($pk)->find()) { if ($db->where($map)->field($pk)->find()) {
return false; return false;
} }
@@ -899,7 +946,7 @@ class Validate
{ {
list($field, $val) = explode(',', $rule); list($field, $val) = explode(',', $rule);
if ($this->getDataValue($data, $field) == $val) { if ($this->getDataValue($data, $field) == $val) {
return !empty($value); return !empty($value) || '0' == $value;
} else { } else {
return true; return true;
} }
@@ -917,7 +964,7 @@ class Validate
{ {
$result = call_user_func_array($rule, [$value, $data]); $result = call_user_func_array($rule, [$value, $data]);
if ($result) { if ($result) {
return !empty($value); return !empty($value) || '0' == $value;
} else { } else {
return true; return true;
} }
@@ -935,7 +982,7 @@ class Validate
{ {
$val = $this->getDataValue($data, $rule); $val = $this->getDataValue($data, $rule);
if (!empty($val)) { if (!empty($val)) {
return !empty($value); return !empty($value) || '0' == $value;
} else { } else {
return true; return true;
} }
@@ -1225,12 +1272,16 @@ class Validate
$msg = $this->message[$attribute]; $msg = $this->message[$attribute];
} elseif (isset(self::$typeMsg[$type])) { } elseif (isset(self::$typeMsg[$type])) {
$msg = self::$typeMsg[$type]; $msg = self::$typeMsg[$type];
} elseif (0 === strpos($type, 'require')) {
$msg = self::$typeMsg['require'];
} else { } else {
$msg = $title . '规则错误'; $msg = $title . Lang::get('not conform to the rules');
} }
if (is_string($msg) && 0 === strpos($msg, '{%')) { if (is_string($msg) && 0 === strpos($msg, '{%')) {
$msg = Lang::get(substr($msg, 2, -1)); $msg = Lang::get(substr($msg, 2, -1));
} elseif (Lang::has($msg)) {
$msg = Lang::get($msg);
} }
if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) { if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) {
+13 -10
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -33,7 +33,7 @@ class View
public function __construct($engine = [], $replace = []) public function __construct($engine = [], $replace = [])
{ {
// 初始化模板引擎 // 初始化模板引擎
$this->engine((array) $engine); $this->engine($engine);
// 基础替换字符串 // 基础替换字符串
$request = Request::instance(); $request = Request::instance();
$base = $request->root(); $base = $request->root();
@@ -127,7 +127,7 @@ class View
* @access private * @access private
* @param string|array $name 参数名 * @param string|array $name 参数名
* @param mixed $value 参数值 * @param mixed $value 参数值
* @return void * @return $this
*/ */
public function config($name, $value = null) public function config($name, $value = null)
{ {
@@ -155,18 +155,21 @@ class View
ob_implicit_flush(0); ob_implicit_flush(0);
// 渲染输出 // 渲染输出
$method = $renderContent ? 'display' : 'fetch'; try {
$this->engine->$method($template, $vars, $config); $method = $renderContent ? 'display' : 'fetch';
// 允许用户自定义模板的字符串替换
$replace = array_merge($this->replace, $replace, (array) $this->engine->config('tpl_replace_string'));
$this->engine->config('tpl_replace_string', $replace);
$this->engine->$method($template, $vars, $config);
} catch (\Exception $e) {
ob_end_clean();
throw $e;
}
// 获取并清空缓存 // 获取并清空缓存
$content = ob_get_clean(); $content = ob_get_clean();
// 内容过滤标签 // 内容过滤标签
Hook::listen('view_filter', $content); Hook::listen('view_filter', $content);
// 允许用户自定义模板的字符串替换
$replace = array_merge($this->replace, $replace);
if (!empty($replace)) {
$content = strtr($content, $replace);
}
return $content; return $content;
} }
+29 -8
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -120,10 +120,29 @@ abstract class Driver
public function remember($name, $value, $expire = null) public function remember($name, $value, $expire = null)
{ {
if (!$this->has($name)) { if (!$this->has($name)) {
if ($value instanceof \Closure) { $time = time();
$value = call_user_func($value); while ($time + 5 > time() && $this->has($name . '_lock')) {
// 存在锁定则等待
usleep(200000);
}
try {
// 锁定
$this->set($name . '_lock', true);
if ($value instanceof \Closure) {
$value = call_user_func($value);
}
$this->set($name, $value, $expire);
// 解锁
$this->rm($name . '_lock');
} catch (\Exception $e) {
// 解锁
$this->rm($name . '_lock');
throw $e;
} catch (\throwable $e) {
$this->rm($name . '_lock');
throw $e;
} }
$this->set($name, $value, $expire);
} else { } else {
$value = $this->get($name); $value = $this->get($name);
} }
@@ -140,7 +159,9 @@ abstract class Driver
*/ */
public function tag($name, $keys = null, $overlay = false) public function tag($name, $keys = null, $overlay = false)
{ {
if (is_null($keys)) { if (is_null($name)) {
} elseif (is_null($keys)) {
$this->tag = $name; $this->tag = $name;
} else { } else {
$key = 'tag_' . md5($name); $key = 'tag_' . md5($name);
@@ -153,7 +174,7 @@ abstract class Driver
} else { } else {
$value = array_unique(array_merge($this->getTagItem($name), $keys)); $value = array_unique(array_merge($this->getTagItem($name), $keys));
} }
$this->set($key, implode(',', $value)); $this->set($key, implode(',', $value), 0);
} }
return $this; return $this;
} }
@@ -176,7 +197,7 @@ abstract class Driver
} else { } else {
$value = $name; $value = $name;
} }
$this->set($key, $value); $this->set($key, $value, 0);
} }
} }
@@ -191,7 +212,7 @@ abstract class Driver
$key = 'tag_' . md5($tag); $key = 'tag_' . md5($tag);
$value = $this->get($key); $value = $this->get($key);
if ($value) { if ($value) {
return explode(',', $value); return array_filter(explode(',', $value));
} else { } else {
return []; return [];
} }
+17 -12
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -109,12 +109,10 @@ class File extends Driver
$content = file_get_contents($filename); $content = file_get_contents($filename);
if (false !== $content) { if (false !== $content) {
$expire = (int) substr($content, 8, 12); $expire = (int) substr($content, 8, 12);
if (0 != $expire && $_SERVER['REQUEST_TIME'] > filemtime($filename) + $expire) { if (0 != $expire && time() > filemtime($filename) + $expire) {
//缓存过期删除缓存文件
$this->unlink($filename);
return $default; return $default;
} }
$content = substr($content, 20, -3); $content = substr($content, 32);
if ($this->options['data_compress'] && function_exists('gzcompress')) { if ($this->options['data_compress'] && function_exists('gzcompress')) {
//启用数据压缩 //启用数据压缩
$content = gzuncompress($content); $content = gzuncompress($content);
@@ -129,9 +127,9 @@ class File extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久 * @param integer|\DateTime $expire 有效时间(秒)
* @return boolean * @return boolean
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -139,6 +137,9 @@ class File extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
$filename = $this->getCacheKey($name); $filename = $this->getCacheKey($name);
if ($this->tag && !is_file($filename)) { if ($this->tag && !is_file($filename)) {
$first = true; $first = true;
@@ -148,7 +149,7 @@ class File extends Driver
//数据压缩 //数据压缩
$data = gzcompress($data, 3); $data = gzcompress($data, 3);
} }
$data = "<?php\n//" . sprintf('%012d', $expire) . $data . "\n?>"; $data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
$result = file_put_contents($filename, $data); $result = file_put_contents($filename, $data);
if ($result) { if ($result) {
isset($first) && $this->setTagItem($filename); isset($first) && $this->setTagItem($filename);
@@ -188,7 +189,7 @@ class File extends Driver
if ($this->has($name)) { if ($this->has($name)) {
$value = $this->get($name) - $step; $value = $this->get($name) - $step;
} else { } else {
$value = $step; $value = -$step;
} }
return $this->set($name, $value, 0) ? $value : false; return $this->set($name, $value, 0) ? $value : false;
} }
@@ -201,7 +202,8 @@ class File extends Driver
*/ */
public function rm($name) public function rm($name)
{ {
return $this->unlink($this->getCacheKey($name)); $filename = $this->getCacheKey($name);
return $this->unlink($filename);
} }
/** /**
@@ -224,7 +226,10 @@ class File extends Driver
$files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*'); $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*');
foreach ($files as $path) { foreach ($files as $path) {
if (is_dir($path)) { if (is_dir($path)) {
array_map('unlink', glob($path . '/*.php')); $matches = glob($path . '/*.php');
if (is_array($matches)) {
array_map('unlink', $matches);
}
rmdir($path); rmdir($path);
} else { } else {
unlink($path); unlink($path);
+12 -10
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -77,7 +77,7 @@ class Lite extends Driver
if (is_file($filename)) { if (is_file($filename)) {
// 判断是否过期 // 判断是否过期
$mtime = filemtime($filename); $mtime = filemtime($filename);
if ($mtime < $_SERVER['REQUEST_TIME']) { if ($mtime < time()) {
// 清除已经过期的文件 // 清除已经过期的文件
unlink($filename); unlink($filename);
return $default; return $default;
@@ -91,9 +91,9 @@ class Lite extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久 * @param integer|\DateTime $expire 有效时间(秒)
* @return bool * @return bool
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -101,9 +101,11 @@ class Lite extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
// 模拟永久 if ($expire instanceof \DateTime) {
if (0 === $expire) { $expire = $expire->getTimestamp();
$expire = 10 * 365 * 24 * 3600; } else {
$expire = 0 === $expire ? 10 * 365 * 24 * 3600 : $expire;
$expire = time() + $expire;
} }
$filename = $this->getCacheKey($name); $filename = $this->getCacheKey($name);
if ($this->tag && !is_file($filename)) { if ($this->tag && !is_file($filename)) {
@@ -113,7 +115,7 @@ class Lite extends Driver
// 通过设置修改时间实现有效期 // 通过设置修改时间实现有效期
if ($ret) { if ($ret) {
isset($first) && $this->setTagItem($filename); isset($first) && $this->setTagItem($filename);
touch($filename, $_SERVER['REQUEST_TIME'] + $expire); touch($filename, $expire);
} }
return $ret; return $ret;
} }
@@ -147,7 +149,7 @@ class Lite extends Driver
if ($this->has($name)) { if ($this->has($name)) {
$value = $this->get($name) - $step; $value = $this->get($name) - $step;
} else { } else {
$value = $step; $value = -$step;
} }
return $this->set($name, $value, 0) ? $value : false; return $this->set($name, $value, 0) ? $value : false;
} }
+7 -4
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -82,9 +82,9 @@ class Memcache extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return bool * @return bool
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -92,6 +92,9 @@ class Memcache extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
if ($this->tag && !$this->has($name)) { if ($this->tag && !$this->has($name)) {
$first = true; $first = true;
} }
+7 -4
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -93,9 +93,9 @@ class Memcached extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return bool * @return bool
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -103,6 +103,9 @@ class Memcached extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
if ($this->tag && !$this->has($name)) { if ($this->tag && !$this->has($name)) {
$first = true; $first = true;
} }
+30 -18
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -46,9 +46,12 @@ class Redis extends Driver
if (!empty($options)) { if (!empty($options)) {
$this->options = array_merge($this->options, $options); $this->options = array_merge($this->options, $options);
} }
$func = $this->options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new \Redis; $this->handler = new \Redis;
$this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']); if ($this->options['persistent']) {
$this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
} else {
$this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']);
}
if ('' != $this->options['password']) { if ('' != $this->options['password']) {
$this->handler->auth($this->options['password']); $this->handler->auth($this->options['password']);
@@ -80,20 +83,25 @@ class Redis extends Driver
public function get($name, $default = false) public function get($name, $default = false)
{ {
$value = $this->handler->get($this->getCacheKey($name)); $value = $this->handler->get($this->getCacheKey($name));
if (is_null($value)) { if (is_null($value) || false === $value) {
return $default; return $default;
} }
$jsonData = json_decode($value, true);
// 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson<xiaobo.sun@qq.com> try {
return (null === $jsonData) ? $value : $jsonData; $result = 0 === strpos($value, 'think_serialize:') ? unserialize(substr($value, 16)) : $value;
} catch (\Exception $e) {
$result = $default;
}
return $result;
} }
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return boolean * @return boolean
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -101,13 +109,15 @@ class Redis extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
if ($this->tag && !$this->has($name)) { if ($this->tag && !$this->has($name)) {
$first = true; $first = true;
} }
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
//对数组/对象数据进行缓存处理,保证数据完整性 byron sampson<xiaobo.sun@qq.com> $value = is_scalar($value) ? $value : 'think_serialize:' . serialize($value);
$value = (is_object($value) || is_array($value)) ? json_encode($value) : $value; if ($expire) {
if (is_int($expire) && $expire) {
$result = $this->handler->setex($key, $expire, $value); $result = $this->handler->setex($key, $expire, $value);
} else { } else {
$result = $this->handler->set($key, $value); $result = $this->handler->set($key, $value);
@@ -119,26 +129,28 @@ class Redis extends Driver
/** /**
* 自增缓存(针对数值缓存) * 自增缓存(针对数值缓存)
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param int $step 步长 * @param int $step 步长
* @return false|int * @return false|int
*/ */
public function inc($name, $step = 1) public function inc($name, $step = 1)
{ {
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
return $this->handler->incrby($key, $step); return $this->handler->incrby($key, $step);
} }
/** /**
* 自减缓存(针对数值缓存) * 自减缓存(针对数值缓存)
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param int $step 步长 * @param int $step 步长
* @return false|int * @return false|int
*/ */
public function dec($name, $step = 1) public function dec($name, $step = 1)
{ {
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
return $this->handler->decrby($key, $step); return $this->handler->decrby($key, $step);
} }
+10 -6
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -96,9 +96,9 @@ class Sqlite extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return boolean * @return boolean
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -108,7 +108,11 @@ class Sqlite extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
$expire = (0 == $expire) ? 0 : ($_SERVER['REQUEST_TIME'] + $expire); //缓存有效期为0表示永久缓存 if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp();
} else {
$expire = (0 == $expire) ? 0 : (time() + $expire); //缓存有效期为0表示永久缓存
}
if (function_exists('gzcompress')) { if (function_exists('gzcompress')) {
//数据压缩 //数据压缩
$value = gzcompress($value, 3); $value = gzcompress($value, 3);
@@ -155,7 +159,7 @@ class Sqlite extends Driver
if ($this->has($name)) { if ($this->has($name)) {
$value = $this->get($name) - $step; $value = $this->get($name) - $step;
} else { } else {
$value = $step; $value = -$step;
} }
return $this->set($name, $value, 0) ? $value : false; return $this->set($name, $value, 0) ? $value : false;
} }
+7 -4
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -68,9 +68,9 @@ class Wincache extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return boolean * @return boolean
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -78,6 +78,9 @@ class Wincache extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
if ($this->tag && !$this->has($name)) { if ($this->tag && !$this->has($name)) {
$first = true; $first = true;
+7 -4
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -68,9 +68,9 @@ class Xcache extends Driver
/** /**
* 写入缓存 * 写入缓存
* @access public * @access public
* @param string $name 缓存变量名 * @param string $name 缓存变量名
* @param mixed $value 存储数据 * @param mixed $value 存储数据
* @param integer $expire 有效时间(秒) * @param integer|\DateTime $expire 有效时间(秒)
* @return boolean * @return boolean
*/ */
public function set($name, $value, $expire = null) public function set($name, $value, $expire = null)
@@ -78,6 +78,9 @@ class Xcache extends Driver
if (is_null($expire)) { if (is_null($expire)) {
$expire = $this->options['expire']; $expire = $this->options['expire'];
} }
if ($expire instanceof \DateTime) {
$expire = $expire->getTimestamp() - time();
}
if ($this->tag && !$this->has($name)) { if ($this->tag && !$this->has($name)) {
$first = true; $first = true;
} }
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -27,6 +27,11 @@ class Route extends Command
protected function execute(Input $input, Output $output) protected function execute(Input $input, Output $output)
{ {
if (!is_dir(RUNTIME_PATH)) {
@mkdir(RUNTIME_PATH, 0755, true);
}
file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache()); file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache());
$output->writeln('<info>Succeed!</info>'); $output->writeln('<info>Succeed!</info>');
} }
@@ -69,7 +69,7 @@ class Descriptor
* 描述参数 * 描述参数
* @param InputArgument $argument * @param InputArgument $argument
* @param array $options * @param array $options
* @return string|mixed * @return void
*/ */
protected function describeInputArgument(InputArgument $argument, array $options = []) protected function describeInputArgument(InputArgument $argument, array $options = [])
{ {
@@ -93,7 +93,7 @@ class Descriptor
* 描述选项 * 描述选项
* @param InputOption $option * @param InputOption $option
* @param array $options * @param array $options
* @return string|mixed * @return void
*/ */
protected function describeInputOption(InputOption $option, array $options = []) protected function describeInputOption(InputOption $option, array $options = [])
{ {
@@ -128,7 +128,7 @@ class Descriptor
* 描述输入 * 描述输入
* @param InputDefinition $definition * @param InputDefinition $definition
* @param array $options * @param array $options
* @return string|mixed * @return void
*/ */
protected function describeInputDefinition(InputDefinition $definition, array $options = []) protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{ {
@@ -173,7 +173,7 @@ class Descriptor
* 描述指令 * 描述指令
* @param Command $command * @param Command $command
* @param array $options * @param array $options
* @return string|mixed * @return void
*/ */
protected function describeCommand(Command $command, array $options = []) protected function describeCommand(Command $command, array $options = [])
{ {
@@ -208,7 +208,7 @@ class Descriptor
* 描述控制台 * 描述控制台
* @param Console $console * @param Console $console
* @param array $options * @param array $options
* @return string|mixed * @return void
*/ */
protected function describeConsole(Console $console, array $options = []) protected function describeConsole(Console $console, array $options = [])
{ {
+3 -3
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -43,7 +43,7 @@ abstract class Rest
if ('' == $ext) { if ('' == $ext) {
// 自动检测资源类型 // 自动检测资源类型
$this->type = $request->type(); $this->type = $request->type();
} elseif (!preg_match('/\(' . $this->restTypeList . '\)$/i', $ext)) { } elseif (!preg_match('/(' . $this->restTypeList . ')$/i', $ext)) {
// 资源类型非法 则用默认资源类型访问 // 资源类型非法 则用默认资源类型访问
$this->type = $this->restDefaultType; $this->type = $this->restDefaultType;
} else { } else {
@@ -51,7 +51,7 @@ abstract class Rest
} }
// 请求方式检测 // 请求方式检测
$method = strtolower($request->method()); $method = strtolower($request->method());
if (false === stripos($this->restMethodList, $method)) { if (!preg_match('/(' . $this->restMethodList . ')$/i', $method)) {
// 请求方式非法 则用默认请求方法 // 请求方式非法 则用默认请求方法
$method = $this->restDefaultMethod; $method = $this->restDefaultMethod;
} }
+54 -26
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,6 +11,7 @@
namespace think\db; namespace think\db;
use BadMethodCallException;
use PDO; use PDO;
use think\Exception; use think\Exception;
@@ -25,7 +26,7 @@ abstract class Builder
protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME']; protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'];
// SQL表达式 // SQL表达式
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%'; protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%UNION%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%%LOCK%%COMMENT%';
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
@@ -46,7 +47,7 @@ abstract class Builder
/** /**
* 获取当前的连接对象实例 * 获取当前的连接对象实例
* @access public * @access public
* @return void * @return Connection
*/ */
public function getConnection() public function getConnection()
{ {
@@ -56,7 +57,7 @@ abstract class Builder
/** /**
* 获取当前的Query对象实例 * 获取当前的Query对象实例
* @access public * @access public
* @return void * @return Query
*/ */
public function getQuery() public function getQuery()
{ {
@@ -80,6 +81,7 @@ abstract class Builder
* @param array $data 数据 * @param array $data 数据
* @param array $options 查询参数 * @param array $options 查询参数
* @return array * @return array
* @throws Exception
*/ */
protected function parseData($data, $options) protected function parseData($data, $options)
{ {
@@ -108,16 +110,26 @@ abstract class Builder
} }
} elseif (is_null($val)) { } elseif (is_null($val)) {
$result[$item] = 'NULL'; $result[$item] = 'NULL';
} elseif (isset($val[0]) && 'exp' == $val[0]) { } elseif (is_array($val) && !empty($val)) {
$result[$item] = $val[1]; switch ($val[0]) {
case 'exp':
$result[$item] = $val[1];
break;
case 'inc':
$result[$item] = $this->parseKey($val[1]) . '+' . floatval($val[2]);
break;
case 'dec':
$result[$item] = $this->parseKey($val[1]) . '-' . floatval($val[2]);
break;
}
} elseif (is_scalar($val)) { } elseif (is_scalar($val)) {
// 过滤非标量数据 // 过滤非标量数据
if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) { if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {
$result[$item] = $val; $result[$item] = $val;
} else { } else {
$key = str_replace('.', '_', $key); $key = str_replace('.', '_', $key);
$this->query->bind('__data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR); $this->query->bind('data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
$result[$item] = ':__data__' . $key; $result[$item] = ':data__' . $key;
} }
} }
} }
@@ -300,7 +312,7 @@ abstract class Builder
// 查询规则和条件 // 查询规则和条件
if (!is_array($val)) { if (!is_array($val)) {
$val = ['=', $val]; $val = is_null($val) ? ['null', ''] : ['=', $val];
} }
list($exp, $value) = $val; list($exp, $value) = $val;
@@ -335,6 +347,11 @@ abstract class Builder
$bindName = md5($bindName); $bindName = md5($bindName);
} }
if (is_object($value) && method_exists($value, '__toString')) {
// 对象数据写入
$value = $value->__toString();
}
$bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR; $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;
if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) { if (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 (strpos($value, ':') !== 0 || !$this->query->isBind(substr($value, 1))) {
@@ -492,7 +509,7 @@ abstract class Builder
/** /**
* limit分析 * limit分析
* @access protected * @access protected
* @param mixed $lmit * @param mixed $limit
* @return string * @return string
*/ */
protected function parseLimit($limit) protected function parseLimit($limit)
@@ -544,7 +561,11 @@ abstract class Builder
foreach ($order as $key => $val) { foreach ($order as $key => $val) {
if (is_numeric($key)) { if (is_numeric($key)) {
if ('[rand]' == $val) { if ('[rand]' == $val) {
$array[] = $this->parseRand(); if (method_exists($this, 'parseRand')) {
$array[] = $this->parseRand();
} else {
throw new BadMethodCallException('method not exists:' . get_class($this) . '-> parseRand');
}
} elseif (false === strpos($val, '(')) { } elseif (false === strpos($val, '(')) {
$array[] = $this->parseKey($val, $options); $array[] = $this->parseKey($val, $options);
} else { } else {
@@ -568,7 +589,7 @@ abstract class Builder
*/ */
protected function parseGroup($group) protected function parseGroup($group)
{ {
return !empty($group) ? ' GROUP BY ' . $group : ''; return !empty($group) ? ' GROUP BY ' . $this->parseKey($group) : '';
} }
/** /**
@@ -619,12 +640,12 @@ abstract class Builder
unset($union['type']); unset($union['type']);
foreach ($union as $u) { foreach ($union as $u) {
if ($u instanceof \Closure) { if ($u instanceof \Closure) {
$sql[] = $type . ' ' . $this->parseClosure($u, false); $sql[] = $type . ' ' . $this->parseClosure($u);
} elseif (is_string($u)) { } elseif (is_string($u)) {
$sql[] = $type . ' ' . $this->parseSqlTable($u); $sql[] = $type . ' ( ' . $this->parseSqlTable($u) . ' )';
} }
} }
return implode(' ', $sql); return ' ' . implode(' ', $sql);
} }
/** /**
@@ -649,12 +670,16 @@ abstract class Builder
/** /**
* 设置锁机制 * 设置锁机制
* @access protected * @access protected
* @param bool $locl * @param bool|string $lock
* @return string * @return string
*/ */
protected function parseLock($lock = false) protected function parseLock($lock = false)
{ {
return $lock ? ' FOR UPDATE ' : ''; if (is_bool($lock)) {
return $lock ? ' FOR UPDATE ' : '';
} elseif (is_string($lock)) {
return ' ' . trim($lock) . ' ';
}
} }
/** /**
@@ -723,8 +748,9 @@ abstract class Builder
* @param array $options 表达式 * @param array $options 表达式
* @param bool $replace 是否replace * @param bool $replace 是否replace
* @return string * @return string
* @throws Exception
*/ */
public function insertAll($dataSet, $options, $replace = false) public function insertAll($dataSet, $options = [], $replace = false)
{ {
// 获取合法的字段 // 获取合法的字段
if ('*' == $options['field']) { if ('*' == $options['field']) {
@@ -733,7 +759,7 @@ abstract class Builder
$fields = $options['field']; $fields = $options['field'];
} }
foreach ($dataSet as &$data) { foreach ($dataSet as $data) {
foreach ($data as $key => $val) { foreach ($data as $key => $val) {
if (!in_array($key, $fields, true)) { if (!in_array($key, $fields, true)) {
if ($options['strict']) { if ($options['strict']) {
@@ -754,23 +780,25 @@ abstract class Builder
} }
$value = array_values($data); $value = array_values($data);
$values[] = 'SELECT ' . implode(',', $value); $values[] = 'SELECT ' . implode(',', $value);
if (!isset($insertFields)) {
$insertFields = array_map([$this, 'parseKey'], array_keys($data));
}
} }
$fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
$sql = str_replace( return str_replace(
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
[ [
$replace ? 'REPLACE' : 'INSERT', $replace ? 'REPLACE' : 'INSERT',
$this->parseTable($options['table'], $options), $this->parseTable($options['table'], $options),
implode(' , ', $fields), implode(' , ', $insertFields),
implode(' UNION ALL ', $values), implode(' UNION ALL ', $values),
$this->parseComment($options['comment']), $this->parseComment($options['comment']),
], $this->insertAllSql); ], $this->insertAllSql);
return $sql;
} }
/** /**
* 生成slectinsert SQL * 生成select insert SQL
* @access public * @access public
* @param array $fields 数据 * @param array $fields 数据
* @param string $table 数据表 * @param string $table 数据表
@@ -791,7 +819,7 @@ abstract class Builder
/** /**
* 生成update SQL * 生成update SQL
* @access public * @access public
* @param array $fields 数据 * @param array $data 数据
* @param array $options 表达式 * @param array $options 表达式
* @return string * @return string
*/ */
+42 -21
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -338,8 +338,8 @@ abstract class Connection
* @param bool $master 是否在主服务器读操作 * @param bool $master 是否在主服务器读操作
* @param bool $pdo 是否返回PDO对象 * @param bool $pdo 是否返回PDO对象
* @return mixed * @return mixed
* @throws BindParamException
* @throws PDOException * @throws PDOException
* @throws \Exception
*/ */
public function query($sql, $bind = [], $master = false, $pdo = false) public function query($sql, $bind = [], $master = false, $pdo = false)
{ {
@@ -354,15 +354,15 @@ abstract class Connection
$this->bind = $bind; $this->bind = $bind;
} }
// 释放前次的查询结果
if (!empty($this->PDOStatement)) {
$this->free();
}
Db::$queryTimes++; Db::$queryTimes++;
try { try {
// 调试开始 // 调试开始
$this->debug(true); $this->debug(true);
// 释放前次的查询结果
if (!empty($this->PDOStatement)) {
$this->free();
}
// 预处理 // 预处理
if (empty($this->PDOStatement)) { if (empty($this->PDOStatement)) {
$this->PDOStatement = $this->linkID->prepare($sql); $this->PDOStatement = $this->linkID->prepare($sql);
@@ -386,6 +386,11 @@ abstract class Connection
return $this->close()->query($sql, $bind, $master, $pdo); return $this->close()->query($sql, $bind, $master, $pdo);
} }
throw new PDOException($e, $this->config, $this->getLastsql()); throw new PDOException($e, $this->config, $this->getLastsql());
} catch (\Throwable $e) {
if ($this->isBreak($e)) {
return $this->close()->query($sql, $bind, $master, $pdo);
}
throw $e;
} catch (\Exception $e) { } catch (\Exception $e) {
if ($this->isBreak($e)) { if ($this->isBreak($e)) {
return $this->close()->query($sql, $bind, $master, $pdo); return $this->close()->query($sql, $bind, $master, $pdo);
@@ -400,8 +405,8 @@ abstract class Connection
* @param string $sql sql指令 * @param string $sql sql指令
* @param array $bind 参数绑定 * @param array $bind 参数绑定
* @return int * @return int
* @throws BindParamException
* @throws PDOException * @throws PDOException
* @throws \Exception
*/ */
public function execute($sql, $bind = []) public function execute($sql, $bind = [])
{ {
@@ -416,15 +421,15 @@ abstract class Connection
$this->bind = $bind; $this->bind = $bind;
} }
//释放前次的查询结果
if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {
$this->free();
}
Db::$executeTimes++; Db::$executeTimes++;
try { try {
// 调试开始 // 调试开始
$this->debug(true); $this->debug(true);
//释放前次的查询结果
if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {
$this->free();
}
// 预处理 // 预处理
if (empty($this->PDOStatement)) { if (empty($this->PDOStatement)) {
$this->PDOStatement = $this->linkID->prepare($sql); $this->PDOStatement = $this->linkID->prepare($sql);
@@ -449,6 +454,11 @@ abstract class Connection
return $this->close()->execute($sql, $bind); return $this->close()->execute($sql, $bind);
} }
throw new PDOException($e, $this->config, $this->getLastsql()); throw new PDOException($e, $this->config, $this->getLastsql());
} catch (\Throwable $e) {
if ($this->isBreak($e)) {
return $this->close()->execute($sql, $bind);
}
throw $e;
} catch (\Exception $e) { } catch (\Exception $e) {
if ($this->isBreak($e)) { if ($this->isBreak($e)) {
return $this->close()->execute($sql, $bind); return $this->close()->execute($sql, $bind);
@@ -466,6 +476,10 @@ abstract class Connection
*/ */
public function getRealSql($sql, array $bind = []) public function getRealSql($sql, array $bind = [])
{ {
if (is_array($sql)) {
$sql = implode(';', $sql);
}
foreach ($bind as $key => $val) { foreach ($bind as $key => $val) {
$value = is_array($val) ? $val[0] : $val; $value = is_array($val) ? $val[0] : $val;
$type = is_array($val) ? $val[1] : PDO::PARAM_STR; $type = is_array($val) ? $val[1] : PDO::PARAM_STR;
@@ -478,8 +492,8 @@ abstract class Connection
$sql = is_numeric($key) ? $sql = is_numeric($key) ?
substr_replace($sql, $value, strpos($sql, '?'), 1) : substr_replace($sql, $value, strpos($sql, '?'), 1) :
str_replace( str_replace(
[':' . $key . ')', ':' . $key . ',', ':' . $key . ' '], [':' . $key . ')', ':' . $key . ',', ':' . $key . ' ', ':' . $key . PHP_EOL],
[$value . ')', $value . ',', $value . ' '], [$value . ')', $value . ',', $value . ' ', $value . PHP_EOL],
$sql . ' '); $sql . ' ');
} }
return rtrim($sql); return rtrim($sql);
@@ -552,7 +566,7 @@ abstract class Connection
* @access protected * @access protected
* @param bool $pdo 是否返回PDOStatement * @param bool $pdo 是否返回PDOStatement
* @param bool $procedure 是否存储过程 * @param bool $procedure 是否存储过程
* @return array * @return PDOStatement|array
*/ */
protected function getResult($pdo = false, $procedure = false) protected function getResult($pdo = false, $procedure = false)
{ {
@@ -618,7 +632,8 @@ abstract class Connection
/** /**
* 启动事务 * 启动事务
* @access public * @access public
* @return void * @return bool|mixed
* @throws \Exception
*/ */
public function startTrans() public function startTrans()
{ {
@@ -642,7 +657,12 @@ abstract class Connection
return $this->close()->startTrans(); return $this->close()->startTrans();
} }
throw $e; throw $e;
} catch (\ErrorException $e) { } catch (\Exception $e) {
if ($this->isBreak($e)) {
return $this->close()->startTrans();
}
throw $e;
} catch (\Error $e) {
if ($this->isBreak($e)) { if ($this->isBreak($e)) {
return $this->close()->startTrans(); return $this->close()->startTrans();
} }
@@ -724,7 +744,7 @@ abstract class Connection
* @param array $sqlArray SQL批处理指令 * @param array $sqlArray SQL批处理指令
* @return boolean * @return boolean
*/ */
public function batchQuery($sqlArray = []) public function batchQuery($sqlArray = [], $bind = [])
{ {
if (!is_array($sqlArray)) { if (!is_array($sqlArray)) {
return false; return false;
@@ -733,7 +753,7 @@ abstract class Connection
$this->startTrans(); $this->startTrans();
try { try {
foreach ($sqlArray as $sql) { foreach ($sqlArray as $sql) {
$this->execute($sql); $this->execute($sql, $bind);
} }
// 提交事务 // 提交事务
$this->commit(); $this->commit();
@@ -741,6 +761,7 @@ abstract class Connection
$this->rollback(); $this->rollback();
throw $e; throw $e;
} }
return true; return true;
} }
@@ -782,7 +803,7 @@ abstract class Connection
/** /**
* 是否断线 * 是否断线
* @access protected * @access protected
* @param \PDOException $e 异常对象 * @param \PDOException|\Exception $e 异常对象
* @return bool * @return bool
*/ */
protected function isBreak($e) protected function isBreak($e)
+144 -95
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -12,6 +12,7 @@
namespace think\db; namespace think\db;
use PDO; use PDO;
use think\App;
use think\Cache; use think\Cache;
use think\Collection; use think\Collection;
use think\Config; use think\Config;
@@ -114,6 +115,7 @@ class Query
{ {
$this->connection = Db::connect($config); $this->connection = Db::connect($config);
$this->setBuilder(); $this->setBuilder();
$this->prefix = $this->connection->getConfig('prefix');
return $this; return $this;
} }
@@ -310,9 +312,9 @@ class Query
* @param array $sql SQL批处理指令 * @param array $sql SQL批处理指令
* @return boolean * @return boolean
*/ */
public function batchQuery($sql = []) public function batchQuery($sql = [], $bind = [])
{ {
return $this->connection->batchQuery($sql); return $this->connection->batchQuery($sql, $bind);
} }
/** /**
@@ -415,8 +417,9 @@ class Query
} }
$result = $pdo->fetchColumn(); $result = $pdo->fetchColumn();
if ($force) { if ($force) {
$result = is_numeric($result) ? $result + 0 : $result; $result += 0;
} }
if (isset($cache)) { if (isset($cache)) {
// 缓存数据 // 缓存数据
$this->cacheData($key, $result, $cache); $this->cacheData($key, $result, $cache);
@@ -531,22 +534,24 @@ class Query
* MIN查询 * MIN查询
* @access public * @access public
* @param string $field 字段名 * @param string $field 字段名
* @param bool $force 强制转为数字类型
* @return mixed * @return mixed
*/ */
public function min($field) public function min($field, $force = true)
{ {
return $this->value('MIN(' . $field . ') AS tp_min', 0, true); return $this->value('MIN(' . $field . ') AS tp_min', 0, $force);
} }
/** /**
* MAX查询 * MAX查询
* @access public * @access public
* @param string $field 字段名 * @param string $field 字段名
* @param bool $force 强制转为数字类型
* @return mixed * @return mixed
*/ */
public function max($field) public function max($field, $force = true)
{ {
return $this->value('MAX(' . $field . ') AS tp_max', 0, true); return $this->value('MAX(' . $field . ') AS tp_max', 0, $force);
} }
/** /**
@@ -604,7 +609,7 @@ class Query
return true; return true;
} }
} }
return $this->setField($field, ['exp', $field . '+' . $step]); return $this->setField($field, ['inc', $field, $step]);
} }
/** /**
@@ -632,8 +637,9 @@ class Query
$this->options = []; $this->options = [];
return true; return true;
} }
return $this->setField($field, ['inc', $field, $step]);
} }
return $this->setField($field, ['exp', $field . '-' . $step]); return $this->setField($field, ['dec', $field, $step]);
} }
/** /**
@@ -701,7 +707,8 @@ class Query
{ {
// 传入的表名为数组 // 传入的表名为数组
if (is_array($join)) { if (is_array($join)) {
list($table, $alias) = each($join); $table = key($join);
$alias = current($join);
} else { } else {
$join = trim($join); $join = trim($join);
if (false !== strpos($join, '(')) { if (false !== strpos($join, '(')) {
@@ -723,10 +730,13 @@ class Query
} }
} }
} }
if (isset($alias)) { if (isset($alias) && $table != $alias) {
if (isset($this->options['alias'][$table])) { if (isset($this->options['alias'][$table])) {
$table = $table . '@think' . uniqid(); $table = $table . '@think' . uniqid();
} elseif ($this->gettable() == $table) {
$table = $table . '@think' . uniqid();
} }
$table = [$table => $alias]; $table = [$table => $alias];
$this->alias($table); $this->alias($table);
} }
@@ -825,7 +835,7 @@ class Query
{ {
$fields = is_string($field) ? explode(',', $field) : $field; $fields = is_string($field) ? explode(',', $field) : $field;
foreach ($fields as $field) { foreach ($fields as $field) {
$this->data($field, ['exp', $field . '+' . $step]); $this->data($field, ['inc', $field, $step]);
} }
return $this; return $this;
} }
@@ -841,7 +851,7 @@ class Query
{ {
$fields = is_string($field) ? explode(',', $field) : $field; $fields = is_string($field) ? explode(',', $field) : $field;
foreach ($fields as $field) { foreach ($fields as $field) {
$this->data($field, ['exp', $field . '-' . $step]); $this->data($field, ['dec', $field, $step]);
} }
return $this; return $this;
} }
@@ -1184,10 +1194,8 @@ class Query
$this->options['multi'][$logic][$field][] = $where[$field]; $this->options['multi'][$logic][$field][] = $where[$field];
} elseif (is_null($condition)) { } elseif (is_null($condition)) {
// 字段相等查询 // 字段相等查询
$where[$field] = ['eq', $op]; $where[$field] = ['eq', $op];
if ('AND' != $logic) { $this->options['multi'][$logic][$field][] = $where[$field];
$this->options['multi'][$logic][$field][] = $where[$field];
}
} else { } else {
$where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null]; $where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null];
if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) { if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) {
@@ -1238,6 +1246,7 @@ class Query
$logic = strtoupper($logic); $logic = strtoupper($logic);
if (isset($this->options['where'][$logic][$field])) { if (isset($this->options['where'][$logic][$field])) {
unset($this->options['where'][$logic][$field]); unset($this->options['where'][$logic][$field]);
unset($this->options['multi'][$logic][$field]);
} }
return $this; return $this;
} }
@@ -1444,18 +1453,19 @@ class Query
/** /**
* 查询缓存 * 查询缓存
* @access public * @access public
* @param mixed $key 缓存key * @param mixed $key 缓存key
* @param integer $expire 缓存有效期 * @param integer|\DateTime $expire 缓存有效期
* @param string $tag 缓存标签 * @param string $tag 缓存标签
* @return $this * @return $this
*/ */
public function cache($key = true, $expire = null, $tag = null) public function cache($key = true, $expire = null, $tag = null)
{ {
// 增加快捷调用方式 cache(10) 等同于 cache(true, 10) // 增加快捷调用方式 cache(10) 等同于 cache(true, 10)
if (is_numeric($key) && is_null($expire)) { if ($key instanceof \DateTime || (is_numeric($key) && is_null($expire))) {
$expire = $key; $expire = $key;
$key = true; $key = true;
} }
if (false !== $key) { if (false !== $key) {
$this->options['cache'] = ['key' => $key, 'expire' => $expire, 'tag' => $tag]; $this->options['cache'] = ['key' => $key, 'expire' => $expire, 'tag' => $tag];
} }
@@ -1489,7 +1499,7 @@ class Query
/** /**
* 指定查询lock * 指定查询lock
* @access public * @access public
* @param boolean $lock 是否lock * @param bool|string $lock 是否lock
* @return $this * @return $this
*/ */
public function lock($lock = false) public function lock($lock = false)
@@ -1521,7 +1531,12 @@ class Query
{ {
if (is_array($alias)) { if (is_array($alias)) {
foreach ($alias as $key => $val) { foreach ($alias as $key => $val) {
$this->options['alias'][$key] = $val; if (false !== strpos($key, '__')) {
$table = $this->parseSqlTable($key);
} else {
$table = $key;
}
$this->options['alias'][$table] = $val;
} }
} else { } else {
if (isset($this->options['table'])) { if (isset($this->options['table'])) {
@@ -1649,46 +1664,49 @@ class Query
* 查询日期或者时间 * 查询日期或者时间
* @access public * @access public
* @param string $field 日期字段名 * @param string $field 日期字段名
* @param string $op 比较运算符或者表达式 * @param string|array $op 比较运算符或者表达式
* @param string|array $range 比较范围 * @param string|array $range 比较范围
* @return $this * @return $this
*/ */
public function whereTime($field, $op, $range = null) public function whereTime($field, $op, $range = null)
{ {
if (is_null($range)) { if (is_null($range)) {
// 使用日期表达式 if (is_array($op)) {
$date = getdate(); $range = $op;
switch (strtolower($op)) { } else {
case 'today': // 使用日期表达式
case 'd': switch (strtolower($op)) {
$range = ['today', 'tomorrow']; case 'today':
break; case 'd':
case 'week': $range = ['today', 'tomorrow'];
case 'w': break;
$range = 'this week 00:00:00'; case 'week':
break; case 'w':
case 'month': $range = ['this week 00:00:00', 'next week 00:00:00'];
case 'm': break;
$range = mktime(0, 0, 0, $date['mon'], 1, $date['year']); case 'month':
break; case 'm':
case 'year': $range = ['first Day of this month 00:00:00', 'first Day of next month 00:00:00'];
case 'y': break;
$range = mktime(0, 0, 0, 1, 1, $date['year']); case 'year':
break; case 'y':
case 'yesterday': $range = ['this year 1/1', 'next year 1/1'];
$range = ['yesterday', 'today']; break;
break; case 'yesterday':
case 'last week': $range = ['yesterday', 'today'];
$range = ['last week 00:00:00', 'this week 00:00:00']; break;
break; case 'last week':
case 'last month': $range = ['last week 00:00:00', 'this week 00:00:00'];
$range = [date('y-m-01', strtotime('-1 month')), mktime(0, 0, 0, $date['mon'], 1, $date['year'])]; break;
break; case 'last month':
case 'last year': $range = ['first Day of last month 00:00:00', 'first Day of this month 00:00:00'];
$range = [mktime(0, 0, 0, 1, 1, $date['year'] - 1), mktime(0, 0, 0, 1, 1, $date['year'])]; break;
break; case 'last year':
default: $range = ['last year 1/1', 'this year 1/1'];
$range = $op; break;
default:
$range = $op;
}
} }
$op = is_array($range) ? 'between' : '>'; $op = is_array($range) ? 'between' : '>';
} }
@@ -1733,7 +1751,7 @@ class Query
$schema = $guid; $schema = $guid;
} }
// 读取缓存 // 读取缓存
if (is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) { if (!App::$debug && is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) {
$info = include RUNTIME_PATH . 'schema/' . $schema . '.php'; $info = include RUNTIME_PATH . 'schema/' . $schema . '.php';
} else { } else {
$info = $this->connection->getFields($guid); $info = $this->connection->getFields($guid);
@@ -1808,7 +1826,9 @@ class Query
*/ */
protected function getFieldBindType($type) protected function getFieldBindType($type)
{ {
if (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) { if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) {
$bind = PDO::PARAM_STR;
} elseif (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) {
$bind = PDO::PARAM_INT; $bind = PDO::PARAM_INT;
} elseif (preg_match('/bool/is', $type)) { } elseif (preg_match('/bool/is', $type)) {
$bind = PDO::PARAM_BOOL; $bind = PDO::PARAM_BOOL;
@@ -2080,7 +2100,7 @@ class Query
} }
// 执行操作 // 执行操作
$result = $this->execute($sql, $bind); $result = 0 === $sql ? 0 : $this->execute($sql, $bind);
if ($result) { if ($result) {
$sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null);
$lastInsId = $this->getLastInsID($sequence); $lastInsId = $this->getLastInsID($sequence);
@@ -2116,24 +2136,37 @@ class Query
/** /**
* 批量插入记录 * 批量插入记录
* @access public * @access public
* @param mixed $dataSet 数据集 * @param mixed $dataSet 数据集
* @param boolean $replace 是否replace * @param boolean $replace 是否replace
* @param integer $limit 每次写入数据限制
* @return integer|string * @return integer|string
*/ */
public function insertAll(array $dataSet, $replace = false) public function insertAll(array $dataSet, $replace = false, $limit = null)
{ {
// 分析查询表达式 // 分析查询表达式
$options = $this->parseExpress(); $options = $this->parseExpress();
if (!is_array(reset($dataSet))) { if (!is_array(reset($dataSet))) {
return false; return false;
} }
// 生成SQL语句 // 生成SQL语句
$sql = $this->builder->insertAll($dataSet, $options, $replace); if (is_null($limit)) {
$sql = $this->builder->insertAll($dataSet, $options, $replace);
} else {
$array = array_chunk($dataSet, $limit, true);
foreach ($array as $item) {
$sql[] = $this->builder->insertAll($item, $options, $replace);
}
}
// 获取参数绑定 // 获取参数绑定
$bind = $this->getBind(); $bind = $this->getBind();
if ($options['fetch_sql']) { if ($options['fetch_sql']) {
// 获取实际执行的SQL语句 // 获取实际执行的SQL语句
return $this->connection->getRealSql($sql, $bind); return $this->connection->getRealSql($sql, $bind);
} elseif (is_array($sql)) {
// 执行操作
return $this->batchQuery($sql, $bind);
} else { } else {
// 执行操作 // 执行操作
return $this->execute($sql, $bind); return $this->execute($sql, $bind);
@@ -2335,7 +2368,7 @@ class Query
$modelName = $this->model; $modelName = $this->model;
if (count($resultSet) > 0) { if (count($resultSet) > 0) {
foreach ($resultSet as $key => $result) { foreach ($resultSet as $key => $result) {
/** @var Model $result */ /** @var Model $model */
$model = new $modelName($result); $model = new $modelName($result);
$model->isUpdate(true); $model->isUpdate(true);
@@ -2391,12 +2424,13 @@ class Query
* @param mixed $value 缓存数据 * @param mixed $value 缓存数据
* @param array $options 缓存参数 * @param array $options 缓存参数
* @param array $bind 绑定参数 * @param array $bind 绑定参数
* @return string
*/ */
protected function getCacheKey($value, $options, $bind = []) protected function getCacheKey($value, $options, $bind = [])
{ {
if (is_scalar($value)) { if (is_scalar($value)) {
$data = $value; $data = $value;
} elseif (is_array($value) && 'eq' == strtolower($value[0])) { } elseif (is_array($value) && is_string($value[0]) && 'eq' == strtolower($value[0])) {
$data = $value[1]; $data = $value[1];
} }
if (isset($data)) { if (isset($data)) {
@@ -2564,44 +2598,59 @@ class Query
* @param integer $count 每次处理的数据数量 * @param integer $count 每次处理的数据数量
* @param callable $callback 处理回调方法 * @param callable $callback 处理回调方法
* @param string $column 分批处理的字段名 * @param string $column 分批处理的字段名
* @param string $order 排序规则
* @return boolean * @return boolean
* @throws \LogicException
*/ */
public function chunk($count, $callback, $column = null) public function chunk($count, $callback, $column = null, $order = 'asc')
{ {
$options = $this->getOptions(); $options = $this->getOptions();
if (isset($options['table'])) {
$table = is_array($options['table']) ? key($options['table']) : $options['table'];
} else {
$table = '';
}
$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)) { $column = $column ?: $this->getPk($options);
if (false === call_user_func($callback, $resultSet)) {
return false; if (isset($options['order'])) {
if (App::$debug) {
throw new \LogicException('chunk not support call order');
} }
$end = end($resultSet); unset($options['order']);
$lastId = is_array($end) ? $end[$key] : $end->$key; }
$resultSet = $this->options($options) $bind = $this->bind;
->limit($count) if (is_array($column)) {
->bind($bind) $times = 1;
->where($column, '>', $lastId) $query = $this->options($options)->page($times, $count);
->order($column, 'asc') } else {
->select(); if (strpos($column, '.')) {
list($alias, $key) = explode('.', $column);
} else {
$key = $column;
}
$query = $this->options($options)->limit($count);
}
$resultSet = $query->order($column, $order)->select();
while (count($resultSet) > 0) {
if ($resultSet instanceof Collection) { if ($resultSet instanceof Collection) {
$resultSet = $resultSet->all(); $resultSet = $resultSet->all();
} }
if (false === call_user_func($callback, $resultSet)) {
return false;
}
if (is_array($column)) {
$times++;
$query = $this->options($options)->page($times, $count);
} else {
$end = end($resultSet);
$lastId = is_array($end) ? $end[$key] : $end->getData($key);
$query = $this->options($options)
->limit($count)
->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
}
$resultSet = $query->bind($bind)->order($column, $order)->select();
} }
return true; return true;
} }
+61 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -12,13 +12,72 @@
namespace think\db\builder; namespace think\db\builder;
use think\db\Builder; use think\db\Builder;
use think\Exception;
/** /**
* mysql数据库驱动 * mysql数据库驱动
*/ */
class Mysql extends Builder class Mysql extends Builder
{ {
protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%';
protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
/**
* 生成insertall SQL
* @access public
* @param array $dataSet 数据集
* @param array $options 表达式
* @param bool $replace 是否replace
* @return string
* @throws Exception
*/
public function insertAll($dataSet, $options = [], $replace = false)
{
// 获取合法的字段
if ('*' == $options['field']) {
$fields = array_keys($this->query->getFieldsType($options['table']));
} else {
$fields = $options['field'];
}
foreach ($dataSet as $data) {
foreach ($data as $key => $val) {
if (!in_array($key, $fields, true)) {
if ($options['strict']) {
throw new Exception('fields not exists:[' . $key . ']');
}
unset($data[$key]);
} elseif (is_null($val)) {
$data[$key] = 'NULL';
} elseif (is_scalar($val)) {
$data[$key] = $this->parseValue($val, $key);
} elseif (is_object($val) && method_exists($val, '__toString')) {
// 对象数据写入
$data[$key] = $val->__toString();
} else {
// 过滤掉非标量数据
unset($data[$key]);
}
}
$value = array_values($data);
$values[] = '( ' . implode(',', $value) . ' )';
if (!isset($insertFields)) {
$insertFields = array_map([$this, 'parseKey'], array_keys($data));
}
}
return str_replace(
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
[
$replace ? 'REPLACE' : 'INSERT',
$this->parseTable($options['table'], $options),
implode(' , ', $insertFields),
implode(' , ', $values),
$this->parseComment($options['comment']),
], $this->insertAllSql);
}
/** /**
* 字段和表名处理 * 字段和表名处理
+3 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -18,6 +18,8 @@ use think\db\Builder;
*/ */
class Pgsql extends Builder class Pgsql extends Builder
{ {
protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
/** /**
* limit分析 * limit分析
+2 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -22,6 +22,7 @@ class Sqlite extends Builder
/** /**
* limit * limit
* @access public * @access public
* @param string $limit
* @return string * @return string
*/ */
public function parseLimit($limit) public function parseLimit($limit)
+4
View File
@@ -22,6 +22,8 @@ class Sqlsrv extends Builder
protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%'; protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%';
protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
/** /**
* order分析 * order分析
@@ -40,6 +42,8 @@ class Sqlsrv extends Builder
$array[] = $this->parseKey($val, $options); $array[] = $this->parseKey($val, $options);
} elseif ('[rand]' == $val) { } elseif ('[rand]' == $val) {
$array[] = $this->parseRand(); $array[] = $this->parseRand();
} else {
$array[] = $val;
} }
} else { } else {
$sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';
+9 -6
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -31,12 +31,15 @@ class Mysql extends Connection
*/ */
protected function parseDsn($config) protected function parseDsn($config)
{ {
$dsn = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname']; if (!empty($config['socket'])) {
if (!empty($config['hostport'])) { $dsn = 'mysql:unix_socket=' . $config['socket'];
$dsn .= ';port=' . $config['hostport']; } elseif (!empty($config['hostport'])) {
} elseif (!empty($config['socket'])) { $dsn = 'mysql:host=' . $config['hostname'] . ';port=' . $config['hostport'];
$dsn .= ';unix_socket=' . $config['socket']; } else {
$dsn = 'mysql:host=' . $config['hostname'];
} }
$dsn .= ';dbname=' . $config['database'];
if (!empty($config['charset'])) { if (!empty($config['charset'])) {
$dsn .= ';charset=' . $config['charset']; $dsn .= ';charset=' . $config['charset'];
} }
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -137,7 +137,7 @@ JS;
} }
break; break;
case '错误': case '错误':
$msg = str_replace("\n", '\n', $m); $msg = str_replace("\n", '\n', json_encode($m));
$style = 'color:#F4006B;font-size:14px;'; $style = 'color:#F4006B;font-size:14px;';
$line[] = "console.error(\"%c{$msg}\", \"{$style}\");"; $line[] = "console.error(\"%c{$msg}\", \"{$style}\");";
break; break;
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+17 -1
View File
@@ -21,11 +21,16 @@ use think\Response;
class Handle class Handle
{ {
protected $render;
protected $ignoreReport = [ protected $ignoreReport = [
'\\think\\exception\\HttpException', '\\think\\exception\\HttpException',
]; ];
public function setRender($render)
{
$this->render = $render;
}
/** /**
* Report or log an exception. * Report or log an exception.
* *
@@ -52,6 +57,10 @@ class Handle
$log = "[{$data['code']}]{$data['message']}"; $log = "[{$data['code']}]{$data['message']}";
} }
if (Config::get('record_trace')) {
$log .= "\r\n" . $exception->getTraceAsString();
}
Log::record($log, 'error'); Log::record($log, 'error');
} }
} }
@@ -74,6 +83,13 @@ class Handle
*/ */
public function render(Exception $e) public function render(Exception $e)
{ {
if ($this->render && $this->render instanceof \Closure) {
$result = call_user_func_array($this->render, [$e]);
if ($result) {
return $result;
}
}
if ($e instanceof HttpException) { if ($e instanceof HttpException) {
return $this->renderHttpException($e); return $this->renderHttpException($e);
} else { } else {
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -16,7 +16,7 @@ class RouteNotFoundException extends HttpException
public function __construct() public function __construct()
{ {
parent::__construct(404); parent::__construct(404, 'Route Not Found');
} }
} }
+15 -6
View File
@@ -12,6 +12,7 @@
namespace think\log\driver; namespace think\log\driver;
use think\App; use think\App;
use think\Request;
/** /**
* 本地化调试输出到文件 * 本地化调试输出到文件
@@ -20,6 +21,7 @@ class File
{ {
protected $config = [ protected $config = [
'time_format' => ' c ', 'time_format' => ' c ',
'single' => false,
'file_size' => 2097152, 'file_size' => 2097152,
'path' => LOG_PATH, 'path' => LOG_PATH,
'apart_level' => [], 'apart_level' => [],
@@ -43,8 +45,12 @@ class File
*/ */
public function save(array $log = []) public function save(array $log = [])
{ {
$cli = IS_CLI ? '_cli' : ''; if ($this->config['single']) {
$destination = $this->config['path'] . date('Ym') . DS . date('d') . $cli . '.log'; $destination = $this->config['path'] . 'single.log';
} else {
$cli = IS_CLI ? '_cli' : '';
$destination = $this->config['path'] . date('Ym') . DS . date('d') . $cli . '.log';
}
$path = dirname($destination); $path = dirname($destination);
!is_dir($path) && mkdir($path, 0755, true); !is_dir($path) && mkdir($path, 0755, true);
@@ -60,7 +66,11 @@ class File
} }
if (in_array($type, $this->config['apart_level'])) { if (in_array($type, $this->config['apart_level'])) {
// 独立记录的日志级别 // 独立记录的日志级别
$filename = $path . DS . date('d') . '_' . $type . $cli . '.log'; if ($this->config['single']) {
$filename = $path . DS . $type . '.log';
} else {
$filename = $path . DS . date('d') . '_' . $type . $cli . '.log';
}
$this->write($level, $filename, true); $this->write($level, $filename, true);
} else { } else {
$info .= $level; $info .= $level;
@@ -99,11 +109,10 @@ class File
$message = '[ info ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n" . $message; $message = '[ info ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n" . $message;
} }
$now = date($this->config['time_format']); $now = date($this->config['time_format']);
$server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0'; $ip = Request::instance()->ip();
$remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI';
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
$message = "---------------------------------------------------------------\r\n[{$now}] {$server} {$remote} {$method} {$uri}\r\n" . $message; $message = "---------------------------------------------------------------\r\n[{$now}] {$ip} {$method} {$uri}\r\n" . $message;
$this->writed[$destination] = true; $this->writed[$destination] = true;
} }
+2 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -85,7 +85,7 @@ class Collection extends BaseCollection
{ {
$this->each(function ($model) use ($append, $override) { $this->each(function ($model) use ($append, $override) {
/** @var Model $model */ /** @var Model $model */
$model->append($append, $override); $model && $model->append($append, $override);
}); });
return $this; return $this;
} }
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+3 -5
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -24,11 +24,11 @@ class Pivot extends Model
/** /**
* 架构函数 * 架构函数
* @access public * @access public
* @param Model $parent 上级模型
* @param array|object $data 数据 * @param array|object $data 数据
* @param Model $parent 上级模型
* @param string $table 中间数据表名 * @param string $table 中间数据表名
*/ */
public function __construct(Model $parent, $data = [], $table = '') public function __construct($data = [], Model $parent = null, $table = '')
{ {
$this->parent = $parent; $this->parent = $parent;
@@ -37,8 +37,6 @@ class Pivot extends Model
} }
parent::__construct($data); parent::__construct($data);
$this->class = $this->name;
} }
} }
+3 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -108,7 +108,8 @@ abstract class Relation
* @access protected * @access protected
* @return void * @return void
*/ */
abstract protected function baseQuery(); protected function baseQuery()
{}
public function __call($method, $args) public function __call($method, $args)
{ {
+20 -14
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,6 +11,7 @@
namespace think\model\relation; namespace think\model\relation;
use think\db\Query;
use think\Loader; use think\Loader;
use think\Model; use think\Model;
@@ -68,7 +69,6 @@ class BelongsTo extends OneToOne
* @param string $operator 比较操作符 * @param string $operator 比较操作符
* @param integer $count 个数 * @param integer $count 个数
* @param string $id 关联表的统计字段 * @param string $id 关联表的统计字段
* @param string $joinType JOIN类型
* @return Query * @return Query
*/ */
public function has($operator = '>=', $count = 1, $id = '*') public function has($operator = '>=', $count = 1, $id = '*')
@@ -79,14 +79,16 @@ class BelongsTo extends OneToOne
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
$table = $this->query->getTable(); $table = $this->query->getTable();
$model = basename(str_replace('\\', '/', get_class($this->parent))); $model = basename(str_replace('\\', '/', get_class($this->parent)));
$relation = basename(str_replace('\\', '/', $this->model)); $relation = basename(str_replace('\\', '/', $this->model));
if (is_array($where)) { if (is_array($where)) {
foreach ($where as $key => $val) { foreach ($where as $key => $val) {
if (false === strpos($key, '.')) { if (false === strpos($key, '.')) {
@@ -95,9 +97,11 @@ class BelongsTo extends OneToOne
} }
} }
} }
$fields = $this->getRelationQueryFields($fields, $model);
return $this->parent->db()->alias($model) return $this->parent->db()->alias($model)
->field($model . '.*') ->field($fields)
->join($table . ' ' . $relation, $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType) ->join([$table => $relation], $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType)
->where($where); ->where($where);
} }
@@ -124,7 +128,7 @@ class BelongsTo extends OneToOne
} }
if (!empty($range)) { if (!empty($range)) {
$data = $this->eagerlyWhere($this, [ $data = $this->eagerlyWhere($this->query, [
$localKey => [ $localKey => [
'in', 'in',
$range, $range,
@@ -143,12 +147,13 @@ class BelongsTo extends OneToOne
$relationModel->isUpdate(true); $relationModel->isUpdate(true);
} }
if ($relationModel && !empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr); $this->bindAttr($relationModel, $result, $this->bindAttr);
} else {
// 设置关联属性
$result->setRelation($attr, $relationModel);
} }
// 设置关联属性
$result->setRelation($attr, $relationModel);
} }
} }
} }
@@ -166,7 +171,7 @@ class BelongsTo extends OneToOne
{ {
$localKey = $this->localKey; $localKey = $this->localKey;
$foreignKey = $this->foreignKey; $foreignKey = $this->foreignKey;
$data = $this->eagerlyWhere($this, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure); $data = $this->eagerlyWhere($this->query, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure);
// 关联模型 // 关联模型
if (!isset($data[$result->$foreignKey])) { if (!isset($data[$result->$foreignKey])) {
$relationModel = null; $relationModel = null;
@@ -175,12 +180,13 @@ class BelongsTo extends OneToOne
$relationModel->setParent(clone $result); $relationModel->setParent(clone $result);
$relationModel->isUpdate(true); $relationModel->isUpdate(true);
} }
if ($relationModel && !empty($this->bindAttr)) { if (!empty($this->bindAttr)) {
// 绑定关联属性 // 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr); $this->bindAttr($relationModel, $result, $this->bindAttr);
} else {
// 设置关联属性
$result->setRelation(Loader::parseName($relation), $relationModel);
} }
// 设置关联属性
$result->setRelation(Loader::parseName($relation), $relationModel);
} }
/** /**
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -52,6 +52,10 @@ class BelongsToMany extends Relation
} }
$this->query = (new $model)->db(); $this->query = (new $model)->db();
$this->pivot = $this->newPivot(); $this->pivot = $this->newPivot();
if ('think\model\Pivot' == get_class($this->pivot)) {
$this->pivot->name($this->middle);
}
} }
/** /**
@@ -68,12 +72,18 @@ class BelongsToMany extends Relation
/** /**
* 实例化中间表模型 * 实例化中间表模型
* @param $data * @param $data
* @return mixed * @return Pivot
* @throws Exception
*/ */
protected function newPivot($data = []) protected function newPivot($data = [])
{ {
$pivot = $this->pivotName ?: '\\think\\model\\Pivot'; $class = $this->pivotName ?: '\\think\\model\\Pivot';
return new $pivot($this->parent, $data, $this->middle); $pivot = new $class($data, $this->parent, $this->middle);
if ($pivot instanceof Pivot) {
return $pivot;
} else {
throw new Exception('pivot model must extends: \think\model\Pivot');
}
} }
/** /**
@@ -206,11 +216,12 @@ class BelongsToMany extends Relation
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
* @throws Exception * @throws Exception
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
throw new Exception('relation not support: hasWhere'); throw new Exception('relation not support: hasWhere');
} }
@@ -384,7 +395,7 @@ class BelongsToMany extends Relation
if (empty($this->baseQuery)) { if (empty($this->baseQuery)) {
$relationFk = $this->query->getPk(); $relationFk = $this->query->getPk();
$query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) $query->join([$table => 'pivot'], 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
->where($condition); ->where($condition);
} }
return $query; return $query;
@@ -565,7 +576,7 @@ class BelongsToMany extends Relation
if (empty($this->baseQuery) && $this->parent->getData()) { if (empty($this->baseQuery) && $this->parent->getData()) {
$pk = $this->parent->getPk(); $pk = $this->parent->getPk();
$table = $this->pivot->getTable(); $table = $this->pivot->getTable();
$this->query->join($table . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk); $this->query->join([$table => 'pivot'], 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);
$this->baseQuery = true; $this->baseQuery = true;
} }
} }
+26 -15
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -24,7 +24,7 @@ class HasMany extends Relation
* @param Model $parent 上级模型对象 * @param Model $parent 上级模型对象
* @param string $model 模型名 * @param string $model 模型名
* @param string $foreignKey 关联外键 * @param string $foreignKey 关联外键
* @param string $localKey 关联主键 * @param string $localKey 当前模型主键
*/ */
public function __construct(Model $parent, $model, $foreignKey, $localKey) public function __construct(Model $parent, $model, $foreignKey, $localKey)
{ {
@@ -77,7 +77,7 @@ class HasMany extends Relation
} }
if (!empty($range)) { if (!empty($range)) {
$data = $this->eagerlyOneToMany($this, [ $data = $this->eagerlyOneToMany($this->query, [
$this->foreignKey => [ $this->foreignKey => [
'in', 'in',
$range, $range,
@@ -114,7 +114,7 @@ class HasMany extends Relation
$localKey = $this->localKey; $localKey = $this->localKey;
if (isset($result->$localKey)) { if (isset($result->$localKey)) {
$data = $this->eagerlyOneToMany($this, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure); $data = $this->eagerlyOneToMany($this->query, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure);
// 关联数据封装 // 关联数据封装
if (!isset($data[$result->$localKey])) { if (!isset($data[$result->$localKey])) {
$data[$result->$localKey] = []; $data[$result->$localKey] = [];
@@ -159,11 +159,11 @@ class HasMany extends Relation
if ($closure) { if ($closure) {
call_user_func_array($closure, [ & $this->query]); call_user_func_array($closure, [ & $this->query]);
} }
$localKey = $this->localKey ?: $this->parent->getPk();
return $this->query->where([ return $this->query->where([
$this->foreignKey => [ $this->foreignKey => [
'exp', 'exp',
'=' . $this->parent->getTable() . '.' . $this->parent->getPk(), '=' . $this->parent->getTable() . '.' . $localKey,
], ],
])->fetchSql()->count(); ])->fetchSql()->count();
} }
@@ -185,7 +185,7 @@ class HasMany extends Relation
if ($closure) { if ($closure) {
call_user_func_array($closure, [ & $model]); call_user_func_array($closure, [ & $model]);
} }
$list = $model->where($where)->with($subRelation)->select(); $list = $model->removeWhereField($foreignKey)->where($where)->with($subRelation)->select();
// 组装模型数据 // 组装模型数据
$data = []; $data = [];
@@ -238,24 +238,31 @@ class HasMany extends Relation
*/ */
public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
{ {
$table = $this->query->getTable(); $table = $this->query->getTable();
return $this->parent->db()->alias('a') $model = basename(str_replace('\\', '/', get_class($this->parent)));
->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $joinType) $relation = basename(str_replace('\\', '/', $this->model));
->group('b.' . $this->foreignKey)
return $this->parent->db()
->alias($model)
->field($model . '.*')
->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType)
->group($relation . '.' . $this->foreignKey)
->having('count(' . $id . ')' . $operator . $count); ->having('count(' . $id . ')' . $operator . $count);
} }
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
$table = $this->query->getTable(); $table = $this->query->getTable();
$model = basename(str_replace('\\', '/', get_class($this->parent))); $model = basename(str_replace('\\', '/', get_class($this->parent)));
$relation = basename(str_replace('\\', '/', $this->model)); $relation = basename(str_replace('\\', '/', $this->model));
if (is_array($where)) { if (is_array($where)) {
foreach ($where as $key => $val) { foreach ($where as $key => $val) {
if (false === strpos($key, '.')) { if (false === strpos($key, '.')) {
@@ -264,9 +271,13 @@ class HasMany extends Relation
} }
} }
} }
$fields = $this->getRelationQueryFields($fields, $model);
return $this->parent->db()->alias($model) return $this->parent->db()->alias($model)
->field($model . '.*') ->field($fields)
->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey) ->group($model . '.' . $this->localKey)
->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey)
->where($where); ->where($where);
} }
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -77,10 +77,11 @@ class HasManyThrough extends Relation
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
throw new Exception('relation not support: hasWhere'); throw new Exception('relation not support: hasWhere');
} }
@@ -92,10 +93,9 @@ class HasManyThrough extends Relation
* @param string $relation 当前关联名 * @param string $relation 当前关联名
* @param string $subRelation 子关联名 * @param string $subRelation 子关联名
* @param \Closure $closure 闭包 * @param \Closure $closure 闭包
* @param string $class 数据集对象名 为空表示数组
* @return void * @return void
*/ */
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class) public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
{} {}
/** /**
@@ -105,10 +105,9 @@ class HasManyThrough extends Relation
* @param string $relation 当前关联名 * @param string $relation 当前关联名
* @param string $subRelation 子关联名 * @param string $subRelation 子关联名
* @param \Closure $closure 闭包 * @param \Closure $closure 闭包
* @param string $class 数据集对象名 为空表示数组
* @return void * @return void
*/ */
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class) public function eagerlyResult(&$result, $relation, $subRelation, $closure)
{} {}
/** /**
+29 -21
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -23,7 +23,7 @@ class HasOne extends OneToOne
* @param Model $parent 上级模型对象 * @param Model $parent 上级模型对象
* @param string $model 模型名 * @param string $model 模型名
* @param string $foreignKey 关联外键 * @param string $foreignKey 关联外键
* @param string $localKey 关联主键 * @param string $localKey 当前模型主键
* @param string $joinType JOIN类型 * @param string $joinType JOIN类型
*/ */
public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER') public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER')
@@ -67,25 +67,30 @@ class HasOne extends OneToOne
public function has() public function has()
{ {
$table = $this->query->getTable(); $table = $this->query->getTable();
$model = basename(str_replace('\\', '/', get_class($this->parent)));
$relation = basename(str_replace('\\', '/', $this->model));
$localKey = $this->localKey; $localKey = $this->localKey;
$foreignKey = $this->foreignKey; $foreignKey = $this->foreignKey;
return $this->parent->db()->alias('a') return $this->parent->db()
->whereExists(function ($query) use ($table, $localKey, $foreignKey) { ->alias($model)
$query->table([$table => 'b'])->field('b.' . $foreignKey)->whereExp('a.' . $localKey, '=b.' . $foreignKey); ->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) {
$query->table([$table => $relation])->field($relation . '.' . $foreignKey)->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey);
}); });
} }
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
$table = $this->query->getTable(); $table = $this->query->getTable();
$model = basename(str_replace('\\', '/', get_class($this->parent))); $model = basename(str_replace('\\', '/', get_class($this->parent)));
$relation = basename(str_replace('\\', '/', $this->model)); $relation = basename(str_replace('\\', '/', $this->model));
if (is_array($where)) { if (is_array($where)) {
foreach ($where as $key => $val) { foreach ($where as $key => $val) {
if (false === strpos($key, '.')) { if (false === strpos($key, '.')) {
@@ -94,9 +99,11 @@ class HasOne extends OneToOne
} }
} }
} }
$fields = $this->getRelationQueryFields($fields, $model);
return $this->parent->db()->alias($model) return $this->parent->db()->alias($model)
->field($model . '.*') ->field($fields)
->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType) ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType)
->where($where); ->where($where);
} }
@@ -140,13 +147,14 @@ class HasOne extends OneToOne
$relationModel = $data[$result->$localKey]; $relationModel = $data[$result->$localKey];
$relationModel->setParent(clone $result); $relationModel->setParent(clone $result);
$relationModel->isUpdate(true); $relationModel->isUpdate(true);
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr);
}
} }
// 设置关联属性 if (!empty($this->bindAttr)) {
$result->setRelation($attr, $relationModel); // 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr);
} else {
// 设置关联属性
$result->setRelation($attr, $relationModel);
}
} }
} }
} }
@@ -173,13 +181,13 @@ class HasOne extends OneToOne
$relationModel = $data[$result->$localKey]; $relationModel = $data[$result->$localKey];
$relationModel->setParent(clone $result); $relationModel->setParent(clone $result);
$relationModel->isUpdate(true); $relationModel->isUpdate(true);
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr);
}
} }
if (!empty($this->bindAttr)) {
$result->setRelation(Loader::parseName($relation), $relationModel); // 绑定关联属性
$this->bindAttr($relationModel, $result, $this->bindAttr);
} else {
$result->setRelation(Loader::parseName($relation), $relationModel);
}
} }
} }
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -82,10 +82,11 @@ class MorphMany extends Relation
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
throw new Exception('relation not support: hasWhere'); throw new Exception('relation not support: hasWhere');
} }
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -81,10 +81,11 @@ class MorphOne extends Relation
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
throw new Exception('relation not support: hasWhere'); throw new Exception('relation not support: hasWhere');
} }
+8 -13
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -82,10 +82,11 @@ class MorphTo extends Relation
/** /**
* 根据关联条件查询当前模型 * 根据关联条件查询当前模型
* @access public * @access public
* @param mixed $where 查询条件(数组或者闭包) * @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @return Query * @return Query
*/ */
public function hasWhere($where = []) public function hasWhere($where = [], $fields = null)
{ {
throw new Exception('relation not support: hasWhere'); throw new Exception('relation not support: hasWhere');
} }
@@ -238,17 +239,18 @@ class MorphTo extends Relation
/** /**
* 添加关联数据 * 添加关联数据
* @access public * @access public
* @param Model $model 关联模型对象 * @param Model $model 关联模型对象
* @param string $type 多态类型
* @return Model * @return Model
*/ */
public function associate($model) public function associate($model, $type = '')
{ {
$morphKey = $this->morphKey; $morphKey = $this->morphKey;
$morphType = $this->morphType; $morphType = $this->morphType;
$pk = $model->getPk(); $pk = $model->getPk();
$this->parent->setAttr($morphKey, $model->$pk); $this->parent->setAttr($morphKey, $model->$pk);
$this->parent->setAttr($morphType, get_class($model)); $this->parent->setAttr($morphType, $type ?: get_class($model));
$this->parent->save(); $this->parent->save();
return $this->parent->setRelation($this->relation, $model); return $this->parent->setRelation($this->relation, $model);
@@ -271,11 +273,4 @@ class MorphTo extends Relation
return $this->parent->setRelation($this->relation, null); return $this->parent->setRelation($this->relation, null);
} }
/**
* 执行基础查询(进执行一次)
* @access protected
* @return void
*/
protected function baseQuery()
{}
} }
+14 -11
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -78,9 +78,9 @@ abstract class OneToOne extends Relation
$query->via($joinAlias); $query->via($joinAlias);
if ($this instanceof BelongsTo) { if ($this instanceof BelongsTo) {
$query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey, $this->joinType); $query->join([$joinTable => $joinAlias], $alias . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey, $this->joinType);
} else { } else {
$query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey, $this->joinType); $query->join([$joinTable => $joinAlias], $alias . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey, $this->joinType);
} }
if ($closure) { if ($closure) {
@@ -214,6 +214,16 @@ abstract class OneToOne extends Relation
return $this; return $this;
} }
/**
* 获取绑定属性
* @access public
* @return array
*/
public function getBindAttr()
{
return $this->bindAttr;
}
/** /**
* 关联统计 * 关联统计
* @access public * @access public
@@ -276,7 +286,7 @@ abstract class OneToOne extends Relation
if (isset($result->$key)) { if (isset($result->$key)) {
throw new Exception('bind attr has exists:' . $key); throw new Exception('bind attr has exists:' . $key);
} else { } else {
$result->setAttr($key, $model->$attr); $result->setAttr($key, $model ? $model->$attr : null);
} }
} }
} }
@@ -311,11 +321,4 @@ abstract class OneToOne extends Relation
return $data; return $data;
} }
/**
* 执行基础查询(进执行一次)
* @access protected
* @return void
*/
protected function baseQuery()
{}
} }
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+6 -2
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -67,7 +67,11 @@ class Redirect extends Response
*/ */
public function getTargetUrl() public function getTargetUrl()
{ {
return strpos($this->data, '://') ? $this->data : Url::build($this->data, $this->params); if (strpos($this->data, '://') || (0 === strpos($this->data, '/') && empty($this->params))) {
return $this->data;
} else {
return Url::build($this->data, $this->params);
}
} }
public function params($params = []) public function params($params = [])
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+8 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -11,6 +11,8 @@
namespace think\response; namespace think\response;
use think\Collection;
use think\Model;
use think\Response; use think\Response;
class Xml extends Response class Xml extends Response
@@ -81,6 +83,11 @@ class Xml extends Response
protected function dataToXml($data, $item, $id) protected function dataToXml($data, $item, $id)
{ {
$xml = $attr = ''; $xml = $attr = '';
if ($data instanceof Collection || $data instanceof Model) {
$data = $data->toArray();
}
foreach ($data as $key => $val) { foreach ($data as $key => $val) {
if (is_numeric($key)) { if (is_numeric($key)) {
$id && $attr = " {$id}=\"{$key}\""; $id && $attr = " {$id}=\"{$key}\"";
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+1 -1
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
+58 -49
View File
@@ -1,5 +1,4 @@
<?php <?php
/** /**
* 用法: * 用法:
* load_trait('controller/Jump'); * load_trait('controller/Jump');
@@ -27,132 +26,142 @@ trait Jump
/** /**
* 操作成功跳转的快捷方法 * 操作成功跳转的快捷方法
* @access protected * @access protected
* @param mixed $msg 提示信息 * @param mixed $msg 提示信息
* @param string $url 跳转的URL地址 * @param string $url 跳转的 URL 地址
* @param mixed $data 返回的数据 * @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间 * @param int $wait 跳转等待时间
* @param array $header 发送的Header信息 * @param array $header 发送的 Header 信息
* @return void * @return void
* @throws HttpResponseException
*/ */
protected function success($msg = '', $url = null, $data = '', $wait = 3, array $header = []) protected function success($msg = '', $url = null, $data = '', $wait = 3, array $header = [])
{ {
$code = 1; if (is_null($url) && !is_null(Request::instance()->server('HTTP_REFERER'))) {
if (is_numeric($msg)) { $url = Request::instance()->server('HTTP_REFERER');
$code = $msg; } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) {
$msg = ''; $url = Url::build($url);
}
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ('' !== $url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url);
} }
$type = $this->getResponseType();
$result = [ $result = [
'code' => $code, 'code' => 1,
'msg' => $msg, 'msg' => $msg,
'data' => $data, 'data' => $data,
'url' => $url, 'url' => $url,
'wait' => $wait, 'wait' => $wait,
]; ];
$type = $this->getResponseType();
if ('html' == strtolower($type)) { if ('html' == strtolower($type)) {
$result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) $template = Config::get('template');
$view = Config::get('view_replace_str');
$result = ViewTemplate::instance($template, $view)
->fetch(Config::get('dispatch_success_tmpl'), $result); ->fetch(Config::get('dispatch_success_tmpl'), $result);
} }
$response = Response::create($result, $type)->header($header); $response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response); throw new HttpResponseException($response);
} }
/** /**
* 操作错误跳转的快捷方法 * 操作错误跳转的快捷方法
* @access protected * @access protected
* @param mixed $msg 提示信息 * @param mixed $msg 提示信息
* @param string $url 跳转的URL地址 * @param string $url 跳转的 URL 地址
* @param mixed $data 返回的数据 * @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间 * @param int $wait 跳转等待时间
* @param array $header 发送的Header信息 * @param array $header 发送的 Header 信息
* @return void * @return void
* @throws HttpResponseException
*/ */
protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = [])
{ {
$code = 0;
if (is_numeric($msg)) {
$code = $msg;
$msg = '';
}
if (is_null($url)) { if (is_null($url)) {
$url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);'; $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);';
} elseif ('' !== $url) { } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url); $url = Url::build($url);
} }
$type = $this->getResponseType();
$result = [ $result = [
'code' => $code, 'code' => 0,
'msg' => $msg, 'msg' => $msg,
'data' => $data, 'data' => $data,
'url' => $url, 'url' => $url,
'wait' => $wait, 'wait' => $wait,
]; ];
$type = $this->getResponseType();
if ('html' == strtolower($type)) { if ('html' == strtolower($type)) {
$result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) $template = Config::get('template');
$view = Config::get('view_replace_str');
$result = ViewTemplate::instance($template, $view)
->fetch(Config::get('dispatch_error_tmpl'), $result); ->fetch(Config::get('dispatch_error_tmpl'), $result);
} }
$response = Response::create($result, $type)->header($header); $response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response); throw new HttpResponseException($response);
} }
/** /**
* 返回封装后的API数据到客户端 * 返回封装后的 API 数据到客户端
* @access protected * @access protected
* @param mixed $data 要返回的数据 * @param mixed $data 要返回的数据
* @param integer $code 返回的code * @param int $code 返回的 code
* @param mixed $msg 提示信息 * @param mixed $msg 提示信息
* @param string $type 返回数据格式 * @param string $type 返回数据格式
* @param array $header 发送的Header信息 * @param array $header 发送的 Header 信息
* @return void * @return void
* @throws HttpResponseException
*/ */
protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) protected function result($data, $code = 0, $msg = '', $type = '', array $header = [])
{ {
$result = [ $result = [
'code' => $code, 'code' => $code,
'msg' => $msg, 'msg' => $msg,
'time' => $_SERVER['REQUEST_TIME'], 'time' => Request::instance()->server('REQUEST_TIME'),
'data' => $data, 'data' => $data,
]; ];
$type = $type ?: $this->getResponseType(); $type = $type ?: $this->getResponseType();
$response = Response::create($result, $type)->header($header); $response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response); throw new HttpResponseException($response);
} }
/** /**
* URL重定向 * URL 重定向
* @access protected * @access protected
* @param string $url 跳转的URL表达式 * @param string $url 跳转的 URL 表达式
* @param array|integer $params 其它URL参数 * @param array|int $params 其它 URL 参数
* @param integer $code http code * @param int $code http code
* @param array $with 隐式传参 * @param array $with 隐式传参
* @return void * @return void
* @throws HttpResponseException
*/ */
protected function redirect($url, $params = [], $code = 302, $with = []) protected function redirect($url, $params = [], $code = 302, $with = [])
{ {
$response = new Redirect($url);
if (is_integer($params)) { if (is_integer($params)) {
$code = $params; $code = $params;
$params = []; $params = [];
} }
$response = new Redirect($url);
$response->code($code)->params($params)->with($with); $response->code($code)->params($params)->with($with);
throw new HttpResponseException($response); throw new HttpResponseException($response);
} }
/** /**
* 获取当前的response 输出类型 * 获取当前的 response 输出类型
* @access protected * @access protected
* @return string * @return string
*/ */
protected function getResponseType() protected function getResponseType()
{ {
$isAjax = Request::instance()->isAjax(); return Request::instance()->isAjax()
return $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); ? Config::get('default_ajax_return')
: Config::get('default_return_type');
} }
} }
+53 -25
View File
@@ -3,10 +3,13 @@
namespace traits\model; namespace traits\model;
use think\db\Query; use think\db\Query;
use think\Model;
/**
* @mixin \Think\Model
*/
trait SoftDelete trait SoftDelete
{ {
/** /**
* 判断当前实例是否被软删除 * 判断当前实例是否被软删除
* @access public * @access public
@@ -15,22 +18,18 @@ trait SoftDelete
public function trashed() public function trashed()
{ {
$field = $this->getDeleteTimeField(); $field = $this->getDeleteTimeField();
if (!empty($this->data[$field])) {
return true; return !empty($this->data[$field]);
}
return false;
} }
/** /**
* 查询软删除数据 * 查询包含软删除数据
* @access public * @access public
* @return Query * @return Query
*/ */
public static function withTrashed() public static function withTrashed()
{ {
$model = new static(); return (new static )->getQuery();
$field = $model->getDeleteTimeField(true);
return $model->getQuery();
} }
/** /**
@@ -42,14 +41,14 @@ trait SoftDelete
{ {
$model = new static(); $model = new static();
$field = $model->getDeleteTimeField(true); $field = $model->getDeleteTimeField(true);
return $model->getQuery()
->useSoftDelete($field, ['not null', '']); return $model->getQuery()->useSoftDelete($field, ['not null', '']);
} }
/** /**
* 删除当前的记录 * 删除当前的记录
* @access public * @access public
* @param bool $force 是否强制删除 * @param bool $force 是否强制删除
* @return integer * @return integer
*/ */
public function delete($force = false) public function delete($force = false)
@@ -57,28 +56,53 @@ trait SoftDelete
if (false === $this->trigger('before_delete', $this)) { if (false === $this->trigger('before_delete', $this)) {
return false; return false;
} }
$name = $this->getDeleteTimeField(); $name = $this->getDeleteTimeField();
if (!$force) { if (!$force) {
// 软删除 // 软删除
$this->data[$name] = $this->autoWriteTimestamp($name); $this->data[$name] = $this->autoWriteTimestamp($name);
$result = $this->isUpdate()->save(); $result = $this->isUpdate()->save();
} else { } else {
$result = $this->getQuery()->delete($this->data); // 强制删除当前模型数据
$result = $this->getQuery()->where($this->getWhere())->delete();
}
// 关联删除
if (!empty($this->relationWrite)) {
foreach ($this->relationWrite as $key => $name) {
$name = is_numeric($key) ? $name : $key;
$result = $this->getRelation($name);
if ($result instanceof Model) {
$result->delete();
} elseif ($result instanceof Collection || is_array($result)) {
foreach ($result as $model) {
$model->delete();
}
}
}
} }
$this->trigger('after_delete', $this); $this->trigger('after_delete', $this);
// 清空原始数据
$this->origin = [];
return $result; return $result;
} }
/** /**
* 删除记录 * 删除记录
* @access public * @access public
* @param mixed $data 主键列表 支持闭包查询条件 * @param mixed $data 主键列表(支持闭包查询条件)
* @param bool $force 是否强制删除 * @param bool $force 是否强制删除
* @return integer 成功删除的记录数 * @return integer 成功删除的记录数
*/ */
public static function destroy($data, $force = false) public static function destroy($data, $force = false)
{ {
if (is_null($data)) {
return 0;
}
// 包含软删除数据 // 包含软删除数据
$query = self::withTrashed(); $query = self::withTrashed();
if (is_array($data) && key($data) !== 0) { if (is_array($data) && key($data) !== 0) {
@@ -87,18 +111,16 @@ trait SoftDelete
} elseif ($data instanceof \Closure) { } elseif ($data instanceof \Closure) {
call_user_func_array($data, [ & $query]); call_user_func_array($data, [ & $query]);
$data = null; $data = null;
} elseif (is_null($data)) {
return 0;
} }
$resultSet = $query->select($data); $count = 0;
$count = 0; if ($resultSet = $query->select($data)) {
if ($resultSet) {
foreach ($resultSet as $data) { foreach ($resultSet as $data) {
$result = $data->delete($force); $result = $data->delete($force);
$count += $result; $count += $result;
} }
} }
return $count; return $count;
} }
@@ -110,11 +132,13 @@ trait SoftDelete
*/ */
public function restore($where = []) public function restore($where = [])
{ {
$name = $this->getDeleteTimeField();
if (empty($where)) { if (empty($where)) {
$pk = $this->getPk(); $pk = $this->getPk();
$where[$pk] = $this->getData($pk); $where[$pk] = $this->getData($pk);
} }
$name = $this->getDeleteTimeField();
// 恢复删除 // 恢复删除
return $this->getQuery() return $this->getQuery()
->useSoftDelete($name, ['not null', '']) ->useSoftDelete($name, ['not null', ''])
@@ -126,30 +150,34 @@ trait SoftDelete
* 查询默认不包含软删除数据 * 查询默认不包含软删除数据
* @access protected * @access protected
* @param Query $query 查询对象 * @param Query $query 查询对象
* @return void * @return Query
*/ */
protected function base($query) protected function base($query)
{ {
$field = $this->getDeleteTimeField(true); return $query->useSoftDelete($this->getDeleteTimeField(true));
$query->useSoftDelete($field);
} }
/** /**
* 获取软删除字段 * 获取软删除字段
* @access public * @access public
* @param bool $read 是否查询操作 写操作的时候会自动去掉表别名 * @param bool $read 是否查询操作(写操作的时候会自动去掉表别名)
* @return string * @return string
*/ */
protected function getDeleteTimeField($read = false) protected function getDeleteTimeField($read = false)
{ {
$field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time'; $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ?
$this->deleteTime :
'delete_time';
if (!strpos($field, '.')) { if (!strpos($field, '.')) {
$field = '__TABLE__.' . $field; $field = '__TABLE__.' . $field;
} }
if (!$read && strpos($field, '.')) { if (!$read && strpos($field, '.')) {
$array = explode('.', $field); $array = explode('.', $field);
$field = array_pop($array); $field = array_pop($array);
} }
return $field; return $field;
} }
} }
+22 -13
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -15,31 +15,40 @@ use think\Exception;
trait Instance trait Instance
{ {
/**
* @var null|static 实例对象
*/
protected static $instance = null; protected static $instance = null;
/** /**
* @param array $options * 获取示例
* @param array $options 实例配置
* @return static * @return static
*/ */
public static function instance($options = []) public static function instance($options = [])
{ {
if (is_null(self::$instance)) { if (is_null(self::$instance)) self::$instance = new self($options);
self::$instance = new self($options);
}
return self::$instance; return self::$instance;
} }
// 静态调用 /**
public static function __callStatic($method, $params) * 静态调用
* @param string $method 调用方法
* @param array $params 调用参数
* @return mixed
* @throws Exception
*/
public static function __callStatic($method, array $params)
{ {
if (is_null(self::$instance)) { if (is_null(self::$instance)) self::$instance = new self();
self::$instance = new self();
}
$call = substr($method, 1); $call = substr($method, 1);
if (0 === strpos($method, '_') && is_callable([self::$instance, $call])) {
return call_user_func_array([self::$instance, $call], $params); if (0 !== strpos($method, '_') || !is_callable([self::$instance, $call])) {
} else {
throw new Exception("method not exists:" . $method); throw new Exception("method not exists:" . $method);
} }
return call_user_func_array([self::$instance, $call], $params);
} }
} }
+4 -3
View File
@@ -2,7 +2,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@@ -12,7 +12,8 @@
namespace think; namespace think;
// ThinkPHP 引导文件 // ThinkPHP 引导文件
// 加载基础文件 // 1. 加载基础文件
require __DIR__ . '/base.php'; require __DIR__ . '/base.php';
// 执行应用
// 2. 执行应用
App::run()->send(); App::run()->send();
+1
View File
@@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<title>跳转提示</title> <title>跳转提示</title>
<style type="text/css"> <style type="text/css">
*{ padding: 0; margin: 0; } *{ padding: 0; margin: 0; }
+1 -1
View File
@@ -319,7 +319,7 @@
<div class="info"> <div class="info">
<div> <div>
<h2>[<?php echo $code; ?>] <?php echo sprintf('%s in %s', parse_class($name), parse_file($file, $line)); ?></h2> <h2>[<?php echo $code; ?>]&nbsp;<?php echo sprintf('%s in %s', parse_class($name), parse_file($file, $line)); ?></h2>
</div> </div>
<div><h1><?php echo nl2br(htmlentities($message)); ?></h1></div> <div><h1><?php echo nl2br(htmlentities($message)); ?></h1></div>
</div> </div>