内核更新
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
define('THINK_VERSION', '5.0.4beta');
|
||||
define('THINK_VERSION', '5.0.5beta');
|
||||
define('THINK_START_TIME', microtime(true));
|
||||
define('THINK_START_MEM', memory_get_usage());
|
||||
define('EXT', '.php');
|
||||
|
||||
@@ -231,39 +231,49 @@ return [
|
||||
|
||||
'database' => [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
'type' => 'mysql',
|
||||
// 数据库连接DSN配置
|
||||
'dsn' => '',
|
||||
'dsn' => '',
|
||||
// 服务器地址
|
||||
'hostname' => 'localhost',
|
||||
'hostname' => '127.0.0.1',
|
||||
// 数据库名
|
||||
'database' => '',
|
||||
'database' => '',
|
||||
// 数据库用户名
|
||||
'username' => 'root',
|
||||
'username' => 'root',
|
||||
// 数据库密码
|
||||
'password' => '',
|
||||
'password' => '',
|
||||
// 数据库连接端口
|
||||
'hostport' => '',
|
||||
'hostport' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => '',
|
||||
'prefix' => '',
|
||||
// 数据库调试模式
|
||||
'debug' => false,
|
||||
'debug' => false,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
// Builder类
|
||||
'builder' => '',
|
||||
// Query类
|
||||
'query' => '\\think\\db\\Query',
|
||||
],
|
||||
|
||||
//分页配置
|
||||
|
||||
@@ -62,4 +62,5 @@ return [
|
||||
'sae mc write error' => 'SAE mc 写入错误',
|
||||
'route name not exists' => '路由标识不存在(或参数不够)',
|
||||
'invalid request' => '非法请求',
|
||||
'bind attr has exists' => '模型的属性已经存在',
|
||||
];
|
||||
|
||||
@@ -11,19 +11,9 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Config;
|
||||
use think\Env;
|
||||
use think\Exception;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\RouteNotFoundException;
|
||||
use think\Hook;
|
||||
use think\Lang;
|
||||
use think\Loader;
|
||||
use think\Log;
|
||||
use think\Request;
|
||||
use think\Response;
|
||||
use think\Route;
|
||||
|
||||
/**
|
||||
* App 应用管理
|
||||
@@ -141,13 +131,13 @@ class App
|
||||
break;
|
||||
case 'controller':
|
||||
// 执行控制器操作
|
||||
$vars = Request::instance()->param();
|
||||
$data = Loader::action($dispatch['controller'], array_merge($vars, $dispatch['var']));
|
||||
$vars = array_merge(Request::instance()->param(), $dispatch['var']);
|
||||
$data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']);
|
||||
break;
|
||||
case 'method':
|
||||
// 执行回调方法
|
||||
$vars = Request::instance()->param();
|
||||
$data = self::invokeMethod($dispatch['method'], array_merge($vars, $dispatch['var']));
|
||||
$vars = array_merge(Request::instance()->param(), $dispatch['var']);
|
||||
$data = self::invokeMethod($dispatch['method'], $vars);
|
||||
break;
|
||||
case 'function':
|
||||
// 执行闭包
|
||||
@@ -257,7 +247,7 @@ class App
|
||||
* 绑定参数
|
||||
* @access public
|
||||
* @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
|
||||
* @param array $vars 变量
|
||||
* @param array $vars 变量
|
||||
* @return array
|
||||
*/
|
||||
private static function bindParams($reflect, $vars = [])
|
||||
@@ -304,8 +294,6 @@ class App
|
||||
throw new \InvalidArgumentException('method param miss:' . $name);
|
||||
}
|
||||
}
|
||||
// 全局过滤
|
||||
array_walk_recursive($args, [Request::instance(), 'filterExp']);
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\cache\Driver;
|
||||
|
||||
class Cache
|
||||
{
|
||||
@@ -31,7 +31,7 @@ class Cache
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @param bool|string $name 缓存连接标识 true 强制重新连接
|
||||
* @return \think\cache\Driver
|
||||
* @return Driver
|
||||
*/
|
||||
public static function connect(array $options = [], $name = false)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ class Cache
|
||||
* 切换缓存类型 需要配置 cache.type 为 complex
|
||||
* @access public
|
||||
* @param string $name 缓存标识
|
||||
* @return \think\cache\Driver
|
||||
* @return Driver
|
||||
*/
|
||||
public static function store($name)
|
||||
{
|
||||
@@ -220,7 +220,7 @@ class Cache
|
||||
* @param string $name 标签名
|
||||
* @param string|array $keys 缓存标识
|
||||
* @param bool $overlay 是否覆盖
|
||||
* @return \think\cache\Driver
|
||||
* @return Driver
|
||||
*/
|
||||
public static function tag($name, $keys = null, $overlay = false)
|
||||
{
|
||||
|
||||
@@ -225,11 +225,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
|
||||
|
||||
$result = [];
|
||||
foreach ($this->items as $row) {
|
||||
$key = $value = null;
|
||||
$key = $value = null;
|
||||
$keySet = $valueSet = false;
|
||||
if (null !== $index_key && array_key_exists($index_key, $row)) {
|
||||
$keySet = true;
|
||||
$key = (string)$row[$index_key];
|
||||
$key = (string) $row[$index_key];
|
||||
}
|
||||
if (null === $column_key) {
|
||||
$valueSet = true;
|
||||
@@ -368,6 +368,6 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
|
||||
if ($items instanceof self) {
|
||||
return $items->all();
|
||||
}
|
||||
return (array)$items;
|
||||
return (array) $items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace think;
|
||||
|
||||
\think\Loader::import('controller/Jump', TRAIT_PATH, EXT);
|
||||
|
||||
use think\Exception;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
class Controller
|
||||
|
||||
@@ -99,6 +99,22 @@ class Cookie
|
||||
$_COOKIE[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 永久保存Cookie数据
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $option 可选参数 可能会是 null|integer|string
|
||||
* @return void
|
||||
*/
|
||||
public static function forever($name, $value = '', $option = null)
|
||||
{
|
||||
if (is_null($option) || is_numeric($option)) {
|
||||
$option = [];
|
||||
}
|
||||
$option['expire'] = 315360000;
|
||||
self::set($name, $value, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断Cookie数据
|
||||
* @param string $name cookie名称
|
||||
@@ -133,7 +149,7 @@ class Cookie
|
||||
}
|
||||
return $value;
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\Collection;
|
||||
use think\db\Connection;
|
||||
use think\db\Query;
|
||||
use think\paginator\Collection as PaginatorCollection;
|
||||
|
||||
@@ -62,7 +61,7 @@ class Db
|
||||
* @access public
|
||||
* @param mixed $config 连接配置
|
||||
* @param bool|string $name 连接标识 true 强制重新连接
|
||||
* @return \think\db\Connection
|
||||
* @return Connection
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function connect($config = [], $name = false)
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Config;
|
||||
use think\exception\ClassNotFoundException;
|
||||
use think\Log;
|
||||
use think\Request;
|
||||
use think\Response;
|
||||
use think\response\Redirect;
|
||||
|
||||
class Debug
|
||||
@@ -178,8 +174,8 @@ class Debug
|
||||
$output = '<pre>' . $label . $output . '</pre>';
|
||||
}
|
||||
if ($echo) {
|
||||
echo ($output);
|
||||
return null;
|
||||
echo($output);
|
||||
return;
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
@@ -12,119 +11,126 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\Debug;
|
||||
use think\Log;
|
||||
|
||||
class Hook
|
||||
{
|
||||
|
||||
private static $tags = [];
|
||||
private static $tags = [];
|
||||
|
||||
/**
|
||||
* 动态添加行为扩展到某个标签
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $behavior 行为名称
|
||||
* @param bool $first 是否放到开头执行
|
||||
* @return void
|
||||
*/
|
||||
public static function add($tag, $behavior, $first = false)
|
||||
{
|
||||
isset(self::$tags[$tag]) || self::$tags[$tag] = [];
|
||||
if (is_array($behavior) && !is_callable($behavior)) {
|
||||
if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = array_merge(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = $behavior;
|
||||
}
|
||||
} elseif ($first) {
|
||||
array_unshift(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
self::$tags[$tag][] = $behavior;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 动态添加行为扩展到某个标签
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $behavior 行为名称
|
||||
* @param bool $first 是否放到开头执行
|
||||
* @return void
|
||||
*/
|
||||
public static function add($tag, $behavior, $first = false)
|
||||
{
|
||||
isset(self::$tags[$tag]) || self::$tags[$tag] = [];
|
||||
if (is_array($behavior) && !is_callable($behavior)) {
|
||||
if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = array_merge(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
unset($behavior['_overlay']);
|
||||
self::$tags[$tag] = $behavior;
|
||||
}
|
||||
} elseif ($first) {
|
||||
array_unshift(self::$tags[$tag], $behavior);
|
||||
} else {
|
||||
self::$tags[$tag][] = $behavior;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入插件
|
||||
* @param array $tags 插件信息
|
||||
* @param boolean $recursive 是否递归合并
|
||||
*/
|
||||
public static function import(array $tags, $recursive = true)
|
||||
{
|
||||
if ($recursive) {
|
||||
foreach ($tags as $tag => $behavior) {
|
||||
self::add($tag, $behavior);
|
||||
}
|
||||
} else {
|
||||
self::$tags = $tags + self::$tags;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 批量导入插件
|
||||
* @param array $tags 插件信息
|
||||
* @param boolean $recursive 是否递归合并
|
||||
*/
|
||||
public static function import(array $tags, $recursive = true)
|
||||
{
|
||||
if ($recursive) {
|
||||
foreach ($tags as $tag => $behavior) {
|
||||
self::add($tag, $behavior);
|
||||
}
|
||||
} else {
|
||||
self::$tags = $tags + self::$tags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件信息
|
||||
* @param string $tag 插件位置 留空获取全部
|
||||
* @return array
|
||||
*/
|
||||
public static function get($tag = '')
|
||||
{
|
||||
if (empty($tag)) {//获取全部的插件信息
|
||||
return self::$tags;
|
||||
} else {
|
||||
return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取插件信息
|
||||
* @param string $tag 插件位置 留空获取全部
|
||||
* @return array
|
||||
*/
|
||||
public static function get($tag = '')
|
||||
{
|
||||
if (empty($tag)) {
|
||||
//获取全部的插件信息
|
||||
return self::$tags;
|
||||
} else {
|
||||
return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听标签的行为
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $params 传入参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @param bool $once 只获取一个有效返回值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function listen($tag, &$params = null, $extra = null, $once = false)
|
||||
{
|
||||
$results = [];
|
||||
$tags = static::get($tag);
|
||||
foreach ($tags as $key => $name) {
|
||||
$results[$key] = self::exec($name, $tag, $params, $extra);
|
||||
if (false === $results[$key]) {// 如果返回false 则中断行为执行
|
||||
break;
|
||||
} elseif (!is_null($results[$key]) && $once) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $once ? end($results) : $results;
|
||||
}
|
||||
/**
|
||||
* 监听标签的行为
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $params 传入参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @param bool $once 只获取一个有效返回值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function listen($tag, &$params = null, $extra = null, $once = false)
|
||||
{
|
||||
$results = [];
|
||||
$tags = static::get($tag);
|
||||
foreach ($tags as $key => $name) {
|
||||
$results[$key] = self::exec($name, $tag, $params, $extra);
|
||||
if (false === $results[$key]) {
|
||||
// 如果返回false 则中断行为执行
|
||||
break;
|
||||
} elseif (!is_null($results[$key]) && $once) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $once ? end($results) : $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行某个行为
|
||||
* @param mixed $class 要执行的行为
|
||||
* @param string $tag 方法名(标签名)
|
||||
* @param Mixed $params 传人的参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exec($class, $tag = '', &$params = null, $extra = null)
|
||||
{
|
||||
App::$debug && Debug::remark('behavior_start', 'time');
|
||||
if (is_callable($class)) {
|
||||
$result = call_user_func_array($class, [ & $params, $extra]);
|
||||
$class = 'Closure';
|
||||
} elseif (is_object($class)) {
|
||||
$result = call_user_func_array([$class, $tag], [ & $params, $extra]);
|
||||
$class = get_class($class);
|
||||
} else {
|
||||
$obj = new $class();
|
||||
$result = ($tag && is_callable([$obj, $tag])) ? $obj->$tag($params, $extra) : $obj->run($params, $extra);
|
||||
}
|
||||
if (App::$debug) {
|
||||
Debug::remark('behavior_end', 'time');
|
||||
Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* 执行某个行为
|
||||
* @param mixed $class 要执行的行为
|
||||
* @param string $tag 方法名(标签名)
|
||||
* @param Mixed $params 传人的参数
|
||||
* @param mixed $extra 额外参数
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exec($class, $tag = '', &$params = null, $extra = null)
|
||||
{
|
||||
App::$debug && Debug::remark('behavior_start', 'time');
|
||||
$method = Loader::parseName($tag, 1, false);
|
||||
if ($class instanceof \Closure) {
|
||||
$result = call_user_func_array($class, [ & $params, $extra]);
|
||||
$class = 'Closure';
|
||||
} elseif (is_array($class)) {
|
||||
list($class, $method) = $class;
|
||||
|
||||
$result = (new $class())->$method($params, $extra);
|
||||
$class = $class . '->' . $method;
|
||||
} elseif (is_object($class)) {
|
||||
$result = $class->$method($params, $extra);
|
||||
$class = get_class($class);
|
||||
} elseif (strpos($class, '::')) {
|
||||
$result = call_user_func_array($class, [ & $params, $extra]);
|
||||
} else {
|
||||
$obj = new $class();
|
||||
$method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
|
||||
$result = $obj->$method($params, $extra);
|
||||
}
|
||||
if (App::$debug) {
|
||||
Debug::remark('behavior_end', 'time');
|
||||
Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\Cookie;
|
||||
use think\Log;
|
||||
|
||||
class Lang
|
||||
{
|
||||
// 语言数据
|
||||
|
||||
@@ -369,12 +369,16 @@ class Loader
|
||||
if (isset(self::$instance[$guid])) {
|
||||
return self::$instance[$guid];
|
||||
}
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name, 2);
|
||||
if (strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name, 2);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
if (class_exists($class)) {
|
||||
$model = new $class();
|
||||
} else {
|
||||
@@ -400,12 +404,16 @@ class Loader
|
||||
*/
|
||||
public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
|
||||
{
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
if (strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
if (class_exists($class)) {
|
||||
return App::invokeClass($class);
|
||||
} elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {
|
||||
@@ -432,12 +440,16 @@ class Loader
|
||||
if (isset(self::$instance[$guid])) {
|
||||
return self::$instance[$guid];
|
||||
}
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
if (strpos($name, '\\')) {
|
||||
$class = $name;
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
if (strpos($name, '/')) {
|
||||
list($module, $name) = explode('/', $name);
|
||||
} else {
|
||||
$module = Request::instance()->module();
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
}
|
||||
$class = self::parseClass($module, $layer, $name, $appendSuffix);
|
||||
if (class_exists($class)) {
|
||||
$validate = new $class;
|
||||
} else {
|
||||
@@ -494,14 +506,16 @@ class Loader
|
||||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||||
* @param string $name 字符串
|
||||
* @param integer $type 转换类型
|
||||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||||
* @return string
|
||||
*/
|
||||
public static function parseName($name, $type = 0)
|
||||
public static function parseName($name, $type = 0, $ucfirst = true)
|
||||
{
|
||||
if ($type) {
|
||||
return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||||
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||||
return strtoupper($match[1]);
|
||||
}, $name));
|
||||
}, $name);
|
||||
return $ucfirst ? ucfirst($name) : lcfirst($name);
|
||||
} else {
|
||||
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
|
||||
}
|
||||
|
||||
@@ -12,14 +12,8 @@
|
||||
namespace think;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use think\Cache;
|
||||
use think\Collection;
|
||||
use think\Config;
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Exception\ValidateException;
|
||||
use think\Loader;
|
||||
use think\model\Relation;
|
||||
use think\model\relation\BelongsTo;
|
||||
use think\model\relation\BelongsToMany;
|
||||
@@ -96,7 +90,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 更新时间字段
|
||||
protected $updateTime = 'update_time';
|
||||
// 时间字段取出后的默认时间格式
|
||||
protected $dateFormat = 'Y-m-d H:i:s';
|
||||
protected $dateFormat;
|
||||
// 字段类型或者格式转换
|
||||
protected $type = [];
|
||||
// 是否为更新数据
|
||||
@@ -151,7 +145,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
if (is_null($this->autoWriteTimestamp)) {
|
||||
// 自动写入时间戳
|
||||
$this->autoWriteTimestamp = $this->db()->getConfig('auto_timestamp');
|
||||
$this->autoWriteTimestamp = $this->db(false)->getConfig('auto_timestamp');
|
||||
}
|
||||
|
||||
if (is_null($this->dateFormat)) {
|
||||
// 设置时间戳格式
|
||||
$this->dateFormat = $this->db(false)->getConfig('datetime_format');
|
||||
}
|
||||
|
||||
// 执行初始化操作
|
||||
@@ -169,13 +168,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$model = $this->class;
|
||||
if (!isset(self::$links[$model])) {
|
||||
// 合并数据库配置
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
if (!empty($this->connection)) {
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
} else {
|
||||
$connection = $this->connection;
|
||||
}
|
||||
} else {
|
||||
$connection = $this->connection;
|
||||
$connection = [];
|
||||
}
|
||||
// 设置当前模型 确保查询返回模型对象
|
||||
$query = Db::connect($connection)->model($model, $this->query);
|
||||
$query = Db::connect($connection)->getQuery($model, $this->query);
|
||||
|
||||
// 设置当前数据表和模型名
|
||||
if (!empty($this->table)) {
|
||||
@@ -319,21 +322,40 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'datetime':
|
||||
case 'date':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = date($format, $_SERVER['REQUEST_TIME']);
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $format);
|
||||
break;
|
||||
case 'timestamp':
|
||||
case 'int':
|
||||
case 'integer':
|
||||
default:
|
||||
$value = $_SERVER['REQUEST_TIME'];
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), ['datetime', 'date', 'timestamp'])) {
|
||||
$value = date($this->dateFormat, $_SERVER['REQUEST_TIME']);
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat);
|
||||
} else {
|
||||
$value = $_SERVER['REQUEST_TIME'];
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat, true);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间日期字段格式化处理
|
||||
* @access public
|
||||
* @param mixed $time 时间日期表达式
|
||||
* @param mixed $format 日期格式
|
||||
* @param bool $timestamp 是否进行时间戳转换
|
||||
* @return mixed
|
||||
*/
|
||||
protected function formatDateTime($time, $format, $timestamp = false)
|
||||
{
|
||||
if (false !== strpos($format, '\\')) {
|
||||
$time = new $format($time);
|
||||
} elseif (!$timestamp) {
|
||||
$time = date($format, $time);
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据写入 类型转换
|
||||
* @access public
|
||||
@@ -369,7 +391,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
break;
|
||||
case 'datetime':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = date($format, is_numeric($value) ? $value : strtotime($value));
|
||||
$value = is_numeric($value) ? $value : strtotime($value);
|
||||
$value = $this->formatDateTime($value, $format);
|
||||
break;
|
||||
case 'object':
|
||||
if (is_object($value)) {
|
||||
@@ -385,6 +408,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'serialize':
|
||||
$value = serialize($value);
|
||||
break;
|
||||
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -414,7 +438,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 类型转换
|
||||
$value = $this->readTransform($value, $this->type[$name]);
|
||||
} elseif ($notFound) {
|
||||
$method = Loader::parseName($name, 1);
|
||||
$method = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $method) && $this->$method() instanceof Relation) {
|
||||
// 不存在该字段 获取关联数据
|
||||
$value = $this->$method()->getRelation();
|
||||
@@ -458,13 +482,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'timestamp':
|
||||
if (!is_null($value)) {
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = date($format, $value);
|
||||
$value = $this->formatDateTime($value, $format);
|
||||
}
|
||||
break;
|
||||
case 'datetime':
|
||||
if (!is_null($value)) {
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = date($format, strtotime($value));
|
||||
$value = $this->formatDateTime(strtotime($value), $format);
|
||||
}
|
||||
break;
|
||||
case 'json':
|
||||
@@ -479,6 +503,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'serialize':
|
||||
$value = unserialize($value);
|
||||
break;
|
||||
default:
|
||||
if (false !== strpos($type, '\\')) {
|
||||
// 对象类型
|
||||
$value = new $type($value);
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -496,6 +525,32 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置附加关联对象的属性
|
||||
* @access public
|
||||
* @param string $relation 关联方法
|
||||
* @param string|array $append 追加属性名
|
||||
* @return $this
|
||||
*/
|
||||
public function appendRelationAttr($relation, $append)
|
||||
{
|
||||
if (is_string($append)) {
|
||||
$append = explode(',', $append);
|
||||
}
|
||||
$model = $this->getAttr($relation);
|
||||
if ($model instanceof Model) {
|
||||
foreach ($append as $key => $attr) {
|
||||
$key = is_numeric($key) ? $attr : $key;
|
||||
if ($this->__isset($key)) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$this->setAttr($key, $model->$attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置需要隐藏的输出属性
|
||||
* @access public
|
||||
@@ -603,10 +658,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function getPk($name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
$table = $this->db()->getTable($name);
|
||||
return $this->db()->getPk($table);
|
||||
$table = $this->db(false)->getTable($name);
|
||||
return $this->db(false)->getPk($table);
|
||||
} elseif (empty($this->pk)) {
|
||||
$this->pk = $this->db()->getPk();
|
||||
$this->pk = $this->db(false)->getPk();
|
||||
}
|
||||
return $this->pk;
|
||||
}
|
||||
@@ -665,7 +720,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$this->autoCompleteData($this->auto);
|
||||
|
||||
// 自动写入更新时间
|
||||
if ($this->autoWriteTimestamp && $this->updateTime) {
|
||||
if ($this->autoWriteTimestamp && $this->updateTime && !isset($this->data[$this->updateTime])) {
|
||||
$this->setAttr($this->updateTime, null);
|
||||
}
|
||||
|
||||
@@ -722,7 +777,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$this->autoCompleteData($this->insert);
|
||||
|
||||
// 自动写入创建时间
|
||||
if ($this->autoWriteTimestamp && $this->createTime) {
|
||||
if ($this->autoWriteTimestamp && $this->createTime && !isset($this->data[$this->createTime])) {
|
||||
$this->setAttr($this->createTime, null);
|
||||
}
|
||||
|
||||
@@ -803,7 +858,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function allowField($field)
|
||||
{
|
||||
if (true === $field) {
|
||||
$field = $this->db()->getTableInfo('', 'fields');
|
||||
$field = $this->db(false)->getTableInfo('', 'fields');
|
||||
}
|
||||
$this->field = $field;
|
||||
return $this;
|
||||
@@ -1156,8 +1211,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public static function useGlobalScope($use)
|
||||
{
|
||||
$model = new static();
|
||||
self::$db = $model->db($use);
|
||||
$model = new static();
|
||||
static::$db = $model->db($use);
|
||||
return $model;
|
||||
}
|
||||
|
||||
@@ -1245,6 +1300,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (strpos($relation, '.')) {
|
||||
list($relation, $subRelation) = explode('.', $relation);
|
||||
}
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$this->$relation()->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $class);
|
||||
}
|
||||
}
|
||||
@@ -1271,10 +1327,34 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (strpos($relation, '.')) {
|
||||
list($relation, $subRelation) = explode('.', $relation);
|
||||
}
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$this->$relation()->eagerlyResult($result, $relation, $subRelation, $closure, $class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string|array $relation 关联名
|
||||
* @return void
|
||||
*/
|
||||
public function relationCount(&$result, $relation)
|
||||
{
|
||||
$relations = is_string($relation) ? explode(',', $relation) : $relation;
|
||||
|
||||
foreach ($relations as $key => $relation) {
|
||||
$closure = false;
|
||||
if ($relation instanceof \Closure) {
|
||||
$closure = $relation;
|
||||
$relation = $key;
|
||||
}
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$count = $this->$relation()->relationCount($result, $closure);
|
||||
$result->setAttr(Loader::parseName($relation) . '_count', $count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HAS ONE 关联定义
|
||||
* @access public
|
||||
@@ -1369,7 +1449,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 记录当前关联信息
|
||||
$model = $this->parseModel($model);
|
||||
$name = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$table = $table ?: $this->db()->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$table = $table ?: $this->db(false)->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$foreignKey = $foreignKey ?: $name . '_id';
|
||||
$localKey = $localKey ?: Loader::parseName($this->name) . '_id';
|
||||
return new BelongsToMany($this, $model, $table, $foreignKey, $localKey, $alias);
|
||||
@@ -1426,7 +1506,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$query = $this->db();
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = $this->db();
|
||||
}
|
||||
|
||||
if (method_exists($this, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
$method = 'scope' . $method;
|
||||
@@ -1441,7 +1527,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public static function __callStatic($method, $params)
|
||||
{
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = (new static())->db();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace think;
|
||||
|
||||
use think\paginator\Collection as PaginatorCollection;
|
||||
use think\Request;
|
||||
|
||||
abstract class Paginator
|
||||
{
|
||||
@@ -42,14 +41,14 @@ abstract class Paginator
|
||||
'var_page' => 'page',
|
||||
'path' => '/',
|
||||
'query' => [],
|
||||
'fragment' => ''
|
||||
'fragment' => '',
|
||||
];
|
||||
|
||||
protected function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
$this->options['path'] = $this->options['path'] != '/' ? rtrim($this->options['path'], '/') : $this->options['path'];
|
||||
$this->options['path'] = '/' != $this->options['path'] ? rtrim($this->options['path'], '/') : $this->options['path'];
|
||||
|
||||
$this->simple = $simple;
|
||||
$this->listRows = $listRows;
|
||||
@@ -63,7 +62,7 @@ abstract class Paginator
|
||||
$items = $items->slice(0, $this->listRows);
|
||||
} else {
|
||||
$this->total = $total;
|
||||
$this->lastPage = (int)ceil($total / $listRows);
|
||||
$this->lastPage = (int) ceil($total / $listRows);
|
||||
$this->currentPage = $this->setCurrentPage($currentPage);
|
||||
$this->hasMore = $this->currentPage < $this->lastPage;
|
||||
}
|
||||
@@ -134,7 +133,7 @@ abstract class Paginator
|
||||
{
|
||||
$page = Request::instance()->request($varPage);
|
||||
|
||||
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int)$page >= 1) {
|
||||
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
|
||||
return $page;
|
||||
}
|
||||
|
||||
@@ -182,7 +181,7 @@ abstract class Paginator
|
||||
*/
|
||||
public function hasPages()
|
||||
{
|
||||
return !($this->currentPage == 1 && !$this->hasMore);
|
||||
return !(1 == $this->currentPage && !$this->hasMore);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +238,6 @@ abstract class Paginator
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构造锚点字符串
|
||||
*
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace think;
|
||||
use think\process\exception\Failed as ProcessFailedException;
|
||||
use think\process\exception\Timeout as ProcessTimeoutException;
|
||||
use think\process\pipes\Pipes;
|
||||
use think\process\Utils;
|
||||
use think\process\pipes\Unix as UnixPipes;
|
||||
use think\process\pipes\Windows as WindowsPipes;
|
||||
use think\process\Utils;
|
||||
|
||||
class Process
|
||||
{
|
||||
@@ -47,10 +47,10 @@ class Process
|
||||
private $exitcode;
|
||||
private $fallbackExitcode;
|
||||
private $processInformation;
|
||||
private $outputDisabled = false;
|
||||
private $outputDisabled = false;
|
||||
private $stdout;
|
||||
private $stderr;
|
||||
private $enhanceWindowsCompatibility = true;
|
||||
private $enhanceWindowsCompatibility = true;
|
||||
private $enhanceSigchildCompatibility;
|
||||
private $process;
|
||||
private $status = self::STATUS_READY;
|
||||
@@ -147,7 +147,7 @@ class Process
|
||||
$this->enhanceSigchildCompatibility = '\\' !== DS && $this->isSigchildEnabled();
|
||||
$this->options = array_replace([
|
||||
'suppress_errors' => true,
|
||||
'binary_pipes' => true
|
||||
'binary_pipes' => true,
|
||||
], $options);
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ class Process
|
||||
public function getExitCodeText()
|
||||
{
|
||||
if (null === $exitcode = $this->getExitCode()) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
|
||||
@@ -586,7 +586,7 @@ class Process
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->status != self::STATUS_READY;
|
||||
return self::STATUS_READY != $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,7 +597,7 @@ class Process
|
||||
{
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->status == self::STATUS_TERMINATED;
|
||||
return self::STATUS_TERMINATED == $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,7 +645,7 @@ class Process
|
||||
* @param string $line
|
||||
*/
|
||||
public function addOutput($line)
|
||||
{
|
||||
{
|
||||
$this->lastOutputTime = microtime(true);
|
||||
$this->stdout .= $line;
|
||||
}
|
||||
@@ -655,7 +655,7 @@ class Process
|
||||
* @param string $line
|
||||
*/
|
||||
public function addErrorOutput($line)
|
||||
{
|
||||
{
|
||||
$this->lastOutputTime = microtime(true);
|
||||
$this->stderr .= $line;
|
||||
}
|
||||
@@ -665,7 +665,7 @@ class Process
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandLine()
|
||||
{
|
||||
{
|
||||
return $this->commandline;
|
||||
}
|
||||
|
||||
@@ -675,7 +675,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setCommandLine($commandline)
|
||||
{
|
||||
{
|
||||
$this->commandline = $commandline;
|
||||
|
||||
return $this;
|
||||
@@ -686,7 +686,7 @@ class Process
|
||||
* @return float|null
|
||||
*/
|
||||
public function getTimeout()
|
||||
{
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ class Process
|
||||
* @return float|null
|
||||
*/
|
||||
public function getIdleTimeout()
|
||||
{
|
||||
{
|
||||
return $this->idleTimeout;
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setTimeout($timeout)
|
||||
{
|
||||
{
|
||||
$this->timeout = $this->validateTimeout($timeout);
|
||||
|
||||
return $this;
|
||||
@@ -717,7 +717,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setIdleTimeout($timeout)
|
||||
{
|
||||
{
|
||||
if (null !== $timeout && $this->outputDisabled) {
|
||||
throw new \LogicException('Idle timeout can not be set while the output is disabled.');
|
||||
}
|
||||
@@ -733,7 +733,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setTty($tty)
|
||||
{
|
||||
{
|
||||
if ('\\' === DS && $tty) {
|
||||
throw new \RuntimeException('TTY mode is not supported on Windows platform.');
|
||||
}
|
||||
@@ -741,7 +741,7 @@ class Process
|
||||
throw new \RuntimeException('TTY mode requires /dev/tty to be readable.');
|
||||
}
|
||||
|
||||
$this->tty = (bool)$tty;
|
||||
$this->tty = (bool) $tty;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -751,7 +751,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
public function isTty()
|
||||
{
|
||||
{
|
||||
return $this->tty;
|
||||
}
|
||||
|
||||
@@ -761,8 +761,8 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setPty($bool)
|
||||
{
|
||||
$this->pty = (bool)$bool;
|
||||
{
|
||||
$this->pty = (bool) $bool;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -772,7 +772,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
public function isPty()
|
||||
{
|
||||
{
|
||||
return $this->pty;
|
||||
}
|
||||
|
||||
@@ -781,7 +781,7 @@ class Process
|
||||
* @return string|null
|
||||
*/
|
||||
public function getWorkingDirectory()
|
||||
{
|
||||
{
|
||||
if (null === $this->cwd) {
|
||||
return getcwd() ?: null;
|
||||
}
|
||||
@@ -795,7 +795,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setWorkingDirectory($cwd)
|
||||
{
|
||||
{
|
||||
$this->cwd = $cwd;
|
||||
|
||||
return $this;
|
||||
@@ -806,7 +806,7 @@ class Process
|
||||
* @return array
|
||||
*/
|
||||
public function getEnv()
|
||||
{
|
||||
{
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
@@ -816,14 +816,14 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setEnv(array $env)
|
||||
{
|
||||
{
|
||||
$env = array_filter($env, function ($value) {
|
||||
return !is_array($value);
|
||||
});
|
||||
|
||||
$this->env = [];
|
||||
foreach ($env as $key => $value) {
|
||||
$this->env[(binary)$key] = (binary)$value;
|
||||
$this->env[(binary) $key] = (binary) $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -834,7 +834,7 @@ class Process
|
||||
* @return null|string
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
@@ -844,7 +844,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
{
|
||||
if ($this->isRunning()) {
|
||||
throw new \LogicException('Input can not be set while the process is running.');
|
||||
}
|
||||
@@ -859,7 +859,7 @@ class Process
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
@@ -869,7 +869,7 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
@@ -880,7 +880,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
public function getEnhanceWindowsCompatibility()
|
||||
{
|
||||
{
|
||||
return $this->enhanceWindowsCompatibility;
|
||||
}
|
||||
|
||||
@@ -890,8 +890,8 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setEnhanceWindowsCompatibility($enhance)
|
||||
{
|
||||
$this->enhanceWindowsCompatibility = (bool)$enhance;
|
||||
{
|
||||
$this->enhanceWindowsCompatibility = (bool) $enhance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -901,7 +901,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
public function getEnhanceSigchildCompatibility()
|
||||
{
|
||||
{
|
||||
return $this->enhanceSigchildCompatibility;
|
||||
}
|
||||
|
||||
@@ -911,8 +911,8 @@ class Process
|
||||
* @return self
|
||||
*/
|
||||
public function setEnhanceSigchildCompatibility($enhance)
|
||||
{
|
||||
$this->enhanceSigchildCompatibility = (bool)$enhance;
|
||||
{
|
||||
$this->enhanceSigchildCompatibility = (bool) $enhance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -921,8 +921,8 @@ class Process
|
||||
* 是否超时
|
||||
*/
|
||||
public function checkTimeout()
|
||||
{
|
||||
if ($this->status !== self::STATUS_STARTED) {
|
||||
{
|
||||
if (self::STATUS_STARTED !== $this->status) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -944,7 +944,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPtySupported()
|
||||
{
|
||||
{
|
||||
static $result;
|
||||
|
||||
if (null !== $result) {
|
||||
@@ -970,7 +970,7 @@ class Process
|
||||
* @return array
|
||||
*/
|
||||
private function getDescriptors()
|
||||
{
|
||||
{
|
||||
if ('\\' === DS) {
|
||||
$this->processPipes = WindowsPipes::create($this, $this->input);
|
||||
} else {
|
||||
@@ -994,7 +994,7 @@ class Process
|
||||
* @return callable
|
||||
*/
|
||||
protected function buildCallback($callback)
|
||||
{
|
||||
{
|
||||
$out = self::OUT;
|
||||
$callback = function ($type, $data) use ($callback, $out) {
|
||||
if ($out == $type) {
|
||||
@@ -1016,7 +1016,7 @@ class Process
|
||||
* @param bool $blocking
|
||||
*/
|
||||
protected function updateStatus($blocking)
|
||||
{
|
||||
{
|
||||
if (self::STATUS_STARTED !== $this->status) {
|
||||
return;
|
||||
}
|
||||
@@ -1036,7 +1036,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSigchildEnabled()
|
||||
{
|
||||
{
|
||||
if (null !== self::$sigchild) {
|
||||
return self::$sigchild;
|
||||
}
|
||||
@@ -1057,8 +1057,8 @@ class Process
|
||||
* @return float|null
|
||||
*/
|
||||
private function validateTimeout($timeout)
|
||||
{
|
||||
$timeout = (float)$timeout;
|
||||
{
|
||||
$timeout = (float) $timeout;
|
||||
|
||||
if (0.0 === $timeout) {
|
||||
$timeout = null;
|
||||
@@ -1075,15 +1075,15 @@ class Process
|
||||
* @param bool $close
|
||||
*/
|
||||
private function readPipes($blocking, $close)
|
||||
{
|
||||
{
|
||||
$result = $this->processPipes->readAndWrite($blocking, $close);
|
||||
|
||||
$callback = $this->callback;
|
||||
foreach ($result as $type => $data) {
|
||||
if (3 == $type) {
|
||||
$this->fallbackExitcode = (int)$data;
|
||||
$this->fallbackExitcode = (int) $data;
|
||||
} else {
|
||||
$callback($type === self::STDOUT ? self::OUT : self::ERR, $data);
|
||||
$callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1092,7 +1092,7 @@ class Process
|
||||
* 捕获退出码
|
||||
*/
|
||||
private function captureExitCode()
|
||||
{
|
||||
{
|
||||
if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {
|
||||
$this->exitcode = $this->processInformation['exitcode'];
|
||||
}
|
||||
@@ -1103,7 +1103,7 @@ class Process
|
||||
* @return int 退出码
|
||||
*/
|
||||
private function close()
|
||||
{
|
||||
{
|
||||
$this->processPipes->close();
|
||||
if (is_resource($this->process)) {
|
||||
$exitcode = proc_close($this->process);
|
||||
@@ -1117,7 +1117,7 @@ class Process
|
||||
if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {
|
||||
$this->exitcode = $this->fallbackExitcode;
|
||||
} elseif (-1 === $this->exitcode && $this->processInformation['signaled']
|
||||
&& 0 < $this->processInformation['termsig']
|
||||
&& 0 < $this->processInformation['termsig']
|
||||
) {
|
||||
$this->exitcode = 128 + $this->processInformation['termsig'];
|
||||
}
|
||||
@@ -1129,7 +1129,7 @@ class Process
|
||||
* 重置数据
|
||||
*/
|
||||
private function resetProcessData()
|
||||
{
|
||||
{
|
||||
$this->starttime = null;
|
||||
$this->callback = null;
|
||||
$this->exitcode = null;
|
||||
@@ -1151,7 +1151,7 @@ class Process
|
||||
* @return bool
|
||||
*/
|
||||
private function doSignal($signal, $throwException)
|
||||
{
|
||||
{
|
||||
if (!$this->isRunning()) {
|
||||
if ($throwException) {
|
||||
throw new \LogicException('Can not send signal on a non running process.');
|
||||
@@ -1186,7 +1186,7 @@ class Process
|
||||
* @param string $functionName
|
||||
*/
|
||||
private function requireProcessIsStarted($functionName)
|
||||
{
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new \LogicException(sprintf('Process must be started before calling %s.', $functionName));
|
||||
}
|
||||
@@ -1197,7 +1197,7 @@ class Process
|
||||
* @param string $functionName
|
||||
*/
|
||||
private function requireProcessIsTerminated($functionName)
|
||||
{
|
||||
{
|
||||
if (!$this->isTerminated()) {
|
||||
throw new \LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
|
||||
}
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Config;
|
||||
use think\Exception;
|
||||
use think\File;
|
||||
use think\Session;
|
||||
|
||||
class Request
|
||||
{
|
||||
/**
|
||||
@@ -25,7 +20,7 @@ class Request
|
||||
|
||||
protected $method;
|
||||
/**
|
||||
* @var string 域名
|
||||
* @var string 域名(含协议和端口)
|
||||
*/
|
||||
protected $domain;
|
||||
|
||||
@@ -226,8 +221,9 @@ class Request
|
||||
if (!isset($info['path'])) {
|
||||
$info['path'] = '/';
|
||||
}
|
||||
$options = [];
|
||||
$queryString = '';
|
||||
$options = [];
|
||||
$options[strtolower($method)] = $params;
|
||||
$queryString = '';
|
||||
if (isset($info['query'])) {
|
||||
parse_str(html_entity_decode($info['query']), $query);
|
||||
if (!empty($params)) {
|
||||
@@ -240,6 +236,11 @@ class Request
|
||||
} elseif (!empty($params)) {
|
||||
$queryString = http_build_query($params, '', '&');
|
||||
}
|
||||
if ($queryString) {
|
||||
parse_str($queryString, $get);
|
||||
$options['get'] = isset($options['get']) ? array_merge($get, $options['get']) : $get;
|
||||
}
|
||||
|
||||
$server['REQUEST_URI'] = $info['path'] . ('' !== $queryString ? '?' . $queryString : '');
|
||||
$server['QUERY_STRING'] = $queryString;
|
||||
$options['cookie'] = $cookie;
|
||||
@@ -257,7 +258,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前包含协议的域名
|
||||
* 设置或获取当前包含协议的域名
|
||||
* @access public
|
||||
* @param string $domain 域名
|
||||
* @return string
|
||||
@@ -274,7 +275,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前完整URL 包括QUERY_STRING
|
||||
* 设置或获取当前完整URL 包括QUERY_STRING
|
||||
* @access public
|
||||
* @param string|true $url URL地址 true 带域名获取
|
||||
* @return string
|
||||
@@ -301,7 +302,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前URL 不含QUERY_STRING
|
||||
* 设置或获取当前URL 不含QUERY_STRING
|
||||
* @access public
|
||||
* @param string $url URL地址
|
||||
* @return string
|
||||
@@ -319,7 +320,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前执行的文件 SCRIPT_NAME
|
||||
* 设置或获取当前执行的文件 SCRIPT_NAME
|
||||
* @access public
|
||||
* @param string $file 当前执行的文件
|
||||
* @return string
|
||||
@@ -351,7 +352,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取URL访问根地址
|
||||
* 设置或获取URL访问根地址
|
||||
* @access public
|
||||
* @param string $url URL地址
|
||||
* @return string
|
||||
@@ -455,7 +456,7 @@ class Request
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
$accept = isset($this->server['HTTP_ACCEPT']) ? $this->server['HTTP_ACCEPT'] : $_SERVER['HTTP_ACCEPT'];
|
||||
$accept = $this->server('HTTP_ACCEPT');
|
||||
if (empty($accept)) {
|
||||
return false;
|
||||
}
|
||||
@@ -602,7 +603,7 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置获取获取当前请求的参数
|
||||
* 获取获取当前请求的参数
|
||||
* @access public
|
||||
* @param string|array $name 变量名
|
||||
* @param mixed $default 默认值
|
||||
@@ -688,7 +689,7 @@ class Request
|
||||
if (empty($this->post)) {
|
||||
$content = $this->input;
|
||||
if (empty($_POST) && strpos($content, '":')) {
|
||||
$this->post = json_decode($content, true);
|
||||
$this->post = (array) json_decode($content, true);
|
||||
} else {
|
||||
$this->post = $_POST;
|
||||
}
|
||||
@@ -713,7 +714,7 @@ class Request
|
||||
if (is_null($this->put)) {
|
||||
$content = $this->input;
|
||||
if (strpos($content, '":')) {
|
||||
$this->put = json_decode($content, true);
|
||||
$this->put = (array) json_decode($content, true);
|
||||
} else {
|
||||
parse_str($content, $this->put);
|
||||
}
|
||||
@@ -885,7 +886,7 @@ class Request
|
||||
return $array[$name];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Cache;
|
||||
use think\Config;
|
||||
use think\Debug;
|
||||
use think\Env;
|
||||
use think\Request;
|
||||
use think\response\Json as JsonResponse;
|
||||
use think\response\Jsonp as JsonpResponse;
|
||||
use think\response\Redirect as RedirectResponse;
|
||||
|
||||
@@ -11,14 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\Config;
|
||||
use think\exception\HttpException;
|
||||
use think\Hook;
|
||||
use think\Loader;
|
||||
use think\Log;
|
||||
use think\Request;
|
||||
use think\Response;
|
||||
|
||||
class Route
|
||||
{
|
||||
@@ -296,12 +289,14 @@ class Route
|
||||
} elseif ('$' == substr($rule, -1, 1)) {
|
||||
// 是否完整匹配
|
||||
$option['complete_match'] = true;
|
||||
$rule = substr($rule, 0, -1);
|
||||
}
|
||||
} elseif (empty($option['complete_match']) && '$' == substr($rule, -1, 1)) {
|
||||
// 是否完整匹配
|
||||
$option['complete_match'] = true;
|
||||
$rule = substr($rule, 0, -1);
|
||||
}
|
||||
|
||||
if ('$' == substr($rule, -1, 1)) {
|
||||
$rule = substr($rule, 0, -1);
|
||||
}
|
||||
|
||||
if ('/' != $rule || $group) {
|
||||
@@ -661,14 +656,14 @@ class Route
|
||||
/**
|
||||
* rest方法定义和修改
|
||||
* @access public
|
||||
* @param string $name 方法名称
|
||||
* @param array $resource 资源
|
||||
* @param string $name 方法名称
|
||||
* @param array|bool $resource 资源
|
||||
* @return void
|
||||
*/
|
||||
public static function rest($name, $resource = [])
|
||||
{
|
||||
if (is_array($name)) {
|
||||
self::$rest = array_merge(self::$rest, $name);
|
||||
self::$rest = $resource ? $name : array_merge(self::$rest, $name);
|
||||
} else {
|
||||
self::$rest[$name] = $resource;
|
||||
}
|
||||
@@ -1493,6 +1488,10 @@ class Route
|
||||
$route = substr($route, 1);
|
||||
list($route, $var) = self::parseUrlPath($route);
|
||||
$result = ['type' => 'controller', 'controller' => implode('/', $route), 'var' => $var];
|
||||
$request->action(array_pop($route));
|
||||
$request->controller($route ? array_pop($route) : Config::get('default_controller'));
|
||||
$request->module($route ? array_pop($route) : Config::get('default_module'));
|
||||
App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : '');
|
||||
} else {
|
||||
// 路由到模块/控制器/操作
|
||||
$result = self::parseModule($route);
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ClassNotFoundException;
|
||||
|
||||
class Session
|
||||
@@ -193,7 +192,7 @@ class Session
|
||||
self::delete($name, $prefix);
|
||||
return $result;
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace think;
|
||||
|
||||
use think\exception\TemplateNotFoundException;
|
||||
use think\Request;
|
||||
|
||||
/**
|
||||
* ThinkPHP分离出来的模板引擎
|
||||
@@ -130,7 +129,7 @@ class Template
|
||||
} elseif (isset($this->config[$config])) {
|
||||
return $this->config[$config];
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +668,7 @@ class Template
|
||||
$content = str_replace($matches[0], '', $content);
|
||||
return explode(',', $matches['name']);
|
||||
}
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1067,6 +1066,8 @@ class Template
|
||||
}
|
||||
if (0 !== strpos($template, '/')) {
|
||||
$template = str_replace(['/', ':'], $this->config['view_depr'], $template);
|
||||
} else {
|
||||
$template = str_replace(['/', ':'], $this->config['view_depr'], substr($template, 1));
|
||||
}
|
||||
if ($this->config['view_base']) {
|
||||
$module = isset($module) ? $module : Request::instance()->module();
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Config;
|
||||
use think\Loader;
|
||||
use think\Request;
|
||||
use think\Route;
|
||||
|
||||
class Url
|
||||
{
|
||||
// 生成URL地址的root
|
||||
@@ -89,7 +84,8 @@ class Url
|
||||
throw new \InvalidArgumentException('route name not exists:' . $name);
|
||||
} else {
|
||||
// 检查别名路由
|
||||
$alias = Route::rules('alias');
|
||||
$alias = Route::rules('alias');
|
||||
$matchAlias = false;
|
||||
if ($alias) {
|
||||
// 别名路由解析
|
||||
foreach ($alias as $key => $val) {
|
||||
@@ -97,11 +93,13 @@ class Url
|
||||
$val = $val[0];
|
||||
}
|
||||
if (0 === strpos($url, $val)) {
|
||||
$url = $key . substr($url, strlen($val));
|
||||
$url = $key . substr($url, strlen($val));
|
||||
$matchAlias = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (!$matchAlias) {
|
||||
// 路由标识不存在 直接解析
|
||||
$url = self::parseUrl($url, $domain);
|
||||
}
|
||||
@@ -250,7 +248,7 @@ class Url
|
||||
$domain .= $rootDomain;
|
||||
}
|
||||
break;
|
||||
} else if (false !== strpos($key, '*')) {
|
||||
} elseif (false !== strpos($key, '*')) {
|
||||
if (!empty($rootDomain)) {
|
||||
$domain .= $rootDomain;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\File;
|
||||
use think\Lang;
|
||||
use think\Request;
|
||||
use think\Session;
|
||||
use think\exception\ClassNotFoundException;
|
||||
|
||||
class Validate
|
||||
{
|
||||
@@ -72,8 +69,8 @@ class Validate
|
||||
'expire' => '不在有效期内 :rule',
|
||||
'allowIp' => '不允许的IP访问',
|
||||
'denyIp' => '禁止的IP访问',
|
||||
'confirm' => ':attribute和字段 :rule 不一致',
|
||||
'different' => ':attribute和字段 :rule 不能相同',
|
||||
'confirm' => ':attribute和确认字段:2不一致',
|
||||
'different' => ':attribute和比较字段:2不能相同',
|
||||
'egt' => ':attribute必须大于等于 :rule',
|
||||
'gt' => ':attribute必须大于 :rule',
|
||||
'elt' => ':attribute必须小于等于 :rule',
|
||||
@@ -317,7 +314,12 @@ class Validate
|
||||
$value = $this->getDataValue($data, $key);
|
||||
|
||||
// 字段验证
|
||||
$result = $this->checkItem($key, $value, $rule, $data, $title, $msg);
|
||||
if ($rule instanceof \Closure) {
|
||||
// 匿名函数验证 支持传入当前字段和所有字段两个数据
|
||||
$result = call_user_func_array($rule, [$value, $data]);
|
||||
} else {
|
||||
$result = $this->checkItem($key, $value, $rule, $data, $title, $msg);
|
||||
}
|
||||
|
||||
if (true !== $result) {
|
||||
// 没有返回true 则表示验证失败
|
||||
@@ -350,73 +352,69 @@ class Validate
|
||||
*/
|
||||
protected function checkItem($field, $value, $rules, $data, $title = '', $msg = [])
|
||||
{
|
||||
if ($rules instanceof \Closure) {
|
||||
// 匿名函数验证 支持传入当前字段和所有字段两个数据
|
||||
$result = call_user_func_array($rules, [$value, $data]);
|
||||
} else {
|
||||
// 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...]
|
||||
if (is_string($rules)) {
|
||||
$rules = explode('|', $rules);
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($rules as $key => $rule) {
|
||||
if ($rule instanceof \Closure) {
|
||||
$result = call_user_func_array($rule, [$value, $data]);
|
||||
} else {
|
||||
// 判断验证类型
|
||||
if (is_numeric($key)) {
|
||||
if (strpos($rule, ':')) {
|
||||
list($type, $rule) = explode(':', $rule, 2);
|
||||
if (isset($this->alias[$type])) {
|
||||
// 判断别名
|
||||
$type = $this->alias[$type];
|
||||
}
|
||||
$info = $type;
|
||||
} elseif (method_exists($this, $rule)) {
|
||||
$type = $rule;
|
||||
$info = $rule;
|
||||
$rule = '';
|
||||
} else {
|
||||
$type = 'is';
|
||||
$info = $rule;
|
||||
}
|
||||
} else {
|
||||
$info = $type = $key;
|
||||
}
|
||||
|
||||
// 如果不是require 有数据才会行验证
|
||||
if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
|
||||
// 验证类型
|
||||
$callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type];
|
||||
// 验证数据
|
||||
$result = call_user_func_array($callback, [$value, $rule, $data, $field]);
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $result) {
|
||||
// 验证失败 返回错误信息
|
||||
if (isset($msg[$i])) {
|
||||
$message = $msg[$i];
|
||||
if (is_string($message) && strpos($message, '{%') === 0) {
|
||||
$message = Lang::get(substr($message, 2, -1));
|
||||
}
|
||||
} else {
|
||||
$message = $this->getRuleMsg($field, $title, $info, $rule);
|
||||
}
|
||||
return $message;
|
||||
} elseif (true !== $result) {
|
||||
// 返回自定义错误信息
|
||||
if (is_string($result) && false !== strpos($result, ':')) {
|
||||
$result = str_replace([':attribute', ':rule'], [$title, (string) $rule], $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
// 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...]
|
||||
if (is_string($rules)) {
|
||||
$rules = explode('|', $rules);
|
||||
}
|
||||
return true !== $result ? $result : true;
|
||||
$i = 0;
|
||||
foreach ($rules as $key => $rule) {
|
||||
if ($rule instanceof \Closure) {
|
||||
$result = call_user_func_array($rule, [$value, $data]);
|
||||
$info = is_numeric($key) ? '' : $key;
|
||||
} else {
|
||||
// 判断验证类型
|
||||
if (is_numeric($key)) {
|
||||
if (strpos($rule, ':')) {
|
||||
list($type, $rule) = explode(':', $rule, 2);
|
||||
if (isset($this->alias[$type])) {
|
||||
// 判断别名
|
||||
$type = $this->alias[$type];
|
||||
}
|
||||
$info = $type;
|
||||
} elseif (method_exists($this, $rule)) {
|
||||
$type = $rule;
|
||||
$info = $rule;
|
||||
$rule = '';
|
||||
} else {
|
||||
$type = 'is';
|
||||
$info = $rule;
|
||||
}
|
||||
} else {
|
||||
$info = $type = $key;
|
||||
}
|
||||
|
||||
// 如果不是require 有数据才会行验证
|
||||
if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
|
||||
// 验证类型
|
||||
$callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type];
|
||||
// 验证数据
|
||||
$result = call_user_func_array($callback, [$value, $rule, $data, $field, $title]);
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $result) {
|
||||
// 验证失败 返回错误信息
|
||||
if (isset($msg[$i])) {
|
||||
$message = $msg[$i];
|
||||
if (is_string($message) && strpos($message, '{%') === 0) {
|
||||
$message = Lang::get(substr($message, 2, -1));
|
||||
}
|
||||
} else {
|
||||
$message = $this->getRuleMsg($field, $title, $info, $rule);
|
||||
}
|
||||
return $message;
|
||||
} elseif (true !== $result) {
|
||||
// 返回自定义错误信息
|
||||
if (is_string($result) && false !== strpos($result, ':')) {
|
||||
$result = str_replace([':attribute', ':rule'], [$title, (string) $rule], $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -811,7 +809,16 @@ class Validate
|
||||
if (is_string($rule)) {
|
||||
$rule = explode(',', $rule);
|
||||
}
|
||||
$db = Db::name($rule[0]);
|
||||
if (false !== strpos($rule[0], '\\')) {
|
||||
// 指定模型类
|
||||
$db = new $rule[0];
|
||||
} else {
|
||||
try {
|
||||
$db = Loader::model($rule[0]);
|
||||
} catch (ClassNotFoundException $e) {
|
||||
$db = Db::name($rule[0]);
|
||||
}
|
||||
}
|
||||
$key = isset($rule[1]) ? $rule[1] : $field;
|
||||
|
||||
if (strpos($key, '^')) {
|
||||
@@ -1201,6 +1208,8 @@ class Validate
|
||||
{
|
||||
if (isset($this->message[$attribute . '.' . $type])) {
|
||||
$msg = $this->message[$attribute . '.' . $type];
|
||||
} elseif (isset($this->message[$attribute][$type])) {
|
||||
$msg = $this->message[$attribute][$type];
|
||||
} elseif (isset($this->message[$attribute])) {
|
||||
$msg = $this->message[$attribute];
|
||||
} elseif (isset(self::$typeMsg[$type])) {
|
||||
@@ -1213,7 +1222,7 @@ class Validate
|
||||
$msg = Lang::get(substr($msg, 2, -1));
|
||||
}
|
||||
|
||||
if (is_string($msg) && false !== strpos($msg, ':')) {
|
||||
if (is_string($msg) && is_string($rule) && false !== strpos($msg, ':')) {
|
||||
// 变量替换
|
||||
if (strpos($rule, ',')) {
|
||||
$array = array_pad(explode(',', $rule), 3, '');
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use think\Loader;
|
||||
use think\Request;
|
||||
|
||||
class View
|
||||
{
|
||||
// 视图实例
|
||||
|
||||
2
core/library/think/cache/Driver.php
vendored
2
core/library/think/cache/Driver.php
vendored
@@ -105,7 +105,7 @@ abstract class Driver
|
||||
$this->rm($name);
|
||||
return $result;
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
core/library/think/cache/driver/Memcache.php
vendored
1
core/library/think/cache/driver/Memcache.php
vendored
@@ -12,7 +12,6 @@
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
use think\Exception;
|
||||
|
||||
class Memcache extends Driver
|
||||
{
|
||||
|
||||
1
core/library/think/cache/driver/Sqlite.php
vendored
1
core/library/think/cache/driver/Sqlite.php
vendored
@@ -12,7 +12,6 @@
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
use think\Exception;
|
||||
|
||||
/**
|
||||
* Sqlite缓存驱动
|
||||
|
||||
3
core/library/think/cache/driver/Wincache.php
vendored
3
core/library/think/cache/driver/Wincache.php
vendored
@@ -12,7 +12,6 @@
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
use think\Exception;
|
||||
|
||||
/**
|
||||
* Wincache缓存驱动
|
||||
@@ -28,7 +27,7 @@ class Wincache extends Driver
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @throws Exception
|
||||
* @throws \BadFunctionCallException
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
|
||||
1
core/library/think/cache/driver/Xcache.php
vendored
1
core/library/think/cache/driver/Xcache.php
vendored
@@ -12,7 +12,6 @@
|
||||
namespace think\cache\driver;
|
||||
|
||||
use think\cache\Driver;
|
||||
use think\Exception;
|
||||
|
||||
/**
|
||||
* Xcache缓存驱动
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
namespace think\db;
|
||||
|
||||
use PDO;
|
||||
use think\Db;
|
||||
use think\db\Connection;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
|
||||
abstract class Builder
|
||||
@@ -118,6 +115,9 @@ abstract class Builder
|
||||
$this->query->bind($key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
|
||||
$result[$item] = ':' . $key;
|
||||
}
|
||||
} elseif (is_object($val) && method_exists($val, '__toString')) {
|
||||
// 对象数据写入
|
||||
$result[$item] = $val->__toString();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
@@ -317,6 +317,11 @@ abstract class Builder
|
||||
}
|
||||
}
|
||||
$bindName = $bindName ?: 'where_' . str_replace('.', '_', $field);
|
||||
if (preg_match('/\W/', $bindName)) {
|
||||
// 处理带非单词字符的字段名
|
||||
$bindName = md5($bindName);
|
||||
}
|
||||
|
||||
$bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;
|
||||
if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {
|
||||
if (strpos($value, ':') !== 0 || !$this->query->isBind(substr($value, 1))) {
|
||||
@@ -702,8 +707,13 @@ abstract class Builder
|
||||
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]);
|
||||
|
||||
@@ -16,7 +16,6 @@ use PDOStatement;
|
||||
use think\Collection;
|
||||
use think\Db;
|
||||
use think\db\exception\BindParamException;
|
||||
use think\db\Query;
|
||||
use think\Debug;
|
||||
use think\Exception;
|
||||
use think\exception\PDOException;
|
||||
@@ -65,47 +64,49 @@ abstract class Connection
|
||||
// 数据库连接参数配置
|
||||
protected $config = [
|
||||
// 数据库类型
|
||||
'type' => '',
|
||||
'type' => '',
|
||||
// 服务器地址
|
||||
'hostname' => '',
|
||||
'hostname' => '',
|
||||
// 数据库名
|
||||
'database' => '',
|
||||
'database' => '',
|
||||
// 用户名
|
||||
'username' => '',
|
||||
'username' => '',
|
||||
// 密码
|
||||
'password' => '',
|
||||
'password' => '',
|
||||
// 端口
|
||||
'hostport' => '',
|
||||
'hostport' => '',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => '',
|
||||
'prefix' => '',
|
||||
// 数据库调试模式
|
||||
'debug' => false,
|
||||
'debug' => false,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
'sql_explain' => false,
|
||||
// Builder类
|
||||
'builder' => '',
|
||||
'builder' => '',
|
||||
// Query类
|
||||
'query' => '\\think\\db\\Query',
|
||||
'query' => '\\think\\db\\Query',
|
||||
];
|
||||
|
||||
// PDO连接参数
|
||||
@@ -136,11 +137,11 @@ abstract class Connection
|
||||
* @param string $queryClass 查询对象类名
|
||||
* @return Query
|
||||
*/
|
||||
public function model($model, $queryClass = '')
|
||||
public function getQuery($model = 'db', $queryClass = '')
|
||||
{
|
||||
if (!isset($this->query[$model])) {
|
||||
$class = $queryClass ?: $this->config['query'];
|
||||
$this->query[$model] = new $class($this, $model);
|
||||
$this->query[$model] = new $class($this, 'db' == $model ? '' : $model);
|
||||
}
|
||||
return $this->query[$model];
|
||||
}
|
||||
@@ -154,11 +155,7 @@ abstract class Connection
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (!isset($this->query['database'])) {
|
||||
$class = $this->config['query'];
|
||||
$this->query['database'] = new $class($this);
|
||||
}
|
||||
return call_user_func_array([$this->query['database'], $method], $args);
|
||||
return call_user_func_array([$this->getQuery(), $method], $args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,6 @@ use think\Cache;
|
||||
use think\Collection;
|
||||
use think\Config;
|
||||
use think\Db;
|
||||
use think\db\Builder;
|
||||
use think\db\Connection;
|
||||
use think\db\exception\BindParamException;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
@@ -27,8 +25,7 @@ use think\exception\PDOException;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\model\Relation;
|
||||
use think\model\relation\BelongsTo;
|
||||
use think\model\relation\HasOne;
|
||||
use think\model\relation\OneToOne;
|
||||
use think\Paginator;
|
||||
|
||||
class Query
|
||||
@@ -1182,7 +1179,14 @@ class Query
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->options['order'] = $field;
|
||||
if (!isset($this->options['order'])) {
|
||||
$this->options['order'] = [];
|
||||
}
|
||||
if (is_array($field)) {
|
||||
$this->options['order'] = array_merge($this->options['order'], $field);
|
||||
} else {
|
||||
$this->options['order'][] = $field;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@@ -1552,7 +1556,7 @@ class Query
|
||||
*/
|
||||
protected function getFieldBindType($type)
|
||||
{
|
||||
if (preg_match('/(int|double|float|decimal|real|numeric|serial)/is', $type)) {
|
||||
if (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) {
|
||||
$bind = PDO::PARAM_INT;
|
||||
} elseif (preg_match('/bool/is', $type)) {
|
||||
$bind = PDO::PARAM_BOOL;
|
||||
@@ -1653,8 +1657,9 @@ class Query
|
||||
}
|
||||
|
||||
/** @var Relation $model */
|
||||
$model = $class->$relation();
|
||||
if ($model instanceof HasOne || $model instanceof BelongsTo) {
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$model = $class->$relation();
|
||||
if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {
|
||||
$model->eagerly($this, $relation, $subRelation, $closure, $first);
|
||||
$first = false;
|
||||
} elseif ($closure) {
|
||||
@@ -1666,6 +1671,36 @@ class Query
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param string|array $relation 关联方法名
|
||||
* @param bool $subQuery 是否使用子查询
|
||||
* @return $this
|
||||
*/
|
||||
public function withCount($relation, $subQuery = true)
|
||||
{
|
||||
if (!$subQuery) {
|
||||
$this->options['with_count'] = $relation;
|
||||
} else {
|
||||
$relations = is_string($relation) ? explode(',', $relation) : $relation;
|
||||
if (!isset($this->options['field'])) {
|
||||
$this->field('*');
|
||||
}
|
||||
foreach ($relations as $key => $relation) {
|
||||
$closure = false;
|
||||
if ($relation instanceof \Closure) {
|
||||
$closure = $relation;
|
||||
$relation = $key;
|
||||
}
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$count = '(' . (new $this->model)->$relation()->getRelationCountQuery($closure) . ')';
|
||||
$this->field([$count => Loader::parseName($relation) . '_count']);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联预加载中 获取关联指定字段值
|
||||
* example:
|
||||
@@ -1997,6 +2032,10 @@ class Query
|
||||
if (!empty($options['relation'])) {
|
||||
$result->relationQuery($options['relation']);
|
||||
}
|
||||
// 关联统计
|
||||
if (!empty($options['with_count'])) {
|
||||
$result->relationCount($result, $options['with_count']);
|
||||
}
|
||||
$resultSet[$key] = $result;
|
||||
}
|
||||
if (!empty($options['with'])) {
|
||||
@@ -2095,10 +2134,14 @@ class Query
|
||||
if (!empty($options['relation'])) {
|
||||
$data->relationQuery($options['relation']);
|
||||
}
|
||||
// 预载入查询
|
||||
if (!empty($options['with'])) {
|
||||
// 预载入
|
||||
$data->eagerlyResult($data, $options['with'], is_object($result) ? get_class($result) : '');
|
||||
}
|
||||
// 关联统计
|
||||
if (!empty($options['with_count'])) {
|
||||
$data->relationCount($data, $options['with_count']);
|
||||
}
|
||||
}
|
||||
} elseif (!empty($options['fail'])) {
|
||||
$this->throwNotFound($options);
|
||||
|
||||
@@ -23,10 +23,10 @@ class DataNotFoundException extends DbException
|
||||
* @param string $table
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($message, $table = '', Array $config = [])
|
||||
public function __construct($message, $table = '', array $config = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->table = $table;
|
||||
$this->message = $message;
|
||||
$this->table = $table;
|
||||
|
||||
$this->setData('Database Config', $config);
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ class ModelNotFoundException extends DbException
|
||||
* @param string $message
|
||||
* @param string $model
|
||||
*/
|
||||
public function __construct($message, $model = '', Array $config = [])
|
||||
public function __construct($message, $model = '', array $config = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->model = $model;
|
||||
$this->message = $message;
|
||||
$this->model = $model;
|
||||
|
||||
$this->setData('Database Config', $config);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace think\exception;
|
||||
|
||||
use think\exception\DbException;
|
||||
|
||||
/**
|
||||
* PDO异常处理类
|
||||
* 重新封装了系统的\PDOException类
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace think\exception;
|
||||
|
||||
use think\exception\HttpException;
|
||||
|
||||
class RouteNotFoundException extends HttpException
|
||||
{
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class File
|
||||
$current_uri = "cmd:" . implode(' ', $_SERVER['argv']);
|
||||
}
|
||||
|
||||
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
||||
$runtime = round(microtime(true) - THINK_START_TIME, 10);
|
||||
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
||||
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
||||
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace think\log\driver;
|
||||
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* github: https://github.com/luofei614/SocketLog
|
||||
* @author luofei614<weibo.com/luofei614>
|
||||
@@ -65,7 +67,7 @@ class Socket
|
||||
}
|
||||
$trace = [];
|
||||
if (App::$debug) {
|
||||
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
||||
$runtime = round(microtime(true) - THINK_START_TIME, 10);
|
||||
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
||||
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
||||
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
||||
@@ -207,19 +209,19 @@ class Socket
|
||||
}
|
||||
|
||||
if (!isset($_SERVER[$key])) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
if (empty($args)) {
|
||||
if (!preg_match('/SocketLog\((.*?)\)/', $_SERVER[$key], $match)) {
|
||||
$args = ['tabid' => null];
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
parse_str($match[1], $args);
|
||||
}
|
||||
if (isset($args[$name])) {
|
||||
return $args[$name];
|
||||
}
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace think\model;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Model;
|
||||
|
||||
class Merge extends Model
|
||||
@@ -168,12 +169,13 @@ class Merge extends Model
|
||||
$this->autoCompleteData($this->auto);
|
||||
|
||||
// 自动写入更新时间
|
||||
if ($this->autoWriteTimestamp && $this->updateTime) {
|
||||
if ($this->autoWriteTimestamp && $this->updateTime && !isset($this->data[$this->updateTime])) {
|
||||
$this->setAttr($this->updateTime, null);
|
||||
}
|
||||
|
||||
$db = $this->db();
|
||||
$db->startTrans();
|
||||
$pk = $this->getPk();
|
||||
try {
|
||||
if ($this->isUpdate) {
|
||||
// 自动写入
|
||||
@@ -187,19 +189,15 @@ class Merge extends Model
|
||||
$where = $this->updateWhere;
|
||||
}
|
||||
|
||||
if (!empty($where)) {
|
||||
$pk = $this->getPk();
|
||||
|
||||
if (isset($this->mapFields[$pk])) {
|
||||
$pk = $this->mapFields[$pk];
|
||||
}
|
||||
if (isset($where[$pk])) {
|
||||
unset($where[$pk]);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理模型数据
|
||||
$data = $this->parseData($this->name, $this->data);
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
$where[$pk] = $data[$pk];
|
||||
}
|
||||
unset($data[$pk]);
|
||||
}
|
||||
// 写入主表数据
|
||||
$result = $db->strict(false)->where($where)->update($data);
|
||||
|
||||
@@ -209,7 +207,7 @@ class Merge extends Model
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $this->data);
|
||||
$query = clone $db;
|
||||
$query = new Query;
|
||||
if ($query->table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||
$result = 1;
|
||||
}
|
||||
@@ -223,7 +221,7 @@ class Merge extends Model
|
||||
$this->autoCompleteData($this->insert);
|
||||
|
||||
// 自动写入创建时间
|
||||
if ($this->autoWriteTimestamp && $this->createTime) {
|
||||
if ($this->autoWriteTimestamp && $this->createTime && !isset($this->data[$this->createTime])) {
|
||||
$this->setAttr($this->createTime, null);
|
||||
}
|
||||
|
||||
@@ -238,7 +236,6 @@ class Merge extends Model
|
||||
if ($result) {
|
||||
$insertId = $db->getLastInsID($sequence);
|
||||
// 写入外键数据
|
||||
$pk = $this->getPk();
|
||||
if ($insertId) {
|
||||
if (is_string($pk)) {
|
||||
$this->data[$pk] = $insertId;
|
||||
@@ -259,7 +256,7 @@ class Merge extends Model
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $source, true);
|
||||
$query = clone $db;
|
||||
$query = new Query;
|
||||
$query->table($table)->strict(false)->insert($data);
|
||||
}
|
||||
}
|
||||
@@ -300,7 +297,7 @@ class Merge extends Model
|
||||
// 删除关联数据
|
||||
foreach ($this->relationModel as $key => $model) {
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
$query = clone $db;
|
||||
$query = new Query;
|
||||
$query->table($table)->where($this->fk, $pk)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Model;
|
||||
use think\model\relation\OneToOne;
|
||||
|
||||
class BelongsTo extends OneToOne
|
||||
{
|
||||
@@ -22,7 +21,7 @@ class BelongsTo extends OneToOne
|
||||
* @param Model $parent 上级模型对象
|
||||
* @param string $model 模型名
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $otherKey 关联主键
|
||||
* @param string $localKey 关联主键
|
||||
* @param array $alias 别名定义
|
||||
* @param string $joinType JOIN类型
|
||||
*/
|
||||
@@ -48,4 +47,80 @@ class BelongsTo extends OneToOne
|
||||
return $this->query->where($localKey, $this->parent->$foreignKey)->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询(数据集)
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$foreignKey)) {
|
||||
$range[] = $result->$foreignKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$this->where[$localKey] = ['in', $range];
|
||||
$data = $this->eagerlyWhere($this, [
|
||||
$localKey => [
|
||||
'in',
|
||||
$range,
|
||||
],
|
||||
], $localKey, $relation, $subRelation, $closure);
|
||||
|
||||
// 关联数据封装
|
||||
foreach ($resultSet as $result) {
|
||||
if (!isset($data[$result->$foreignKey])) {
|
||||
$data[$result->$foreignKey] = [];
|
||||
}
|
||||
$relationModel = $this->resultSetBuild($data[$result->$foreignKey], $class);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($relation, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询(数据)
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
protected function eagerlyOne(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$data = $this->eagerlyWhere($this, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure);
|
||||
// 关联数据封装
|
||||
if (!isset($data[$result->$foreignKey])) {
|
||||
$data[$result->$foreignKey] = [];
|
||||
}
|
||||
$relationModel = $this->resultSetBuild($data[$result->$foreignKey], $class);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($relation, $relationModel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Model;
|
||||
use think\model\Pivot;
|
||||
use think\model\Relation;
|
||||
@@ -128,14 +129,11 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$pk = $result->getPk();
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
// 查询管理数据
|
||||
$data = $this->eagerlyManyToMany(['pivot.' . $localKey => $pk], $relation, $subRelation);
|
||||
$data = $this->eagerlyManyToMany(['pivot.' . $this->localKey => $pk], $relation, $subRelation);
|
||||
|
||||
// 关联数据封装
|
||||
if (!isset($data[$pk])) {
|
||||
@@ -145,6 +143,35 @@ class BelongsToMany extends Relation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{
|
||||
$pk = $result->getPk();
|
||||
$count = 0;
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
$count = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联统计子查询
|
||||
* @access public
|
||||
* @param \Closure $closure 闭包
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationCountQuery($closure)
|
||||
{
|
||||
return $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => ['exp', '=' . $this->parent->getTable() . '.' . $this->parent->getPk()]])->fetchSql()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多对多 关联模型预查询
|
||||
* @access public
|
||||
@@ -155,10 +182,8 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
protected function eagerlyManyToMany($where, $relation, $subRelation = '')
|
||||
{
|
||||
$foreignKey = $this->foreignKey;
|
||||
$localKey = $this->localKey;
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
$list = $this->belongsToManyQuery($this->middle, $foreignKey, $localKey, $where)->with($subRelation)->select();
|
||||
$list = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, $where)->with($subRelation)->select();
|
||||
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
@@ -173,8 +198,8 @@ class BelongsToMany extends Relation
|
||||
}
|
||||
}
|
||||
}
|
||||
$set->pivot = new Pivot($pivot, $this->middle);
|
||||
$data[$pivot[$localKey]][] = $set;
|
||||
$set->pivot = new Pivot($pivot, $this->middle);
|
||||
$data[$pivot[$this->localKey]][] = $set;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
@@ -217,13 +242,19 @@ class BelongsToMany extends Relation
|
||||
* @access public
|
||||
* @param array $dataSet 数据集
|
||||
* @param array $pivot 中间表额外数据
|
||||
* @param bool $samePivot 额外数据是否相同
|
||||
* @return integer
|
||||
*/
|
||||
public function saveAll(array $dataSet, array $pivot = [])
|
||||
public function saveAll(array $dataSet, array $pivot = [], $samePivot = false)
|
||||
{
|
||||
$result = false;
|
||||
foreach ($dataSet as $key => $data) {
|
||||
$result = $this->attach($data, !empty($pivot) ? $pivot[$key] : []);
|
||||
if (!$samePivot) {
|
||||
$pivotData = isset($pivot[$key]) ? $pivot[$key] : [];
|
||||
} else {
|
||||
$pivotData = $pivot;
|
||||
}
|
||||
$result = $this->attach($data, $pivotData);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -238,10 +269,14 @@ class BelongsToMany extends Relation
|
||||
public function attach($data, $pivot = [])
|
||||
{
|
||||
if (is_array($data)) {
|
||||
// 保存关联表数据
|
||||
$model = new $this->model;
|
||||
$model->save($data);
|
||||
$id = $model->getLastInsID();
|
||||
if (key($data) === 0) {
|
||||
$id = $data;
|
||||
} else {
|
||||
// 保存关联表数据
|
||||
$model = new $this->model;
|
||||
$model->save($data);
|
||||
$id = $model->getLastInsID();
|
||||
}
|
||||
} elseif (is_numeric($data) || is_string($data)) {
|
||||
// 根据关联表主键直接写入中间表
|
||||
$id = $data;
|
||||
@@ -253,10 +288,14 @@ class BelongsToMany extends Relation
|
||||
|
||||
if ($id) {
|
||||
// 保存中间表数据
|
||||
$pk = $this->parent->getPk();
|
||||
$pivot[$this->localKey] = $this->parent->$pk;
|
||||
$pivot[$this->foreignKey] = $id;
|
||||
return $this->query->table($this->middle)->insert($pivot);
|
||||
$pk = $this->parent->getPk();
|
||||
$pivot[$this->localKey] = $this->parent->$pk;
|
||||
$ids = (array) $id;
|
||||
foreach ($ids as $id) {
|
||||
$pivot[$this->foreignKey] = $id;
|
||||
$result = $this->query->table($this->middle)->insert($pivot, true);
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
throw new Exception('miss relation data');
|
||||
}
|
||||
|
||||
@@ -58,10 +58,8 @@ class HasMany extends Relation
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$range = [];
|
||||
$localKey = $this->localKey;
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$localKey)) {
|
||||
@@ -70,9 +68,9 @@ class HasMany extends Relation
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$this->where[$foreignKey] = ['in', $range];
|
||||
$data = $this->eagerlyOneToMany($this, [
|
||||
$foreignKey => [
|
||||
$this->where[$this->foreignKey] = ['in', $range];
|
||||
$data = $this->eagerlyOneToMany($this, [
|
||||
$this->foreignKey => [
|
||||
'in',
|
||||
$range,
|
||||
],
|
||||
@@ -100,11 +98,10 @@ class HasMany extends Relation
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$localKey = $this->localKey;
|
||||
|
||||
if (isset($result->$localKey)) {
|
||||
$data = $this->eagerlyOneToMany($this, [$foreignKey => $result->$localKey], $relation, $subRelation, $closure);
|
||||
$data = $this->eagerlyOneToMany($this, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure);
|
||||
// 关联数据封装
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
@@ -113,6 +110,41 @@ class HasMany extends Relation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$count = 0;
|
||||
if (isset($result->$localKey)) {
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$count = $this->query->where([$this->foreignKey => $result->$localKey])->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建关联统计子查询
|
||||
* @access public
|
||||
* @param \Closure $closure 闭包
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationCountQuery($closure)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
|
||||
return $this->query->where([$this->foreignKey => ['exp', '=' . $this->parent->getTable() . '.' . $this->parent->getPk()]])->fetchSql()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* 一对多 关联模型预查询
|
||||
* @access public
|
||||
|
||||
@@ -21,6 +21,8 @@ class HasManyThrough extends Relation
|
||||
{
|
||||
// 中间关联表外键
|
||||
protected $throughKey;
|
||||
// 中间表模型
|
||||
protected $through;
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
@@ -37,7 +39,7 @@ class HasManyThrough extends Relation
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
$this->middle = $through;
|
||||
$this->through = $through;
|
||||
$this->foreignKey = $foreignKey;
|
||||
$this->throughKey = $throughKey;
|
||||
$this->localKey = $localKey;
|
||||
@@ -65,8 +67,7 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 预载入关联查询 返回模型对象
|
||||
@@ -79,8 +80,17 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
@@ -90,7 +100,7 @@ class HasManyThrough extends Relation
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
$through = $this->middle;
|
||||
$through = $this->through;
|
||||
$model = $this->model;
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$throughTable = $through::getTable();
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Model;
|
||||
use think\model\relation\OneToOne;
|
||||
|
||||
class HasOne extends OneToOne
|
||||
{
|
||||
@@ -73,4 +72,80 @@ class HasOne extends OneToOne
|
||||
->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $this->joinType)
|
||||
->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询(数据集)
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$localKey)) {
|
||||
$range[] = $result->$localKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$this->where[$foreignKey] = ['in', $range];
|
||||
$data = $this->eagerlyWhere($this, [
|
||||
$foreignKey => [
|
||||
'in',
|
||||
$range,
|
||||
],
|
||||
], $foreignKey, $relation, $subRelation, $closure);
|
||||
|
||||
// 关联数据封装
|
||||
foreach ($resultSet as $result) {
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$relationModel = $this->resultSetBuild($data[$result->$localKey], $class);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($relation, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询(数据)
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
protected function eagerlyOne(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$data = $this->eagerlyWhere($this, [$foreignKey => $result->$localKey], $foreignKey, $relation, $subRelation, $closure);
|
||||
// 关联数据封装
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$relationModel = $this->resultSetBuild($data[$result->$localKey], $class);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
$result->setAttr($relation, $relationModel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -106,16 +106,48 @@ class MorphMany extends Relation
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
$morphType = $this->morphType;
|
||||
$morphKey = $this->morphKey;
|
||||
$type = $this->type;
|
||||
$pk = $result->getPk();
|
||||
$pk = $result->getPk();
|
||||
if (isset($result->$pk)) {
|
||||
$data = $this->eagerlyMorphToMany([$morphKey => $result->$pk, $morphType => $type], $relation, $subRelation, $closure);
|
||||
$data = $this->eagerlyMorphToMany([$this->morphKey => $result->$pk, $this->morphType => $this->type], $relation, $subRelation, $closure);
|
||||
$result->setAttr($relation, $this->resultSetBuild($data[$result->$pk], $class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{
|
||||
$pk = $result->getPk();
|
||||
$count = 0;
|
||||
if (isset($result->$pk)) {
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$count = $this->query->where([$this->morphKey => $result->$pk, $this->morphType => $this->type])->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联统计子查询
|
||||
* @access public
|
||||
* @param \Closure $closure 闭包
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationCountQuery($closure)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
|
||||
return $this->query->where([$this->morphKey => ['exp', '=' . $this->parent->getTable() . '.' . $this->parent->getPk()], $this->morphType => $this->type])->fetchSql()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多态一对多 关联模型预查询
|
||||
* @access public
|
||||
|
||||
@@ -136,6 +136,16 @@ class MorphTo extends Relation
|
||||
$this->eagerlyMorphToOne($model, $relation, $result, $subRelation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 多态MorphTo 关联模型预查询
|
||||
* @access public
|
||||
|
||||
@@ -12,15 +12,20 @@
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\model\Relation;
|
||||
use think\model\relation\BelongsTo;
|
||||
|
||||
abstract class OneToOne extends Relation
|
||||
{
|
||||
// 预载入方式
|
||||
protected $eagerlyType = 0;
|
||||
// 要绑定的属性
|
||||
protected $bindAttr = [];
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* 预载入关联查询(JOIN方式)
|
||||
* @access public
|
||||
* @param Query $query 查询对象
|
||||
* @param string $relation 关联名
|
||||
@@ -76,7 +81,7 @@ abstract class OneToOne extends Relation
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* 预载入关联查询(数据集)
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
@@ -85,16 +90,21 @@ abstract class OneToOne extends Relation
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation)
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
foreach ($resultSet as $result) {
|
||||
if (1 == $this->eagerlyType) {
|
||||
// IN查询
|
||||
$this->eagerlySet($resultSet, $relation, $subRelation, $closure, $class);
|
||||
} else {
|
||||
// 模型关联组装
|
||||
$this->match($this->model, $relation, $result);
|
||||
foreach ($resultSet as $result) {
|
||||
$this->match($this->model, $relation, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询 返回模型对象
|
||||
* 预载入关联查询(数据)
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
@@ -103,12 +113,81 @@ abstract class OneToOne extends Relation
|
||||
* @param string $class 数据集对象名 为空表示数组
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation)
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
// 模型关联组装
|
||||
$this->match($this->model, $relation, $result);
|
||||
if (1 == $this->eagerlyType) {
|
||||
// IN查询
|
||||
$this->eagerlyOne($result, $relation, $subRelation, $closure, $class);
|
||||
} else {
|
||||
// 模型关联组装
|
||||
$this->match($this->model, $relation, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存(新增)当前关联数据对象
|
||||
* @access public
|
||||
* @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键
|
||||
* @return integer
|
||||
*/
|
||||
public function save($data)
|
||||
{
|
||||
if ($data instanceof Model) {
|
||||
$data = $data->getData();
|
||||
}
|
||||
// 保存关联表数据
|
||||
$data[$this->foreignKey] = $this->parent->{$this->localKey};
|
||||
$model = new $this->model;
|
||||
return $model->save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置预载入方式
|
||||
* @access public
|
||||
* @param integer $type 预载入方式 0 JOIN查询 1 IN查询
|
||||
* @return this
|
||||
*/
|
||||
public function setEagerlyType($type)
|
||||
{
|
||||
$this->eagerlyType = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预载入方式
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getEagerlyType()
|
||||
{
|
||||
return $this->eagerlyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定关联表的属性到父模型属性
|
||||
* @access public
|
||||
* @param mixed $attr 要绑定的属性列表
|
||||
* @return this
|
||||
*/
|
||||
public function bind($attr)
|
||||
{
|
||||
if (is_string($attr)) {
|
||||
$attr = explode(',', $attr);
|
||||
}
|
||||
$this->bindAttr = $attr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 一对一 关联模型预查询拼装
|
||||
* @access public
|
||||
@@ -129,25 +208,60 @@ abstract class OneToOne extends Relation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result->setAttr($relation, !isset($list[$relation]) ? null : (new $model($list[$relation]))->isUpdate(true));
|
||||
if (isset($list[$relation])) {
|
||||
$relationModel = new $model($list[$relation]);
|
||||
if (!empty($this->bindAttr)) {
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
}
|
||||
$result->setAttr($relation, !isset($relationModel) ? null : $relationModel->isUpdate(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存(新增)当前关联数据对象
|
||||
* @access public
|
||||
* @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键
|
||||
* @return integer
|
||||
* 绑定关联属性到父模型
|
||||
* @access protected
|
||||
* @param Model $model 关联模型对象
|
||||
* @param Model $result 父模型对象
|
||||
* @param array $bindAttr 绑定属性
|
||||
* @return void
|
||||
*/
|
||||
public function save($data)
|
||||
protected function bindAttr($model, &$result, $bindAttr)
|
||||
{
|
||||
if ($data instanceof Model) {
|
||||
$data = $data->getData();
|
||||
foreach ($bindAttr as $key => $attr) {
|
||||
$key = is_numeric($key) ? $attr : $key;
|
||||
if (isset($result->$key)) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$result->setAttr($key, $model->$attr);
|
||||
}
|
||||
}
|
||||
// 保存关联表数据
|
||||
$data[$this->foreignKey] = $this->parent->{$this->localKey};
|
||||
$model = new $this->model;
|
||||
return $model->save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一对一 关联模型预查询(IN方式)
|
||||
* @access public
|
||||
* @param object $model 关联模型对象
|
||||
* @param array $where 关联预查询条件
|
||||
* @param string $key 关联键名
|
||||
* @param string $relation 关联名
|
||||
* @param string $subRelation 子关联
|
||||
* @param bool $closure
|
||||
* @return array
|
||||
*/
|
||||
protected function eagerlyWhere($model, $where, $key, $relation, $subRelation = '', $closure = false)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $model]);
|
||||
}
|
||||
$list = $model->where($where)->with($subRelation)->select();
|
||||
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
foreach ($list as $set) {
|
||||
$data[$set->$key][] = $set;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -102,7 +102,6 @@ class Bootstrap extends Paginator
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 渲染分页html
|
||||
* @return mixed
|
||||
@@ -127,7 +126,6 @@ class Bootstrap extends Paginator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成一个可点击的按钮
|
||||
*
|
||||
|
||||
@@ -15,10 +15,9 @@ use think\Process;
|
||||
|
||||
class Builder
|
||||
{
|
||||
|
||||
private $arguments;
|
||||
private $cwd;
|
||||
private $env = null;
|
||||
private $env = null;
|
||||
private $input;
|
||||
private $timeout = 60;
|
||||
private $options = [];
|
||||
@@ -155,7 +154,7 @@ class Builder
|
||||
return $this;
|
||||
}
|
||||
|
||||
$timeout = (float)$timeout;
|
||||
$timeout = (float) $timeout;
|
||||
|
||||
if ($timeout < 0) {
|
||||
throw new \InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
|
||||
|
||||
@@ -60,7 +60,7 @@ class Utils
|
||||
return $input;
|
||||
}
|
||||
if (is_scalar($input)) {
|
||||
return (string)$input;
|
||||
return (string) $input;
|
||||
}
|
||||
throw new \InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
|
||||
}
|
||||
|
||||
42
core/library/think/process/exception/Failed.php
Normal file
42
core/library/think/process/exception/Failed.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\process\exception;
|
||||
|
||||
use think\Process;
|
||||
|
||||
class Failed extends \RuntimeException
|
||||
{
|
||||
|
||||
private $process;
|
||||
|
||||
public function __construct(Process $process)
|
||||
{
|
||||
if ($process->isSuccessful()) {
|
||||
throw new \InvalidArgumentException('Expected a failed process, but the given process was successful.');
|
||||
}
|
||||
|
||||
$error = sprintf('The command "%s" failed.' . "\nExit Code: %s(%s)", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText());
|
||||
|
||||
if (!$process->isOutputDisabled()) {
|
||||
$error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput());
|
||||
}
|
||||
|
||||
parent::__construct($error);
|
||||
|
||||
$this->process = $process;
|
||||
}
|
||||
|
||||
public function getProcess()
|
||||
{
|
||||
return $this->process;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,6 @@ abstract class Pipes
|
||||
*/
|
||||
abstract public function areOpen();
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -25,14 +25,14 @@ class Unix extends Pipes
|
||||
|
||||
public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
|
||||
{
|
||||
$this->ttyMode = (bool)$ttyMode;
|
||||
$this->ptyMode = (bool)$ptyMode;
|
||||
$this->disableOutput = (bool)$disableOutput;
|
||||
$this->ttyMode = (bool) $ttyMode;
|
||||
$this->ptyMode = (bool) $ptyMode;
|
||||
$this->disableOutput = (bool) $disableOutput;
|
||||
|
||||
if (is_resource($input)) {
|
||||
$this->input = $input;
|
||||
} else {
|
||||
$this->inputBuffer = (string)$input;
|
||||
$this->inputBuffer = (string) $input;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +134,12 @@ class Unix extends Pipes
|
||||
|
||||
$type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';
|
||||
$data = '';
|
||||
while ('' !== $dataread = (string)fread($pipe, self::CHUNK_SIZE)) {
|
||||
while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
|
||||
$data .= $dataread;
|
||||
}
|
||||
|
||||
if ('' !== $data) {
|
||||
if ($type === 'input') {
|
||||
if ('input' === $type) {
|
||||
$this->inputBuffer .= $data;
|
||||
} else {
|
||||
$read[$type] = $data;
|
||||
@@ -147,7 +147,7 @@ class Unix extends Pipes
|
||||
}
|
||||
|
||||
if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
|
||||
if ($type === 'input') {
|
||||
if ('input' === $type) {
|
||||
$this->input = null;
|
||||
} else {
|
||||
fclose($this->pipes[$type]);
|
||||
@@ -160,7 +160,7 @@ class Unix extends Pipes
|
||||
while (strlen($this->inputBuffer)) {
|
||||
$written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k
|
||||
if ($written > 0) {
|
||||
$this->inputBuffer = (string)substr($this->inputBuffer, $written);
|
||||
$this->inputBuffer = (string) substr($this->inputBuffer, $written);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ class Unix extends Pipes
|
||||
*/
|
||||
public function areOpen()
|
||||
{
|
||||
return (bool)$this->pipes;
|
||||
return (bool) $this->pipes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class Windows extends Pipes
|
||||
|
||||
public function __construct($disableOutput, $input)
|
||||
{
|
||||
$this->disableOutput = (bool)$disableOutput;
|
||||
$this->disableOutput = (bool) $disableOutput;
|
||||
|
||||
if (!$this->disableOutput) {
|
||||
|
||||
@@ -128,7 +128,7 @@ class Windows extends Pipes
|
||||
*/
|
||||
public function areOpen()
|
||||
{
|
||||
return (bool)$this->pipes && (bool)$this->fileHandles;
|
||||
return (bool) $this->pipes && (bool) $this->fileHandles;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +213,7 @@ class Windows extends Pipes
|
||||
while (strlen($this->inputBuffer)) {
|
||||
$written = fwrite($w[0], $this->inputBuffer, 2 << 18);
|
||||
if ($written > 0) {
|
||||
$this->inputBuffer = (string)substr($this->inputBuffer, $written);
|
||||
$this->inputBuffer = (string) substr($this->inputBuffer, $written);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class Memcache extends SessionHandler
|
||||
*/
|
||||
public function read($sessID)
|
||||
{
|
||||
return $this->handler->get($this->config['session_name'] . $sessID);
|
||||
return (string) $this->handler->get($this->config['session_name'] . $sessID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,7 +87,7 @@ class Memcached extends SessionHandler
|
||||
*/
|
||||
public function read($sessID)
|
||||
{
|
||||
return $this->handler->get($this->config['session_name'] . $sessID);
|
||||
return (string) $this->handler->get($this->config['session_name'] . $sessID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,11 +81,11 @@ class Redis extends SessionHandler
|
||||
* 读取Session
|
||||
* @access public
|
||||
* @param string $sessID
|
||||
* @return bool|string
|
||||
* @return string
|
||||
*/
|
||||
public function read($sessID)
|
||||
{
|
||||
return $this->handler->get($this->config['session_name'] . $sessID);
|
||||
return (string) $this->handler->get($this->config['session_name'] . $sessID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -620,8 +620,8 @@ class Cx extends Taglib
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* U函数的tag标签
|
||||
/**
|
||||
* url函数的tag标签
|
||||
* 格式:{url link="模块/控制器/方法" vars="参数" suffix="true或者false 是否带有后缀" domain="true或者false 是否携带域名" /}
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
|
||||
@@ -127,17 +127,18 @@ class Php
|
||||
|
||||
$depr = $this->config['view_depr'];
|
||||
if (0 !== strpos($template, '/')) {
|
||||
$template = str_replace(['/', ':'], $depr, $template);
|
||||
}
|
||||
|
||||
$controller = Loader::parseName($request->controller());
|
||||
if ($controller) {
|
||||
if ('' == $template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = str_replace('.', DS, $controller) . $depr . $request->action();
|
||||
} elseif (false === strpos($template, $depr)) {
|
||||
$template = str_replace('.', DS, $controller) . $depr . $template;
|
||||
$template = str_replace(['/', ':'], $depr, $template);
|
||||
$controller = Loader::parseName($request->controller());
|
||||
if ($controller) {
|
||||
if ('' == $template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = str_replace('.', DS, $controller) . $depr . $request->action();
|
||||
} elseif (false === strpos($template, $depr)) {
|
||||
$template = str_replace('.', DS, $controller) . $depr . $template;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$template = str_replace(['/', ':'], $depr, substr($template, 1));
|
||||
}
|
||||
return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');
|
||||
}
|
||||
|
||||
@@ -120,18 +120,20 @@ class Think
|
||||
$path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path'];
|
||||
}
|
||||
|
||||
$controller = Loader::parseName($request->controller());
|
||||
$depr = $this->config['view_depr'];
|
||||
$depr = $this->config['view_depr'];
|
||||
if (0 !== strpos($template, '/')) {
|
||||
$template = str_replace(['/', ':'], $depr, $template);
|
||||
}
|
||||
if ($controller) {
|
||||
if ('' == $template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = str_replace('.', DS, $controller) . $depr . $request->action();
|
||||
} elseif (false === strpos($template, $depr)) {
|
||||
$template = str_replace('.', DS, $controller) . $depr . $template;
|
||||
$template = str_replace(['/', ':'], $depr, $template);
|
||||
$controller = Loader::parseName($request->controller());
|
||||
if ($controller) {
|
||||
if ('' == $template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = str_replace('.', DS, $controller) . $depr . $request->action();
|
||||
} elseif (false === strpos($template, $depr)) {
|
||||
$template = str_replace('.', DS, $controller) . $depr . $template;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$template = str_replace(['/', ':'], $depr, substr($template, 1));
|
||||
}
|
||||
return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace traits\model;
|
||||
|
||||
use think\db\Query;
|
||||
|
||||
trait SoftDelete
|
||||
{
|
||||
|
||||
@@ -22,7 +24,7 @@ trait SoftDelete
|
||||
/**
|
||||
* 查询软删除数据
|
||||
* @access public
|
||||
* @return \think\db\Query
|
||||
* @return Query
|
||||
*/
|
||||
public static function withTrashed()
|
||||
{
|
||||
@@ -34,7 +36,7 @@ trait SoftDelete
|
||||
/**
|
||||
* 只查询软删除数据
|
||||
* @access public
|
||||
* @return \think\db\Query
|
||||
* @return Query
|
||||
*/
|
||||
public static function onlyTrashed()
|
||||
{
|
||||
@@ -77,8 +79,8 @@ trait SoftDelete
|
||||
*/
|
||||
public static function destroy($data, $force = false)
|
||||
{
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
// 包含软删除数据
|
||||
$query = self::withTrashed();
|
||||
if (is_array($data) && key($data) !== 0) {
|
||||
$query->where($data);
|
||||
$data = null;
|
||||
@@ -109,15 +111,19 @@ trait SoftDelete
|
||||
public function restore($where = [])
|
||||
{
|
||||
$name = $this->getDeleteTimeField();
|
||||
if (empty($where)) {
|
||||
$pk = $this->getPk();
|
||||
$where[$pk] = $this->getData($pk);
|
||||
$where[$name] = ['not null', ''];
|
||||
}
|
||||
// 恢复删除
|
||||
return $this->isUpdate()->save([$name => null], $where);
|
||||
|
||||
return $this->db(false)->removeWhereField($this->getDeleteTimeField(true))->where($where)->update([$name => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询默认不包含软删除数据
|
||||
* @access protected
|
||||
* @param \think\db\Query $query 查询对象
|
||||
* @param Query $query 查询对象
|
||||
* @return void
|
||||
*/
|
||||
protected function base($query)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace traits\think;
|
||||
|
||||
use \think\Exception;
|
||||
use think\Exception;
|
||||
|
||||
trait Instance
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user