内核更新

This commit is contained in:
2016-12-28 10:41:09 +08:00
parent c89254e12a
commit ffab826db0
65 changed files with 1194 additions and 610 deletions

View File

@@ -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');

View File

@@ -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',
],
//分页配置

View File

@@ -62,4 +62,5 @@ return [
'sae mc write error' => 'SAE mc 写入错误',
'route name not exists' => '路由标识不存在(或参数不够)',
'invalid request' => '非法请求',
'bind attr has exists' => '模型的属性已经存在',
];

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;
}
}

View File

@@ -13,7 +13,6 @@ namespace think;
\think\Loader::import('controller/Jump', TRAIT_PATH, EXT);
use think\Exception;
use think\exception\ValidateException;
class Controller

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -11,10 +11,6 @@
namespace think;
use think\App;
use think\Cookie;
use think\Log;
class Lang
{
// 语言数据

View File

@@ -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), "_"));
}

View File

@@ -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();
}

View File

@@ -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;
}
/**
* 构造锚点字符串
*
@@ -255,4 +253,4 @@ abstract class Paginator
* @return mixed
*/
abstract public function render();
}
}

View File

@@ -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,9 +1197,9 @@ class Process
* @param string $functionName
*/
private function requireProcessIsTerminated($functionName)
{
{
if (!$this->isTerminated()) {
throw new \LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
}
}
}
}

View File

@@ -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;
}
/**

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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, '');

View File

@@ -11,9 +11,6 @@
namespace think;
use think\Loader;
use think\Request;
class View
{
// 视图实例

View File

@@ -105,7 +105,7 @@ abstract class Driver
$this->rm($name);
return $result;
} else {
return null;
return;
}
}

View File

@@ -12,7 +12,6 @@
namespace think\cache\driver;
use think\cache\Driver;
use think\Exception;
class Memcache extends Driver
{

View File

@@ -12,7 +12,6 @@
namespace think\cache\driver;
use think\cache\Driver;
use think\Exception;
/**
* Sqlite缓存驱动

View File

@@ -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 = [])

View File

@@ -12,7 +12,6 @@
namespace think\cache\driver;
use think\cache\Driver;
use think\Exception;
/**
* Xcache缓存驱动

View File

@@ -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]);

View File

@@ -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);
}
/**

View File

@@ -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);

View File

@@ -16,7 +16,7 @@ use think\exception\DbException;
/**
* PDO参数绑定异常
*/
class BindParamException extends DbException
class BindParamException extends DbException
{
/**

View File

@@ -13,7 +13,7 @@ namespace think\db\exception;
use think\exception\DbException;
class DataNotFoundException extends DbException
class DataNotFoundException extends DbException
{
protected $table;
@@ -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);
}

View File

@@ -13,7 +13,7 @@ namespace think\db\exception;
use think\exception\DbException;
class ModelNotFoundException extends DbException
class ModelNotFoundException extends DbException
{
protected $model;
@@ -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);
}

View File

@@ -11,8 +11,6 @@
namespace think\exception;
use think\exception\DbException;
/**
* PDO异常处理类
* 重新封装了系统的\PDOException类

View File

@@ -11,8 +11,6 @@
namespace think\exception;
use think\exception\HttpException;
class RouteNotFoundException extends HttpException
{

View File

@@ -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);

View File

@@ -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;
}
/**

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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');
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
/**

View File

@@ -71,4 +71,4 @@ class Collection extends \think\Collection
throw new Exception('method not exists:' . __CLASS__ . '->' . $method);
}
}
}
}

View File

@@ -102,7 +102,6 @@ class Bootstrap extends Paginator
return $html;
}
/**
* 渲染分页html
* @return mixed
@@ -127,7 +126,6 @@ class Bootstrap extends Paginator
}
}
/**
* 生成一个可点击的按钮
*
@@ -204,4 +202,4 @@ class Bootstrap extends Paginator
return $this->getAvailablePageWrapper($url, $page);
}
}
}

View File

@@ -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.');
@@ -231,4 +230,4 @@ class Builder
return $process;
}
}
}

View File

@@ -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));
}
@@ -72,4 +72,4 @@ class Utils
return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
}
}
}

View 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;
}
}

View File

@@ -58,4 +58,4 @@ class Timeout extends \RuntimeException
throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
}
}
}
}

View File

@@ -53,7 +53,6 @@ abstract class Pipes
*/
abstract public function areOpen();
/**
* {@inheritdoc}
*/
@@ -91,4 +90,4 @@ abstract class Pipes
$this->blocked = false;
}
}
}

View File

@@ -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;
}
/**
@@ -193,4 +193,4 @@ class Unix extends Pipes
{
return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
}
}
}

View File

@@ -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;
}
@@ -225,4 +225,4 @@ class Windows extends Pipes
unset($this->pipes[0]);
}
}
}
}

View File

@@ -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);
}
/**

View File

@@ -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);
}
/**

View File

@@ -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);
}
/**

View File

@@ -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 标签属性

View File

@@ -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'], '.');
}

View File

@@ -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'], '.');
}

View File

@@ -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)

View File

@@ -11,7 +11,7 @@
namespace traits\think;
use \think\Exception;
use think\Exception;
trait Instance
{