更新内核,API接口开发的一些尝试,后期会增加API接口开发这块
This commit is contained in:
15
application/api/controller/AccessToken.php
Normal file
15
application/api/controller/AccessToken.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\api\controller;
|
||||
use api\BaseAuth;
|
||||
|
||||
class AccessToken extends BaseAuth {
|
||||
|
||||
}
|
||||
26
application/api/controller/Base.php
Normal file
26
application/api/controller/Base.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\api\controller;
|
||||
use api\BaseRest;
|
||||
|
||||
class Base extends BaseRest {
|
||||
|
||||
// 允许访问的请求类型
|
||||
protected $restMethodList = 'get|post|put|delete|patch|head|options';
|
||||
//业务错误码的映射表
|
||||
public $errMap = [
|
||||
0 => 'success', //没有错误
|
||||
1001 => '参数错误',
|
||||
9999 => '自定义错误', //让程序给出的自定义错误
|
||||
];
|
||||
|
||||
//是否开启权限认证
|
||||
public $apiAuth = true;
|
||||
}
|
||||
@@ -8,10 +8,30 @@
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\api\controller;
|
||||
use app\common\controller\User;
|
||||
|
||||
class Index extends Api{
|
||||
use think\Request;
|
||||
|
||||
public function index(){
|
||||
class Index extends Base {
|
||||
|
||||
public $apiAuth = true;
|
||||
// 允许访问的请求类型
|
||||
protected $restMethodList = 'get|post|';
|
||||
|
||||
/**
|
||||
* get的响应
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResponse(Request $request) {
|
||||
return $this->sendError(1001, 'THIS IS GET', 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* post的响应
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function postResponse(Request $request) {
|
||||
return $this->sendSuccess('THIS IS POST');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
define('THINK_VERSION', '5.0.7');
|
||||
define('THINK_VERSION', '5.0.9');
|
||||
define('THINK_START_TIME', microtime(true));
|
||||
define('THINK_START_MEM', memory_get_usage());
|
||||
define('EXT', '.php');
|
||||
|
||||
@@ -5,8 +5,6 @@ return [
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用命名空间
|
||||
'app_namespace' => 'app',
|
||||
// 应用调试模式
|
||||
'app_debug' => true,
|
||||
// 应用Trace
|
||||
@@ -91,6 +89,8 @@ return [
|
||||
'url_route_must' => false,
|
||||
// 域名部署
|
||||
'url_domain_deploy' => false,
|
||||
// 默认Host地址
|
||||
'default_host' => '',
|
||||
// 域名根,如thinkphp.cn
|
||||
'url_domain_root' => '',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
|
||||
@@ -192,7 +192,7 @@ if (!function_exists('db')) {
|
||||
* @param bool $force 是否强制重新连接
|
||||
* @return \think\db\Query
|
||||
*/
|
||||
function db($name = '', $config = [], $force = true)
|
||||
function db($name = '', $config = [], $force = false)
|
||||
{
|
||||
return Db::connect($config, $force)->name($name);
|
||||
}
|
||||
@@ -354,22 +354,25 @@ if (!function_exists('cache')) {
|
||||
{
|
||||
if (is_array($options)) {
|
||||
// 缓存操作的同时初始化
|
||||
Cache::connect($options);
|
||||
$cache = Cache::connect($options);
|
||||
} elseif (is_array($name)) {
|
||||
// 缓存初始化
|
||||
return Cache::connect($name);
|
||||
} else {
|
||||
$cache = Cache::init();
|
||||
}
|
||||
|
||||
if (is_null($name)) {
|
||||
return Cache::clear($value);
|
||||
return $cache->clear($value);
|
||||
} elseif ('' === $value) {
|
||||
// 获取缓存
|
||||
return 0 === strpos($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name);
|
||||
return 0 === strpos($name, '?') ? $cache->has(substr($name, 1)) : $cache->get($name);
|
||||
} elseif (is_null($value)) {
|
||||
// 删除缓存
|
||||
return Cache::rm($name);
|
||||
return $cache->rm($name);
|
||||
} elseif (0 === strpos($name, '?') && '' !== $value) {
|
||||
$expire = is_numeric($options) ? $options : null;
|
||||
return Cache::remember(substr($name, 1), $value, $expire);
|
||||
return $cache->remember(substr($name, 1), $value, $expire);
|
||||
} else {
|
||||
// 缓存数据
|
||||
if (is_array($options)) {
|
||||
@@ -378,9 +381,9 @@ if (!function_exists('cache')) {
|
||||
$expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
|
||||
}
|
||||
if (is_null($tag)) {
|
||||
return Cache::set($name, $value, $expire);
|
||||
return $cache->set($name, $value, $expire);
|
||||
} else {
|
||||
return Cache::tag($tag)->set($name, $value, $expire);
|
||||
return $cache->tag($tag)->set($name, $value, $expire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +414,11 @@ class App
|
||||
public static function initCommon()
|
||||
{
|
||||
if (empty(self::$init)) {
|
||||
if (defined('APP_NAMESPACE')) {
|
||||
self::$namespace = APP_NAMESPACE;
|
||||
}
|
||||
Loader::addNamespace(self::$namespace, APP_PATH);
|
||||
|
||||
// 初始化应用
|
||||
$config = self::init();
|
||||
self::$suffix = $config['class_suffix'];
|
||||
@@ -433,9 +438,6 @@ class App
|
||||
}
|
||||
}
|
||||
|
||||
// 注册应用命名空间
|
||||
self::$namespace = $config['app_namespace'];
|
||||
Loader::addNamespace($config['app_namespace'], APP_PATH);
|
||||
if (!empty($config['root_namespace'])) {
|
||||
Loader::addNamespace($config['root_namespace']);
|
||||
}
|
||||
|
||||
@@ -51,28 +51,29 @@ class Cache
|
||||
self::$instance[$name] = new $class($options);
|
||||
}
|
||||
}
|
||||
self::$handler = self::$instance[$name];
|
||||
return self::$handler;
|
||||
return self::$instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动初始化缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @return void
|
||||
* @return Driver
|
||||
*/
|
||||
public static function init(array $options = [])
|
||||
{
|
||||
if (is_null(self::$handler)) {
|
||||
// 自动初始化缓存
|
||||
if (!empty($options)) {
|
||||
self::connect($options);
|
||||
$connect = self::connect($options);
|
||||
} elseif ('complex' == Config::get('cache.type')) {
|
||||
self::connect(Config::get('cache.default'));
|
||||
$connect = self::connect(Config::get('cache.default'));
|
||||
} else {
|
||||
self::connect(Config::get('cache'));
|
||||
$connect = self::connect(Config::get('cache'));
|
||||
}
|
||||
self::$handler = $connect;
|
||||
}
|
||||
return self::$handler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,9 +85,9 @@ class Cache
|
||||
public static function store($name = '')
|
||||
{
|
||||
if ('' !== $name && 'complex' == Config::get('cache.type')) {
|
||||
self::connect(Config::get('cache.' . $name), strtolower($name));
|
||||
return self::connect(Config::get('cache.' . $name), strtolower($name));
|
||||
}
|
||||
return self::$handler;
|
||||
return self::init();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,9 +98,8 @@ class Cache
|
||||
*/
|
||||
public static function has($name)
|
||||
{
|
||||
self::init();
|
||||
self::$readTimes++;
|
||||
return self::$handler->has($name);
|
||||
return self::init()->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,9 +111,8 @@ class Cache
|
||||
*/
|
||||
public static function get($name, $default = false)
|
||||
{
|
||||
self::init();
|
||||
self::$readTimes++;
|
||||
return self::$handler->get($name, $default);
|
||||
return self::init()->get($name, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,9 +125,8 @@ class Cache
|
||||
*/
|
||||
public static function set($name, $value, $expire = null)
|
||||
{
|
||||
self::init();
|
||||
self::$writeTimes++;
|
||||
return self::$handler->set($name, $value, $expire);
|
||||
return self::init()->set($name, $value, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,9 +138,8 @@ class Cache
|
||||
*/
|
||||
public static function inc($name, $step = 1)
|
||||
{
|
||||
self::init();
|
||||
self::$writeTimes++;
|
||||
return self::$handler->inc($name, $step);
|
||||
return self::init()->inc($name, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,9 +151,8 @@ class Cache
|
||||
*/
|
||||
public static function dec($name, $step = 1)
|
||||
{
|
||||
self::init();
|
||||
self::$writeTimes++;
|
||||
return self::$handler->dec($name, $step);
|
||||
return self::init()->dec($name, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,9 +163,8 @@ class Cache
|
||||
*/
|
||||
public static function rm($name)
|
||||
{
|
||||
self::init();
|
||||
self::$writeTimes++;
|
||||
return self::$handler->rm($name);
|
||||
return self::init()->rm($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,9 +175,8 @@ class Cache
|
||||
*/
|
||||
public static function clear($tag = null)
|
||||
{
|
||||
self::init();
|
||||
self::$writeTimes++;
|
||||
return self::$handler->clear($tag);
|
||||
return self::init()->clear($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,10 +187,9 @@ class Cache
|
||||
*/
|
||||
public static function pull($name)
|
||||
{
|
||||
self::init();
|
||||
self::$readTimes++;
|
||||
self::$writeTimes++;
|
||||
return self::$handler->pull($name);
|
||||
return self::init()->pull($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,9 +202,8 @@ class Cache
|
||||
*/
|
||||
public static function remember($name, $value, $expire = null)
|
||||
{
|
||||
self::init();
|
||||
self::$readTimes++;
|
||||
return self::$handler->remember($name, $value, $expire);
|
||||
return self::init()->remember($name, $value, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,8 +216,7 @@ class Cache
|
||||
*/
|
||||
public static function tag($name, $keys = null, $overlay = false)
|
||||
{
|
||||
self::init();
|
||||
return self::$handler->tag($name, $keys, $overlay);
|
||||
return self::init()->tag($name, $keys, $overlay);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,22 +135,35 @@ class Cookie
|
||||
* @param string|null $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name, $prefix = null)
|
||||
public static function get($name = '', $prefix = null)
|
||||
{
|
||||
!isset(self::$init) && self::init();
|
||||
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
if (isset($_COOKIE[$name])) {
|
||||
$value = $_COOKIE[$name];
|
||||
$key = $prefix . $name;
|
||||
|
||||
if ('' == $name) {
|
||||
// 获取全部
|
||||
if ($prefix) {
|
||||
$value = [];
|
||||
foreach ($_COOKIE as $k => $val) {
|
||||
if (0 === strpos($k, $prefix)) {
|
||||
$value[$k] = $val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = $_COOKIE;
|
||||
}
|
||||
} elseif (isset($_COOKIE[$key])) {
|
||||
$value = $_COOKIE[$key];
|
||||
if (0 === strpos($value, 'think:')) {
|
||||
$value = substr($value, 6);
|
||||
$value = json_decode($value, true);
|
||||
array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
|
||||
}
|
||||
return $value;
|
||||
} else {
|
||||
return;
|
||||
$value = null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ use think\db\Query;
|
||||
* @method integer update(array $data) static 更新记录
|
||||
* @method integer delete(mixed $data = null) static 删除记录
|
||||
* @method boolean chunk(integer $count, callable $callback, string $column = null) static 分块获取数据
|
||||
* @method mixed query(string $sql, array $bind = [], boolean $fetch = false, boolean $master = false, mixed $class = null) static SQL查询
|
||||
* @method mixed query(string $sql, array $bind = [], boolean $master = false, bool $pdo = false) static SQL查询
|
||||
* @method integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) static SQL执行
|
||||
* @method Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) static 分页查询
|
||||
* @method mixed transaction(callable $callback) static 执行数据库事务
|
||||
@@ -44,6 +44,8 @@ use think\db\Query;
|
||||
* @method void commit() static 用于非自动提交状态下面的查询提交
|
||||
* @method void rollback() static 事务回滚
|
||||
* @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
|
||||
* @method string quote(string $str) static SQL指令安全过滤
|
||||
* @method string getLastInsID($sequence = null) static 获取最近插入的ID
|
||||
*/
|
||||
class Db
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ class Debug
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某个区间的时间(微秒)使用情况
|
||||
* 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位
|
||||
@@ -53,7 +53,7 @@ class Debug
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计从开始到统计时的时间(微秒)使用情况
|
||||
* 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
|
||||
* @param integer|string $dec 小数位
|
||||
* @return integer
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,10 @@ class Lang
|
||||
protected static $langCookieExpire = 3600;
|
||||
// 允许语言列表
|
||||
protected static $allowLangList = [];
|
||||
// Accept-Language转义为对应语言包名称 系统默认配置
|
||||
protected static $acceptLanguage = [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
];
|
||||
|
||||
// 设定当前的语言
|
||||
public static function range($range = '')
|
||||
@@ -34,6 +38,7 @@ class Lang
|
||||
} else {
|
||||
self::$range = $range;
|
||||
}
|
||||
return self::$range;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +98,6 @@ class Lang
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @param string|null $name 语言变量
|
||||
* @param array $vars 变量替换
|
||||
* @param string $range 语言作用域
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -152,26 +156,25 @@ class Lang
|
||||
{
|
||||
// 自动侦测设置获取语言选择
|
||||
$langSet = '';
|
||||
|
||||
if (isset($_GET[self::$langDetectVar])) {
|
||||
// url中设置了语言变量
|
||||
$langSet = strtolower($_GET[self::$langDetectVar]);
|
||||
Cookie::set(self::$langCookieVar, $langSet, self::$langCookieExpire);
|
||||
} elseif (Cookie::get(self::$langCookieVar)) {
|
||||
// 获取上次用户的选择
|
||||
$langSet = strtolower(Cookie::get(self::$langCookieVar));
|
||||
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
// 自动侦测浏览器语言
|
||||
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
|
||||
$langSet = strtolower($matches[1]);
|
||||
Cookie::set(self::$langCookieVar, $langSet, self::$langCookieExpire);
|
||||
$langSet = strtolower($matches[1]);
|
||||
$acceptLangs = Config::get('header_accept_lang');
|
||||
if (isset($acceptLangs[$langSet])) {
|
||||
$langSet = $acceptLangs[$langSet];
|
||||
} elseif (isset(self::$acceptLanguage[$langSet])) {
|
||||
$langSet = self::$acceptLanguage[$langSet];
|
||||
}
|
||||
}
|
||||
if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
|
||||
// 合法的语言
|
||||
self::$range = $langSet ?: self::$range;
|
||||
}
|
||||
if ('zh-hans-cn' == self::$range) {
|
||||
self::$range = 'zh-cn';
|
||||
}
|
||||
return self::$range;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ use think\model\relation\HasMany;
|
||||
use think\model\relation\HasManyThrough;
|
||||
use think\model\relation\HasOne;
|
||||
use think\model\relation\MorphMany;
|
||||
use think\model\relation\MorphOne;
|
||||
use think\model\relation\MorphTo;
|
||||
|
||||
/**
|
||||
@@ -31,10 +32,12 @@ use think\model\relation\MorphTo;
|
||||
*/
|
||||
abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
// 数据库对象池
|
||||
// 数据库查询对象池
|
||||
protected static $links = [];
|
||||
// 数据库配置
|
||||
protected $connection = [];
|
||||
// 父关联模型对象
|
||||
protected $parent;
|
||||
// 数据库查询对象
|
||||
protected $query;
|
||||
// 当前模型名称
|
||||
@@ -63,8 +66,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $append = [];
|
||||
// 数据信息
|
||||
protected $data = [];
|
||||
// 记录改变字段
|
||||
protected $change = [];
|
||||
// 原始数据
|
||||
protected $origin = [];
|
||||
// 关联模型
|
||||
protected $relation = [];
|
||||
|
||||
// 保存自动完成列表
|
||||
protected $auto = [];
|
||||
@@ -86,8 +91,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $isUpdate = false;
|
||||
// 更新条件
|
||||
protected $updateWhere;
|
||||
// 当前执行的关联对象
|
||||
protected $relation;
|
||||
// 验证失败是否抛出异常
|
||||
protected $failException = false;
|
||||
// 全局查询范围
|
||||
@@ -98,8 +101,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $resultSetType;
|
||||
// 关联自动写入
|
||||
protected $relationWrite;
|
||||
//
|
||||
protected static $db;
|
||||
|
||||
/**
|
||||
* 初始化过的模型.
|
||||
@@ -120,9 +121,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} else {
|
||||
$this->data = $data;
|
||||
}
|
||||
// 记录原始数据
|
||||
$this->origin = $this->data;
|
||||
|
||||
// 当前类名
|
||||
$this->class = get_class($this);
|
||||
$this->class = get_called_class();
|
||||
|
||||
if (empty($this->name)) {
|
||||
// 当前模型名
|
||||
@@ -136,63 +139,94 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
if (is_null($this->autoWriteTimestamp)) {
|
||||
// 自动写入时间戳
|
||||
$this->autoWriteTimestamp = $this->db(false)->getConfig('auto_timestamp');
|
||||
$this->autoWriteTimestamp = $this->getQuery()->getConfig('auto_timestamp');
|
||||
}
|
||||
|
||||
if (is_null($this->dateFormat)) {
|
||||
// 设置时间戳格式
|
||||
$this->dateFormat = $this->db(false)->getConfig('datetime_format');
|
||||
$this->dateFormat = $this->getQuery()->getConfig('datetime_format');
|
||||
}
|
||||
|
||||
if (is_null($this->resultSetType)) {
|
||||
$this->resultSetType = $this->db(false)->getConfig('resultset_type');
|
||||
$this->resultSetType = $this->getQuery()->getConfig('resultset_type');
|
||||
}
|
||||
// 执行初始化操作
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的数据库查询对象
|
||||
* @access public
|
||||
* @param bool $baseQuery 是否调用全局查询范围
|
||||
* 创建模型的查询对象
|
||||
* @access protected
|
||||
* @return Query
|
||||
*/
|
||||
public function db($baseQuery = true)
|
||||
protected function buildQuery()
|
||||
{
|
||||
$model = $this->class;
|
||||
if (!isset(self::$links[$model])) {
|
||||
// 合并数据库配置
|
||||
if (!empty($this->connection)) {
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
} else {
|
||||
$connection = $this->connection;
|
||||
}
|
||||
// 合并数据库配置
|
||||
if (!empty($this->connection)) {
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
} else {
|
||||
$connection = [];
|
||||
$connection = $this->connection;
|
||||
}
|
||||
// 设置当前模型 确保查询返回模型对象
|
||||
$query = Db::connect($connection)->getQuery($model, $this->query);
|
||||
|
||||
// 设置当前数据表和模型名
|
||||
if (!empty($this->table)) {
|
||||
$query->setTable($this->table);
|
||||
} else {
|
||||
$query->name($this->name);
|
||||
}
|
||||
|
||||
if (!empty($this->pk)) {
|
||||
$query->pk($this->pk);
|
||||
}
|
||||
|
||||
self::$links[$model] = $query;
|
||||
} else {
|
||||
$connection = [];
|
||||
}
|
||||
|
||||
$con = Db::connect($connection);
|
||||
// 设置当前模型 确保查询返回模型对象
|
||||
$queryClass = $this->query ?: $con->getConfig('query');
|
||||
$query = new $queryClass($con, $this->class);
|
||||
|
||||
// 设置当前数据表和模型名
|
||||
if (!empty($this->table)) {
|
||||
$query->setTable($this->table);
|
||||
} else {
|
||||
$query->name($this->name);
|
||||
}
|
||||
|
||||
if (!empty($this->pk)) {
|
||||
$query->pk($this->pk);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的查询对象
|
||||
* @access public
|
||||
* @param bool $buildNewQuery 创建新的查询对象
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery($buildNewQuery = false)
|
||||
{
|
||||
if ($buildNewQuery) {
|
||||
return $this->buildQuery();
|
||||
} elseif (!isset(self::$links[$this->class])) {
|
||||
// 创建模型查询对象
|
||||
self::$links[$this->class] = $this->buildQuery();
|
||||
}
|
||||
|
||||
return self::$links[$this->class];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的数据库查询对象
|
||||
* @access public
|
||||
* @param bool $useBaseQuery 是否调用全局查询范围
|
||||
* @param bool $buildNewQuery 创建新的查询对象
|
||||
* @return Query
|
||||
*/
|
||||
public function db($useBaseQuery = true, $buildNewQuery = true)
|
||||
{
|
||||
$query = $this->getQuery($buildNewQuery);
|
||||
|
||||
// 全局作用域
|
||||
if ($baseQuery && method_exists($this, 'base')) {
|
||||
call_user_func_array([$this, 'base'], [ & self::$links[$model]]);
|
||||
if ($useBaseQuery && method_exists($this, 'base')) {
|
||||
call_user_func_array([$this, 'base'], [ & $query]);
|
||||
}
|
||||
|
||||
// 返回当前模型的数据库查询对象
|
||||
return self::$links[$model];
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,6 +252,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置父关联对象
|
||||
* @access public
|
||||
* @param Model $model 模型对象
|
||||
* @return $this
|
||||
*/
|
||||
public function setParent($model)
|
||||
{
|
||||
$this->parent = $model;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父关联对象
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据对象值
|
||||
* @access public
|
||||
@@ -260,6 +317,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this->data;
|
||||
} elseif (array_key_exists($name, $this->data)) {
|
||||
return $this->data[$name];
|
||||
} elseif (array_key_exists($name, $this->relation)) {
|
||||
return $this->relation[$name];
|
||||
} else {
|
||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
||||
}
|
||||
@@ -282,26 +341,48 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 检测修改器
|
||||
$method = 'set' . Loader::parseName($name, 1) . 'Attr';
|
||||
if (method_exists($this, $method)) {
|
||||
$value = $this->$method($value, array_merge($data, $this->data));
|
||||
$value = $this->$method($value, array_merge($this->data, $data));
|
||||
} elseif (isset($this->type[$name])) {
|
||||
// 类型转换
|
||||
$value = $this->writeTransform($value, $this->type[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
// 标记字段更改
|
||||
if (!isset($this->data[$name])) {
|
||||
$this->change[] = $name;
|
||||
} elseif (is_scalar($value) && is_scalar($this->data[$name]) && 0 !== strcmp($this->data[$name], $value)) {
|
||||
$this->change[] = $name;
|
||||
} elseif (!is_object($value) && $value != $this->data[$name]) {
|
||||
$this->change[] = $name;
|
||||
}
|
||||
// 设置数据对象属性
|
||||
$this->data[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的关联模型数据
|
||||
* @access public
|
||||
* @param string $name 关联方法名
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRelation($name = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->relation;
|
||||
} elseif (array_key_exists($name, $this->relation)) {
|
||||
return $this->relation[$name];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置关联数据对象值
|
||||
* @access public
|
||||
* @param string $name 属性名
|
||||
* @param mixed $value 属性值
|
||||
* @return $this
|
||||
*/
|
||||
public function setRelation($name, $value)
|
||||
{
|
||||
$this->relation[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动写入时间戳
|
||||
* @access public
|
||||
@@ -319,12 +400,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'datetime':
|
||||
case 'date':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $format);
|
||||
$value = $this->formatDateTime(time(), $format);
|
||||
break;
|
||||
case 'timestamp':
|
||||
case 'integer':
|
||||
default:
|
||||
$value = $_SERVER['REQUEST_TIME'];
|
||||
$value = time();
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
|
||||
@@ -333,9 +414,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
'timestamp',
|
||||
])
|
||||
) {
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat);
|
||||
$value = $this->formatDateTime(time(), $this->dateFormat);
|
||||
} else {
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat, true);
|
||||
$value = $this->formatDateTime(time(), $this->dateFormat, true);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -367,6 +448,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
protected function writeTransform($value, $type)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($type)) {
|
||||
list($type, $param) = $type;
|
||||
} elseif (strpos($type, ':')) {
|
||||
@@ -451,14 +536,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$value = $this->formatDateTime($value, $this->dateFormat);
|
||||
}
|
||||
} elseif ($notFound) {
|
||||
$method = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $method) && $this->$method() instanceof Relation) {
|
||||
// 清空之前的查询参数
|
||||
$this->$method()->removeOption();
|
||||
$relation = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $relation)) {
|
||||
$modelRelation = $this->$relation();
|
||||
// 不存在该字段 获取关联数据
|
||||
$value = $this->$method()->getRelation();
|
||||
$value = $this->getRelationData($modelRelation);
|
||||
// 保存关联对象值
|
||||
$this->data[$name] = $value;
|
||||
$this->relation[$name] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
||||
}
|
||||
@@ -466,6 +550,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联模型数据
|
||||
* @access public
|
||||
* @param Relation $modelRelation 模型关联对象
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getRelationData(Relation $modelRelation)
|
||||
{
|
||||
if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) {
|
||||
$value = $this->parent;
|
||||
} else {
|
||||
// 首先获取关联数据
|
||||
$value = $modelRelation->getRelation();
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据读取 类型转换
|
||||
* @access public
|
||||
@@ -475,6 +576,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
protected function readTransform($value, $type)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($type)) {
|
||||
list($type, $param) = $type;
|
||||
} elseif (strpos($type, ':')) {
|
||||
@@ -553,14 +658,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (is_string($append)) {
|
||||
$append = explode(',', $append);
|
||||
}
|
||||
$model = $this->getAttr($relation);
|
||||
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
|
||||
// 获取关联数据
|
||||
if (isset($this->relation[$relation])) {
|
||||
$model = $this->relation[$relation];
|
||||
} else {
|
||||
$model = $this->getRelationData($this->$relation());
|
||||
}
|
||||
|
||||
if ($model instanceof Model) {
|
||||
foreach ($append as $key => $attr) {
|
||||
$key = is_numeric($key) ? $attr : $key;
|
||||
if ($this->__isset($key)) {
|
||||
if (isset($this->data[$key])) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$this->setAttr($key, $model->$attr);
|
||||
$this->data[$key] = $model->$attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -653,15 +767,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$item = [];
|
||||
$visible = [];
|
||||
$hidden = [];
|
||||
|
||||
$data = array_merge($this->data, $this->relation);
|
||||
|
||||
// 过滤属性
|
||||
if (!empty($this->visible)) {
|
||||
$array = $this->parseAttr($this->visible, $visible);
|
||||
$data = array_intersect_key($this->data, array_flip($array));
|
||||
$data = array_intersect_key($data, array_flip($array));
|
||||
} elseif (!empty($this->hidden)) {
|
||||
$array = $this->parseAttr($this->hidden, $hidden, false);
|
||||
$data = array_diff_key($this->data, array_flip($array));
|
||||
} else {
|
||||
$data = $this->data;
|
||||
$data = array_diff_key($data, array_flip($array));
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
@@ -672,7 +787,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 关联模型数据集
|
||||
$arr = [];
|
||||
foreach ($val as $k => $value) {
|
||||
$arr[$k] = $this->subToArray($value, $visible, $hidden, $k);
|
||||
$arr[$k] = $this->subToArray($value, $visible, $hidden, $key);
|
||||
}
|
||||
$item[$key] = $arr;
|
||||
} else {
|
||||
@@ -754,10 +869,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function getPk($name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
$table = $this->db(false)->getTable($name);
|
||||
return $this->db(false)->getPk($table);
|
||||
$table = $this->getQuery()->getTable($name);
|
||||
return $this->getQuery()->getPk($table);
|
||||
} elseif (empty($this->pk)) {
|
||||
$this->pk = $this->db(false)->getPk();
|
||||
$this->pk = $this->getQuery()->getPk();
|
||||
}
|
||||
return $this->pk;
|
||||
}
|
||||
@@ -807,31 +922,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (!empty($this->relationWrite)) {
|
||||
$relation = [];
|
||||
foreach ($this->relationWrite as $key => $name) {
|
||||
if (!is_numeric($key)) {
|
||||
$relation[$key] = [];
|
||||
foreach ($name as $val) {
|
||||
if (isset($this->data[$val])) {
|
||||
$relation[$key][$val] = $this->data[$val];
|
||||
unset($this->data[$val]);
|
||||
if (is_array($name)) {
|
||||
if (key($name) === 0) {
|
||||
$relation[$key] = [];
|
||||
foreach ($name as $val) {
|
||||
if (isset($this->data[$val])) {
|
||||
$relation[$key][$val] = $this->data[$val];
|
||||
unset($this->data[$val]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$relation[$key] = $name;
|
||||
}
|
||||
} elseif (isset($this->relation[$name])) {
|
||||
$relation[$name] = $this->relation[$name];
|
||||
} elseif (isset($this->data[$name])) {
|
||||
$relation[$name] = $this->data[$name];
|
||||
if (!$this->isUpdate) {
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测字段
|
||||
if (!empty($this->field)) {
|
||||
if (true === $this->field) {
|
||||
$this->field = $this->db(false)->getTableInfo('', 'fields');
|
||||
}
|
||||
foreach ($this->data as $key => $val) {
|
||||
if (!in_array($key, $this->field)) {
|
||||
unset($this->data[$key]);
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,33 +952,25 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
$pk = $this->getPk();
|
||||
if ($this->isUpdate) {
|
||||
// 检测字段
|
||||
$this->checkAllowField($this->data, array_merge($this->auto, $this->update));
|
||||
|
||||
// 自动更新
|
||||
$this->autoCompleteData($this->update);
|
||||
|
||||
// 获取有更新的数据
|
||||
$data = $this->getChangedData();
|
||||
|
||||
// 事件回调
|
||||
if (false === $this->trigger('before_update', $this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 去除没有更新的字段
|
||||
$data = [];
|
||||
foreach ($this->data as $key => $val) {
|
||||
if (in_array($key, $this->change) || $this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->readonly)) {
|
||||
// 只读字段不允许更新
|
||||
foreach ($this->readonly as $key => $field) {
|
||||
if (isset($data[$field])) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data) || (count($data) == 1 && is_string($pk) && isset($data[$pk]))) {
|
||||
// 没有更新
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
$this->autoRelationUpdate($relation);
|
||||
}
|
||||
return 0;
|
||||
} elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
|
||||
// 自动写入更新时间
|
||||
@@ -882,6 +981,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$where = $this->updateWhere;
|
||||
}
|
||||
|
||||
// 保留主键数据
|
||||
foreach ($this->data as $key => $val) {
|
||||
if ($this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
@@ -890,40 +996,24 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
unset($data[$pk]);
|
||||
}
|
||||
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
foreach ($relation as $name => $val) {
|
||||
if (isset($data[$name])) {
|
||||
unset($data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模型更新
|
||||
$result = $this->db()->where($where)->update($data);
|
||||
$result = $this->getQuery()->where($where)->update($data);
|
||||
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
foreach ($relation as $name => $val) {
|
||||
if ($val instanceof Model) {
|
||||
$val->save();
|
||||
} else {
|
||||
unset($this->data[$name]);
|
||||
$model = $this->getAttr($name);
|
||||
if ($model instanceof Model) {
|
||||
$model->save($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->autoRelationUpdate($relation);
|
||||
}
|
||||
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
// 更新回调
|
||||
$this->trigger('after_update', $this);
|
||||
|
||||
} else {
|
||||
// 检测字段
|
||||
$this->checkAllowField($this->data, array_merge($this->auto, $this->insert));
|
||||
|
||||
// 自动写入
|
||||
$this->autoCompleteData($this->insert);
|
||||
|
||||
// 自动写入创建时间和更新时间
|
||||
if ($this->autoWriteTimestamp) {
|
||||
if ($this->createTime && !isset($this->data[$this->createTime])) {
|
||||
@@ -938,11 +1028,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->db()->insert($this->data);
|
||||
$result = $this->getQuery()->insert($this->data);
|
||||
|
||||
// 获取自动增长主键
|
||||
if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
|
||||
$insertId = $this->db()->getLastInsID($sequence);
|
||||
$insertId = $this->getQuery()->getLastInsID($sequence);
|
||||
if ($insertId) {
|
||||
$this->data[$pk] = $insertId;
|
||||
}
|
||||
@@ -958,17 +1048,78 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
// 标记为更新
|
||||
$this->isUpdate = true;
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
|
||||
// 新增回调
|
||||
$this->trigger('after_insert', $this);
|
||||
}
|
||||
// 写入回调
|
||||
$this->trigger('after_write', $this);
|
||||
|
||||
// 重新记录原始数据
|
||||
$this->origin = $this->data;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function checkAllowField(&$data, $auto = [])
|
||||
{
|
||||
if (!empty($this->field)) {
|
||||
if (true === $this->field) {
|
||||
$this->field = $this->getQuery()->getTableInfo('', 'fields');
|
||||
$field = $this->field;
|
||||
} else {
|
||||
$field = array_merge($this->field, $auto);
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if (!in_array($key, $field)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function autoRelationUpdate($relation)
|
||||
{
|
||||
foreach ($relation as $name => $val) {
|
||||
if ($val instanceof Model) {
|
||||
$val->save();
|
||||
} else {
|
||||
unset($this->data[$name]);
|
||||
$model = $this->getAttr($name);
|
||||
if ($model instanceof Model) {
|
||||
$model->save($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取变化的数据 并排除只读数据
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getChangedData()
|
||||
{
|
||||
$data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
|
||||
if ((empty($b) || empty($b)) && $a !== $b) {
|
||||
return 1;
|
||||
}
|
||||
return is_object($a) || $a != $b ? 1 : 0;
|
||||
});
|
||||
|
||||
if (!empty($this->readonly)) {
|
||||
// 只读字段不允许更新
|
||||
foreach ($this->readonly as $key => $field) {
|
||||
if (isset($data[$field])) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存多个数据到当前数据对象
|
||||
* @access public
|
||||
@@ -990,7 +1141,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$db = $this->db();
|
||||
$db = $this->getQuery();
|
||||
$db->startTrans();
|
||||
try {
|
||||
$pk = $this->getPk();
|
||||
@@ -1071,9 +1222,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$field = $value;
|
||||
$value = null;
|
||||
}
|
||||
if (!in_array($field, $this->change)) {
|
||||
$this->setAttr($field, !is_null($value) ? $value : (isset($this->data[$field]) ? $this->data[$field] : $value));
|
||||
|
||||
if (!isset($this->data[$field])) {
|
||||
$default = null;
|
||||
} else {
|
||||
$default = $this->data[$field];
|
||||
}
|
||||
|
||||
$this->setAttr($field, !is_null($value) ? $value : $default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1099,7 +1255,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
// 删除当前模型数据
|
||||
$result = $this->db()->where($where)->delete();
|
||||
$result = $this->getQuery()->where($where)->delete();
|
||||
|
||||
// 关联删除
|
||||
if (!empty($this->relationWrite)) {
|
||||
@@ -1113,6 +1269,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
$this->trigger('after_delete', $this);
|
||||
// 清空原始数据
|
||||
$this->origin = [];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -1207,7 +1366,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
/**
|
||||
* 返回模型的错误信息
|
||||
* @access public
|
||||
* @return string
|
||||
* @return string|array
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
@@ -1294,11 +1453,15 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @param mixed $data 主键值或者查询条件(闭包)
|
||||
* @param array|string $with 关联预查询
|
||||
* @param bool $cache 是否缓存
|
||||
* @return static
|
||||
* @return static|null
|
||||
* @throws exception\DbException
|
||||
*/
|
||||
public static function get($data = null, $with = [], $cache = false)
|
||||
public static function get($data, $with = [], $cache = false)
|
||||
{
|
||||
if (is_null($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (true === $with || is_int($with)) {
|
||||
$cache = $with;
|
||||
$with = [];
|
||||
@@ -1366,7 +1529,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} elseif ($data instanceof \Closure) {
|
||||
call_user_func_array($data, [ & $query]);
|
||||
$data = null;
|
||||
} elseif (is_null($data)) {
|
||||
} elseif (empty($data) && 0 !== $data) {
|
||||
return 0;
|
||||
}
|
||||
$resultSet = $query->select($data);
|
||||
@@ -1385,16 +1548,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @access public
|
||||
* @param string|array|\Closure $name 命名范围名称 逗号分隔
|
||||
* @internal mixed ...$params 参数调用
|
||||
* @return Model|Query
|
||||
* @return Query
|
||||
*/
|
||||
public static function scope($name)
|
||||
{
|
||||
if ($name instanceof Query) {
|
||||
return $name;
|
||||
}
|
||||
$model = new static();
|
||||
$params = func_get_args();
|
||||
$params[0] = $model->db();
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
$params = func_get_args();
|
||||
array_unshift($params, $query);
|
||||
if ($name instanceof \Closure) {
|
||||
call_user_func_array($name, $params);
|
||||
} elseif (is_string($name)) {
|
||||
@@ -1408,7 +1569,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
}
|
||||
}
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1419,9 +1580,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public static function useGlobalScope($use)
|
||||
{
|
||||
$model = new static();
|
||||
static::$db = $model->db($use);
|
||||
return $model;
|
||||
$model = new static();
|
||||
return $model->db($use);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1638,7 +1798,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$model = $this->parseModel($model);
|
||||
$foreignKey = $foreignKey ?: $this->getForeignKey($model);
|
||||
$localKey = $localKey ?: (new $model)->getPk();
|
||||
return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType);
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$relation = Loader::parseName($trace[1]['function']);
|
||||
return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType, $relation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1693,7 +1855,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 记录当前关联信息
|
||||
$model = $this->parseModel($model);
|
||||
$name = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$table = $table ?: $this->db(false)->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$table = $table ?: $this->getQuery()->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$foreignKey = $foreignKey ?: $name . '_id';
|
||||
$localKey = $localKey ?: $this->getForeignKey($this->name);
|
||||
return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
|
||||
@@ -1725,6 +1887,32 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return new MorphMany($this, $model, $foreignKey, $morphType, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* MORPH One 关联定义
|
||||
* @access public
|
||||
* @param string $model 模型名
|
||||
* @param string|array $morph 多态字段信息
|
||||
* @param string $type 多态类型
|
||||
* @return MorphOne
|
||||
*/
|
||||
public function morphOne($model, $morph = null, $type = '')
|
||||
{
|
||||
// 记录当前关联信息
|
||||
$model = $this->parseModel($model);
|
||||
if (is_null($morph)) {
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
}
|
||||
$type = $type ?: Loader::parseName($this->name);
|
||||
if (is_array($morph)) {
|
||||
list($morphType, $foreignKey) = $morph;
|
||||
} else {
|
||||
$morphType = $morph . '_type';
|
||||
$foreignKey = $morph . '_id';
|
||||
}
|
||||
return new MorphOne($this, $model, $foreignKey, $morphType, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* MORPH TO 关联定义
|
||||
* @access public
|
||||
@@ -1734,9 +1922,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function morphTo($morph = null, $alias = [])
|
||||
{
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$relation = Loader::parseName($trace[1]['function']);
|
||||
|
||||
if (is_null($morph)) {
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
$morph = $relation;
|
||||
}
|
||||
// 记录当前关联信息
|
||||
if (is_array($morph)) {
|
||||
@@ -1745,17 +1935,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$morphType = $morph . '_type';
|
||||
$foreignKey = $morph . '_id';
|
||||
}
|
||||
return new MorphTo($this, $morphType, $foreignKey, $alias);
|
||||
return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = $this->db();
|
||||
}
|
||||
$query = $this->db(true, false);
|
||||
|
||||
if (method_exists($this, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
@@ -1768,16 +1953,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
}
|
||||
|
||||
public static function __callStatic($method, $params)
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = (new static())->db();
|
||||
}
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
|
||||
return call_user_func_array([$query, $method], $params);
|
||||
if (method_exists($model, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
$method = 'scope' . $method;
|
||||
array_unshift($args, $query);
|
||||
|
||||
call_user_func_array([$model, $method], $args);
|
||||
return $query;
|
||||
} else {
|
||||
return call_user_func_array([$query, $method], $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1812,7 +2002,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function __isset($name)
|
||||
{
|
||||
try {
|
||||
if (array_key_exists($name, $this->data)) {
|
||||
if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {
|
||||
return true;
|
||||
} else {
|
||||
$this->getAttr($name);
|
||||
@@ -1832,7 +2022,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->data[$name]);
|
||||
unset($this->data[$name], $this->relation[$name]);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
|
||||
@@ -273,6 +273,23 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
||||
return $this->items->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 给每个元素执行个回调
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function each(callable $callback)
|
||||
{
|
||||
foreach ($this->items as $key => $item) {
|
||||
if ($callback($item, $key) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an external iterator
|
||||
* @return Traversable An instance of an object implementing <b>Iterator</b> or
|
||||
@@ -349,6 +366,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
||||
'total' => $total,
|
||||
'per_page' => $this->listRows(),
|
||||
'current_page' => $this->currentPage(),
|
||||
'last_page' => $this->lastPage,
|
||||
'data' => $this->items->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -88,20 +88,18 @@ class Request
|
||||
* @var array 资源类型
|
||||
*/
|
||||
protected $mimeType = [
|
||||
'xml' => 'application/xml,text/xml,application/x-xml',
|
||||
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
|
||||
'js' => 'text/javascript,application/javascript,application/x-javascript',
|
||||
'css' => 'text/css',
|
||||
'rss' => 'application/rss+xml',
|
||||
'yaml' => 'application/x-yaml,text/yaml',
|
||||
'atom' => 'application/atom+xml',
|
||||
'pdf' => 'application/pdf',
|
||||
'text' => 'text/plain',
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpg,image/jpeg,image/pjpeg',
|
||||
'gif' => 'image/gif',
|
||||
'csv' => 'text/csv',
|
||||
'html' => 'text/html,application/xhtml+xml,*/*',
|
||||
'xml' => 'application/xml,text/xml,application/x-xml',
|
||||
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
|
||||
'js' => 'text/javascript,application/javascript,application/x-javascript',
|
||||
'css' => 'text/css',
|
||||
'rss' => 'application/rss+xml',
|
||||
'yaml' => 'application/x-yaml,text/yaml',
|
||||
'atom' => 'application/atom+xml',
|
||||
'pdf' => 'application/pdf',
|
||||
'text' => 'text/plain',
|
||||
'image' => 'image/png,image/jpg,image/jpeg,image/pjpeg,image/gif,image/webp,image/*',
|
||||
'csv' => 'text/csv',
|
||||
'html' => 'text/html,application/xhtml+xml,*/*',
|
||||
];
|
||||
|
||||
protected $content;
|
||||
@@ -134,6 +132,7 @@ class Request
|
||||
if (is_null($this->filter)) {
|
||||
$this->filter = Config::get('default_filter');
|
||||
}
|
||||
|
||||
// 保存 php://input
|
||||
$this->input = file_get_contents('php://input');
|
||||
}
|
||||
@@ -802,12 +801,26 @@ class Request
|
||||
public function cookie($name = '', $default = null, $filter = '')
|
||||
{
|
||||
if (empty($this->cookie)) {
|
||||
$this->cookie = $_COOKIE;
|
||||
$this->cookie = Cookie::get();
|
||||
}
|
||||
if (is_array($name)) {
|
||||
return $this->cookie = array_merge($this->cookie, $name);
|
||||
} elseif (!empty($name)) {
|
||||
$data = Cookie::has($name) ? Cookie::get($name) : $default;
|
||||
} else {
|
||||
$data = $this->cookie;
|
||||
}
|
||||
return $this->input($this->cookie, $name, $default, $filter);
|
||||
|
||||
// 解析过滤器
|
||||
$filter = $this->getFilter($filter, $default);
|
||||
|
||||
if (is_array($data)) {
|
||||
array_walk_recursive($data, [$this, 'filterValue'], $filter);
|
||||
reset($data);
|
||||
} else {
|
||||
$this->filterValue($data, $name, $filter);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -984,18 +997,8 @@ class Request
|
||||
}
|
||||
|
||||
// 解析过滤器
|
||||
if (is_null($filter)) {
|
||||
$filter = [];
|
||||
} else {
|
||||
$filter = $filter ?: $this->filter;
|
||||
if (is_string($filter)) {
|
||||
$filter = explode(',', $filter);
|
||||
} else {
|
||||
$filter = (array) $filter;
|
||||
}
|
||||
}
|
||||
$filter = $this->getFilter($filter, $default);
|
||||
|
||||
$filter[] = $default;
|
||||
if (is_array($data)) {
|
||||
array_walk_recursive($data, [$this, 'filterValue'], $filter);
|
||||
reset($data);
|
||||
@@ -1024,6 +1027,23 @@ class Request
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFilter($filter, $default)
|
||||
{
|
||||
if (is_null($filter)) {
|
||||
$filter = [];
|
||||
} else {
|
||||
$filter = $filter ?: $this->filter;
|
||||
if (is_string($filter) && false === strpos($filter, '/')) {
|
||||
$filter = explode(',', $filter);
|
||||
} else {
|
||||
$filter = (array) $filter;
|
||||
}
|
||||
}
|
||||
|
||||
$filter[] = $default;
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归过滤给定的值
|
||||
* @param mixed $value 键值
|
||||
@@ -1039,7 +1059,7 @@ class Request
|
||||
// 调用函数或者方法过滤
|
||||
$value = call_user_func($filter, $value);
|
||||
} elseif (is_scalar($value)) {
|
||||
if (strpos($filter, '/')) {
|
||||
if (false !== strpos($filter, '/')) {
|
||||
// 正则过滤
|
||||
if (!preg_match($filter, $value)) {
|
||||
// 匹配不成功返回默认值
|
||||
@@ -1527,13 +1547,13 @@ class Request
|
||||
}
|
||||
}
|
||||
// 自动缓存功能
|
||||
$key = md5($this->host()) . '__URL__';
|
||||
$key = '__URL__';
|
||||
} elseif (strpos($key, '|')) {
|
||||
list($key, $fun) = explode('|', $key);
|
||||
}
|
||||
// 特殊规则替换
|
||||
if (false !== strpos($key, '__')) {
|
||||
$key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__', ''], [$this->module, $this->controller, $this->action, md5($this->url())], $key);
|
||||
$key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__', ''], [$this->module, $this->controller, $this->action, md5($this->url(true))], $key);
|
||||
}
|
||||
|
||||
if (false !== strpos($key, ':')) {
|
||||
|
||||
@@ -19,7 +19,6 @@ use think\response\Xml as XmlResponse;
|
||||
|
||||
class Response
|
||||
{
|
||||
|
||||
// 原始数据
|
||||
protected $data;
|
||||
|
||||
@@ -50,12 +49,12 @@ class Response
|
||||
public function __construct($data = '', $code = 200, array $header = [], $options = [])
|
||||
{
|
||||
$this->data($data);
|
||||
$this->header = $header;
|
||||
$this->code = $code;
|
||||
if (!empty($options)) {
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
$this->contentType($this->contentType, $this->charset);
|
||||
$this->header = array_merge($this->header, $header);
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +112,11 @@ class Response
|
||||
http_response_code($this->code);
|
||||
// 发送头部信息
|
||||
foreach ($this->header as $name => $val) {
|
||||
header($name . ':' . $val);
|
||||
if (is_null($val)) {
|
||||
header($name);
|
||||
} else {
|
||||
header($name . ':' . $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -842,7 +842,7 @@ class Route
|
||||
}
|
||||
$method = strtolower($request->method());
|
||||
// 获取当前请求类型的路由规则
|
||||
$rules = self::$rules[$method];
|
||||
$rules = isset(self::$rules[$method]) ? self::$rules[$method] : [];
|
||||
// 检测域名部署
|
||||
if ($checkDomain) {
|
||||
self::checkDomain($request, $rules, $method);
|
||||
@@ -924,7 +924,7 @@ class Route
|
||||
} else {
|
||||
$str = $key;
|
||||
}
|
||||
if (is_string($str) && $str && 0 !== strpos(str_replace('|', '/', $url), $str)) {
|
||||
if (is_string($str) && $str && 0 !== stripos(str_replace('|', '/', $url), $str)) {
|
||||
continue;
|
||||
}
|
||||
self::setOption($option);
|
||||
@@ -1184,9 +1184,9 @@ class Route
|
||||
}
|
||||
}
|
||||
$pattern = array_merge(self::$rules['pattern'], $pattern);
|
||||
if (false !== $match = self::match($url, $rule, $pattern, $merge)) {
|
||||
if (false !== $match = self::match($url, $rule, $pattern)) {
|
||||
// 匹配到路由规则
|
||||
return self::parseRule($rule, $route, $url, $option, $match, $merge);
|
||||
return self::parseRule($rule, $route, $url, $option, $match);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -56,7 +56,7 @@ class Session
|
||||
$isDoStart = true;
|
||||
}
|
||||
|
||||
if (isset($config['prefix'])) {
|
||||
if (isset($config['prefix']) && (self::$prefix === '' || self::$prefix === null)) {
|
||||
self::$prefix = $config['prefix'];
|
||||
}
|
||||
if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {
|
||||
|
||||
@@ -235,7 +235,7 @@ class Url
|
||||
$rootDomain = Config::get('url_domain_root');
|
||||
if (true === $domain) {
|
||||
// 自动判断域名
|
||||
$domain = $request->host();
|
||||
$domain = Config::get('default_host') ?: $request->host();
|
||||
|
||||
$domains = Route::rules('domain');
|
||||
if ($domains) {
|
||||
@@ -265,7 +265,7 @@ class Url
|
||||
|
||||
} else {
|
||||
if (empty($rootDomain)) {
|
||||
$host = $request->host();
|
||||
$host = Config::get('default_host') ?: $request->host();
|
||||
$rootDomain = substr_count($host, '.') > 1 ? substr(strstr($host, '.'), 1) : $host;
|
||||
}
|
||||
if (substr_count($domain, '.') < 2 && !strpos($domain, $rootDomain)) {
|
||||
@@ -297,7 +297,7 @@ class Url
|
||||
}
|
||||
foreach ($pattern as $key => $val) {
|
||||
if (isset($vars[$key])) {
|
||||
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], $vars[$key], $url);
|
||||
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url);
|
||||
unset($vars[$key]);
|
||||
$result = [$url, $domain, $suffix];
|
||||
} elseif (2 == $val) {
|
||||
|
||||
@@ -456,11 +456,13 @@ class Validate
|
||||
* @access protected
|
||||
* @param mixed $value 字段值
|
||||
* @param mixed $rule 验证规则
|
||||
* @param array $data 数据
|
||||
* @return bool
|
||||
*/
|
||||
protected function egt($value, $rule)
|
||||
protected function egt($value, $rule, $data)
|
||||
{
|
||||
return $value >= $rule;
|
||||
$val = $this->getDataValue($data, $rule);
|
||||
return !is_null($val) && $value >= $val;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,11 +470,13 @@ class Validate
|
||||
* @access protected
|
||||
* @param mixed $value 字段值
|
||||
* @param mixed $rule 验证规则
|
||||
* @param array $data 数据
|
||||
* @return bool
|
||||
*/
|
||||
protected function gt($value, $rule)
|
||||
protected function gt($value, $rule, $data)
|
||||
{
|
||||
return $value > $rule;
|
||||
$val = $this->getDataValue($data, $rule);
|
||||
return !is_null($val) && $value > $val;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,11 +484,13 @@ class Validate
|
||||
* @access protected
|
||||
* @param mixed $value 字段值
|
||||
* @param mixed $rule 验证规则
|
||||
* @param array $data 数据
|
||||
* @return bool
|
||||
*/
|
||||
protected function elt($value, $rule)
|
||||
protected function elt($value, $rule, $data)
|
||||
{
|
||||
return $value <= $rule;
|
||||
$val = $this->getDataValue($data, $rule);
|
||||
return !is_null($val) && $value <= $val;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,11 +498,13 @@ class Validate
|
||||
* @access protected
|
||||
* @param mixed $value 字段值
|
||||
* @param mixed $rule 验证规则
|
||||
* @param array $data 数据
|
||||
* @return bool
|
||||
*/
|
||||
protected function lt($value, $rule)
|
||||
protected function lt($value, $rule, $data)
|
||||
{
|
||||
return $value < $rule;
|
||||
$val = $this->getDataValue($data, $rule);
|
||||
return !is_null($val) && $value < $val;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1180,13 +1188,15 @@ class Validate
|
||||
/**
|
||||
* 获取数据值
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string $key 数据标识 支持二维
|
||||
* @param array $data 数据
|
||||
* @param string $key 数据标识 支持二维
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getDataValue($data, $key)
|
||||
{
|
||||
if (strpos($key, '.')) {
|
||||
if (is_numeric($key)) {
|
||||
$value = $key;
|
||||
} elseif (strpos($key, '.')) {
|
||||
// 支持二维数组验证
|
||||
list($name1, $name2) = explode('.', $key);
|
||||
$value = isset($data[$name1][$name2]) ? $data[$name1][$name2] : null;
|
||||
|
||||
5
core/library/think/cache/driver/Memcache.php
vendored
5
core/library/think/cache/driver/Memcache.php
vendored
@@ -113,7 +113,10 @@ class Memcache extends Driver
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->increment($key, $step);
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,7 +125,10 @@ class Memcached extends Driver
|
||||
public function inc($name, $step = 1)
|
||||
{
|
||||
$key = $this->getCacheKey($name);
|
||||
return $this->handler->increment($key, $step);
|
||||
if ($this->handler->get($key)) {
|
||||
return $this->handler->increment($key, $step);
|
||||
}
|
||||
return $this->handler->set($key, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class Builder
|
||||
// SQL表达式
|
||||
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
|
||||
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
|
||||
protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
|
||||
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
|
||||
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
|
||||
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
|
||||
|
||||
@@ -88,7 +88,7 @@ abstract class Builder
|
||||
}
|
||||
|
||||
// 获取绑定信息
|
||||
$bind = $this->query->getFieldsBind($options);
|
||||
$bind = $this->query->getFieldsBind($options['table']);
|
||||
if ('*' == $options['field']) {
|
||||
$fields = array_keys($bind);
|
||||
} else {
|
||||
@@ -222,6 +222,14 @@ abstract class Builder
|
||||
protected function parseWhere($where, $options)
|
||||
{
|
||||
$whereStr = $this->buildWhere($where, $options);
|
||||
if (!empty($options['soft_delete'])) {
|
||||
// 附加软删除条件
|
||||
list($field, $condition) = $options['soft_delete'];
|
||||
|
||||
$binds = $this->query->getFieldsBind($options['table']);
|
||||
$whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
|
||||
$whereStr = $whereStr . $this->parseWhereItem($field, $condition, '', $options, $binds);
|
||||
}
|
||||
return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
|
||||
}
|
||||
|
||||
@@ -243,7 +251,7 @@ abstract class Builder
|
||||
}
|
||||
|
||||
$whereStr = '';
|
||||
$binds = $this->query->getFieldsBind($options);
|
||||
$binds = $this->query->getFieldsBind($options['table']);
|
||||
foreach ($where as $key => $val) {
|
||||
$str = [];
|
||||
foreach ($val as $field => $value) {
|
||||
@@ -280,13 +288,7 @@ abstract class Builder
|
||||
|
||||
$whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($key) + 1) : implode(' ', $str);
|
||||
}
|
||||
if (!empty($options['soft_delete'])) {
|
||||
// 附加软删除条件
|
||||
list($field, $condition) = $options['soft_delete'];
|
||||
|
||||
$whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
|
||||
$whereStr = $whereStr . $this->parseWhereItem($field, $condition, '', $options, $binds);
|
||||
}
|
||||
return $whereStr;
|
||||
}
|
||||
|
||||
@@ -346,9 +348,14 @@ abstract class Builder
|
||||
|
||||
$whereStr = '';
|
||||
if (in_array($exp, ['=', '<>', '>', '>=', '<', '<='])) {
|
||||
// 比较运算 及 模糊匹配
|
||||
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);
|
||||
// 比较运算
|
||||
if ($value instanceof \Closure) {
|
||||
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);
|
||||
} else {
|
||||
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);
|
||||
}
|
||||
} elseif ('LIKE' == $exp || 'NOT LIKE' == $exp) {
|
||||
// 模糊匹配
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$array[] = $key . ' ' . $exp . ' ' . $this->parseValue($item, $field);
|
||||
@@ -712,13 +719,14 @@ abstract class Builder
|
||||
* @access public
|
||||
* @param array $dataSet 数据集
|
||||
* @param array $options 表达式
|
||||
* @param bool $replace 是否replace
|
||||
* @return string
|
||||
*/
|
||||
public function insertAll($dataSet, $options)
|
||||
public function insertAll($dataSet, $options, $replace = false)
|
||||
{
|
||||
// 获取合法的字段
|
||||
if ('*' == $options['field']) {
|
||||
$fields = array_keys($this->query->getFieldsType($options));
|
||||
$fields = array_keys($this->query->getFieldsType($options['table']));
|
||||
} else {
|
||||
$fields = $options['field'];
|
||||
}
|
||||
@@ -747,8 +755,9 @@ abstract class Builder
|
||||
}
|
||||
$fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
|
||||
$sql = str_replace(
|
||||
['%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
|
||||
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
|
||||
[
|
||||
$replace ? 'REPLACE' : 'INSERT',
|
||||
$this->parseTable($options['table'], $options),
|
||||
implode(' , ', $fields),
|
||||
implode(' UNION ALL ', $values),
|
||||
|
||||
@@ -56,8 +56,6 @@ abstract class Connection
|
||||
protected $attrCase = PDO::CASE_LOWER;
|
||||
// 监听回调
|
||||
protected static $event = [];
|
||||
// 查询对象
|
||||
protected $query = [];
|
||||
// 使用Builder类
|
||||
protected $builder;
|
||||
// 数据库连接参数配置
|
||||
@@ -137,19 +135,14 @@ abstract class Connection
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定模型的查询对象
|
||||
* @access public
|
||||
* @param string $model 模型类名称
|
||||
* @param string $queryClass 查询对象类名
|
||||
* 获取新的查询对象
|
||||
* @access protected
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery($model = 'db', $queryClass = '')
|
||||
protected function getQuery()
|
||||
{
|
||||
if (!isset($this->query[$model])) {
|
||||
$class = $queryClass ?: $this->config['query'];
|
||||
$this->query[$model] = new $class($this, 'db' == $model ? '' : $model);
|
||||
}
|
||||
return $this->query[$model];
|
||||
$class = $this->config['query'];
|
||||
return new $class($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,13 +333,9 @@ abstract class Connection
|
||||
/**
|
||||
* 执行查询 返回数据集
|
||||
* @access public
|
||||
* @param string $sql sql指令
|
||||
* @param array $bind 参数绑定
|
||||
* @param bool $master 是否在主服务器读操作
|
||||
* @param bool $class 是否返回PDO对象
|
||||
* @param string $sql sql指令
|
||||
* @param array $bind 参数绑定
|
||||
* @param boolean $master 是否在主服务器读操作
|
||||
* @param bool $master 是否在主服务器读操作
|
||||
* @param bool $pdo 是否返回PDO对象
|
||||
* @return mixed
|
||||
* @throws BindParamException
|
||||
@@ -393,10 +382,15 @@ abstract class Connection
|
||||
// 返回结果集
|
||||
return $this->getResult($pdo, $procedure);
|
||||
} catch (\PDOException $e) {
|
||||
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->query($sql, $bind, $master, $pdo);
|
||||
}
|
||||
throw new PDOException($e, $this->config, $this->getLastsql());
|
||||
} catch (\ErrorException $e) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->query($sql, $bind, $master, $pdo);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,10 +445,15 @@ abstract class Connection
|
||||
$this->numRows = $this->PDOStatement->rowCount();
|
||||
return $this->numRows;
|
||||
} catch (\PDOException $e) {
|
||||
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->execute($sql, $bind);
|
||||
}
|
||||
throw new PDOException($e, $this->config, $this->getLastsql());
|
||||
} catch (\ErrorException $e) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->execute($sql, $bind);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,13 +628,25 @@ abstract class Connection
|
||||
}
|
||||
|
||||
++$this->transTimes;
|
||||
try {
|
||||
if (1 == $this->transTimes) {
|
||||
$this->linkID->beginTransaction();
|
||||
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
|
||||
$this->linkID->exec(
|
||||
$this->parseSavepoint('trans' . $this->transTimes)
|
||||
);
|
||||
}
|
||||
|
||||
if (1 == $this->transTimes) {
|
||||
$this->linkID->beginTransaction();
|
||||
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
|
||||
$this->linkID->exec(
|
||||
$this->parseSavepoint('trans' . $this->transTimes)
|
||||
);
|
||||
} catch (\PDOException $e) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->startTrans();
|
||||
}
|
||||
throw $e;
|
||||
} catch (\ErrorException $e) {
|
||||
if ($this->isBreak($e)) {
|
||||
return $this->close()->startTrans();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,11 +782,35 @@ abstract class Connection
|
||||
/**
|
||||
* 是否断线
|
||||
* @access protected
|
||||
* @param \PDOException $e 异常
|
||||
* @param \PDOException $e 异常对象
|
||||
* @return bool
|
||||
*/
|
||||
protected function isBreak($e)
|
||||
{
|
||||
if (!$this->config['break_reconnect']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = [
|
||||
'server has gone away',
|
||||
'no connection to the server',
|
||||
'Lost connection',
|
||||
'is dead or not enabled',
|
||||
'Error while sending',
|
||||
'decryption failed or bad record mac',
|
||||
'server closed the connection unexpectedly',
|
||||
'SSL connection has been closed unexpectedly',
|
||||
'Error writing data to the connection',
|
||||
'Resource deadlock avoided',
|
||||
];
|
||||
|
||||
$error = $e->getMessage();
|
||||
|
||||
foreach ($info as $msg) {
|
||||
if (false !== stripos($error, $msg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -860,7 +895,6 @@ abstract class Connection
|
||||
Debug::remark('queryEndTime', 'time');
|
||||
$runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime');
|
||||
$sql = $sql ?: $this->getLastsql();
|
||||
$log = $sql . ' [ RunTime:' . $runtime . 's ]';
|
||||
$result = [];
|
||||
// SQL性能分析
|
||||
if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) {
|
||||
@@ -918,7 +952,7 @@ abstract class Connection
|
||||
{
|
||||
if (!empty($this->config['deploy'])) {
|
||||
// 采用分布式数据库
|
||||
if ($master) {
|
||||
if ($master || $this->transTimes) {
|
||||
if (!$this->linkWrite) {
|
||||
$this->linkWrite = $this->multiConnect(true);
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ class Query
|
||||
if (empty($this->options['table'])) {
|
||||
$this->options['table'] = $this->getTable();
|
||||
}
|
||||
$key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options));
|
||||
$key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
|
||||
$result = Cache::get($key);
|
||||
}
|
||||
if (false === $result) {
|
||||
@@ -444,14 +444,16 @@ class Query
|
||||
if (empty($this->options['table'])) {
|
||||
$this->options['table'] = $this->getTable();
|
||||
}
|
||||
$guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options));
|
||||
$guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
|
||||
$result = Cache::get($guid);
|
||||
}
|
||||
if (false === $result) {
|
||||
if (isset($this->options['field'])) {
|
||||
unset($this->options['field']);
|
||||
}
|
||||
if ($key && '*' != $field) {
|
||||
if (is_null($field)) {
|
||||
$field = '*';
|
||||
} elseif ($key && '*' != $field) {
|
||||
$field = $key . ',' . $field;
|
||||
}
|
||||
$pdo = $this->field($field)->getPdo();
|
||||
@@ -594,7 +596,7 @@ class Query
|
||||
}
|
||||
if ($lazyTime > 0) {
|
||||
// 延迟写入
|
||||
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition));
|
||||
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));
|
||||
$step = $this->lazyWrite('inc', $guid, $step, $lazyTime);
|
||||
if (false === $step) {
|
||||
// 清空查询条件
|
||||
@@ -623,7 +625,7 @@ class Query
|
||||
}
|
||||
if ($lazyTime > 0) {
|
||||
// 延迟写入
|
||||
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition));
|
||||
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));
|
||||
$step = $this->lazyWrite('dec', $guid, $step, $lazyTime);
|
||||
if (false === $step) {
|
||||
// 清空查询条件
|
||||
@@ -649,16 +651,16 @@ class Query
|
||||
if (!Cache::has($guid . '_time')) {
|
||||
// 计时开始
|
||||
Cache::set($guid . '_time', $_SERVER['REQUEST_TIME'], 0);
|
||||
Cache::$type($guid, $step, 0);
|
||||
Cache::$type($guid, $step);
|
||||
} elseif ($_SERVER['REQUEST_TIME'] > Cache::get($guid . '_time') + $lazyTime) {
|
||||
// 删除缓存
|
||||
$value = Cache::$type($guid, $step, 0);
|
||||
$value = Cache::$type($guid, $step);
|
||||
Cache::rm($guid);
|
||||
Cache::rm($guid . '_time');
|
||||
return 0 === $value ? false : $value;
|
||||
} else {
|
||||
// 更新缓存
|
||||
Cache::$type($guid, $step, 0);
|
||||
Cache::$type($guid, $step);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1132,6 +1134,7 @@ class Query
|
||||
if ($field) {
|
||||
$this->options['soft_delete'] = [$field, $condition ?: ['null', '']];
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1773,21 +1776,21 @@ class Query
|
||||
}
|
||||
|
||||
// 获取当前数据表字段信息
|
||||
public function getTableFields($options)
|
||||
public function getTableFields($table = '')
|
||||
{
|
||||
return $this->getTableInfo($options['table'], 'fields');
|
||||
return $this->getTableInfo($table ?: $this->getOptions('table'), 'fields');
|
||||
}
|
||||
|
||||
// 获取当前数据表字段类型
|
||||
public function getFieldsType($options)
|
||||
public function getFieldsType($table = '')
|
||||
{
|
||||
return $this->getTableInfo($options['table'], 'type');
|
||||
return $this->getTableInfo($table ?: $this->getOptions('table'), 'type');
|
||||
}
|
||||
|
||||
// 获取当前数据表绑定信息
|
||||
public function getFieldsBind($options)
|
||||
public function getFieldsBind($table = '')
|
||||
{
|
||||
$types = $this->getFieldsType($options);
|
||||
$types = $this->getFieldsType($table);
|
||||
$bind = [];
|
||||
if ($types) {
|
||||
foreach ($types as $key => $type) {
|
||||
@@ -1900,6 +1903,9 @@ class Query
|
||||
$closure = $relation;
|
||||
$relation = $key;
|
||||
$with[$key] = $key;
|
||||
} elseif (is_array($relation)) {
|
||||
$subRelation = $relation;
|
||||
$relation = $key;
|
||||
} elseif (is_string($relation) && strpos($relation, '.')) {
|
||||
$with[$key] = $relation;
|
||||
list($relation, $subRelation) = explode('.', $relation, 2);
|
||||
@@ -1909,7 +1915,7 @@ class Query
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
$model = $class->$relation();
|
||||
if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {
|
||||
$model->removeOption()->eagerly($this, $relation, $subRelation, $closure, $first);
|
||||
$model->eagerly($this, $relation, $subRelation, $closure, $first);
|
||||
$first = false;
|
||||
} elseif ($closure) {
|
||||
$with[$key] = $closure;
|
||||
@@ -1997,7 +2003,7 @@ class Query
|
||||
$relation = explode(',', $relation);
|
||||
}
|
||||
if (isset($this->options['relation'])) {
|
||||
$this->options['relation'] = array_mrege($this->options['relation'], $relation);
|
||||
$this->options['relation'] = array_merge($this->options['relation'], $relation);
|
||||
} else {
|
||||
$this->options['relation'] = $relation;
|
||||
}
|
||||
@@ -2111,9 +2117,10 @@ class Query
|
||||
* 批量插入记录
|
||||
* @access public
|
||||
* @param mixed $dataSet 数据集
|
||||
* @param boolean $replace 是否replace
|
||||
* @return integer|string
|
||||
*/
|
||||
public function insertAll(array $dataSet)
|
||||
public function insertAll(array $dataSet, $replace = false)
|
||||
{
|
||||
// 分析查询表达式
|
||||
$options = $this->parseExpress();
|
||||
@@ -2121,7 +2128,7 @@ class Query
|
||||
return false;
|
||||
}
|
||||
// 生成SQL语句
|
||||
$sql = $this->builder->insertAll($dataSet, $options);
|
||||
$sql = $this->builder->insertAll($dataSet, $options, $replace);
|
||||
// 获取参数绑定
|
||||
$bind = $this->getBind();
|
||||
if ($options['fetch_sql']) {
|
||||
@@ -2203,7 +2210,7 @@ class Query
|
||||
$options['where']['AND'] = $where;
|
||||
}
|
||||
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
|
||||
}
|
||||
|
||||
// 生成UPDATE SQL语句
|
||||
@@ -2291,7 +2298,7 @@ class Query
|
||||
// 判断查询缓存
|
||||
$cache = $options['cache'];
|
||||
unset($options['cache']);
|
||||
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));
|
||||
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($this->bind));
|
||||
$resultSet = Cache::get($key);
|
||||
}
|
||||
if (!$resultSet) {
|
||||
@@ -2383,8 +2390,9 @@ class Query
|
||||
* @access public
|
||||
* @param mixed $value 缓存数据
|
||||
* @param array $options 缓存参数
|
||||
* @param array $bind 绑定参数
|
||||
*/
|
||||
protected function getCacheKey($value, $options)
|
||||
protected function getCacheKey($value, $options, $bind = [])
|
||||
{
|
||||
if (is_scalar($value)) {
|
||||
$data = $value;
|
||||
@@ -2392,9 +2400,9 @@ class Query
|
||||
$data = $value[1];
|
||||
}
|
||||
if (isset($data)) {
|
||||
return 'think:' . $options['table'] . '|' . $data;
|
||||
return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
|
||||
} else {
|
||||
return md5(serialize($options));
|
||||
return md5(serialize($options) . serialize($bind));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2422,7 +2430,7 @@ class Query
|
||||
// AR模式分析主键条件
|
||||
$this->parsePkWhere($data, $options);
|
||||
} elseif (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
|
||||
}
|
||||
|
||||
$options['limit'] = 1;
|
||||
@@ -2435,7 +2443,7 @@ class Query
|
||||
} elseif (is_string($cache['key'])) {
|
||||
$key = $cache['key'];
|
||||
} elseif (!isset($key)) {
|
||||
$key = md5(serialize($options));
|
||||
$key = md5(serialize($options) . serialize($this->bind));
|
||||
}
|
||||
$result = Cache::get($key);
|
||||
}
|
||||
@@ -2646,7 +2654,7 @@ class Query
|
||||
// AR模式分析主键条件
|
||||
$this->parsePkWhere($data, $options);
|
||||
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
||||
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
|
||||
}
|
||||
|
||||
if (true !== $data && empty($options['where'])) {
|
||||
|
||||
@@ -47,6 +47,9 @@ class Mysql extends Builder
|
||||
$key = '`' . $key . '`';
|
||||
}
|
||||
if (isset($table)) {
|
||||
if (strpos($table, '.')) {
|
||||
$table = str_replace('.', '`.`', $table);
|
||||
}
|
||||
$key = '`' . $table . '`.' . $key;
|
||||
}
|
||||
return $key;
|
||||
|
||||
@@ -21,7 +21,7 @@ class Sqlsrv extends Builder
|
||||
protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';
|
||||
protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%';
|
||||
protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
||||
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
||||
protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
||||
|
||||
/**
|
||||
* order分析
|
||||
|
||||
@@ -51,7 +51,7 @@ class Mysql extends Connection
|
||||
*/
|
||||
public function getFields($tableName)
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
list($tableName) = explode(' ', $tableName);
|
||||
if (false === strpos($tableName, '`')) {
|
||||
if (strpos($tableName, '.')) {
|
||||
@@ -91,7 +91,7 @@ class Mysql extends Connection
|
||||
*/
|
||||
public function getTables($dbName = '')
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
$sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';
|
||||
// 调试开始
|
||||
$this->debug(true);
|
||||
@@ -130,17 +130,4 @@ class Mysql extends Connection
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否断线
|
||||
* @access protected
|
||||
* @param \PDOException $e 异常对象
|
||||
* @return bool
|
||||
*/
|
||||
protected function isBreak($e)
|
||||
{
|
||||
if (false !== stripos($e->getMessage(), 'server has gone away')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class Pgsql extends Connection
|
||||
*/
|
||||
public function getFields($tableName)
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
list($tableName) = explode(' ', $tableName);
|
||||
$sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');';
|
||||
// 调试开始
|
||||
@@ -78,7 +78,7 @@ class Pgsql extends Connection
|
||||
*/
|
||||
public function getTables($dbName = '')
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
$sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'";
|
||||
// 调试开始
|
||||
$this->debug(true);
|
||||
|
||||
@@ -42,7 +42,7 @@ class Sqlite extends Connection
|
||||
*/
|
||||
public function getFields($tableName)
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
list($tableName) = explode(' ', $tableName);
|
||||
$sql = 'PRAGMA table_info( ' . $tableName . ' )';
|
||||
// 调试开始
|
||||
@@ -76,7 +76,7 @@ class Sqlite extends Connection
|
||||
*/
|
||||
public function getTables($dbName = '')
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
$sql = "SELECT name FROM sqlite_master WHERE type='table' "
|
||||
. "UNION ALL SELECT name FROM sqlite_temp_master "
|
||||
. "WHERE type='table' ORDER BY name";
|
||||
|
||||
@@ -49,7 +49,7 @@ class Sqlsrv extends Connection
|
||||
*/
|
||||
public function getFields($tableName)
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
list($tableName) = explode(' ', $tableName);
|
||||
$sql = "SELECT column_name, data_type, column_default, is_nullable
|
||||
FROM information_schema.tables AS t
|
||||
@@ -99,7 +99,7 @@ class Sqlsrv extends Connection
|
||||
*/
|
||||
public function getTables($dbName = '')
|
||||
{
|
||||
$this->initConnect(true);
|
||||
$this->initConnect(false);
|
||||
$sql = "SELECT TABLE_NAME
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_TYPE = 'BASE TABLE'
|
||||
|
||||
@@ -76,7 +76,7 @@ class File
|
||||
{
|
||||
//检测日志文件大小,超过配置大小则备份日志文件重新生成
|
||||
if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) {
|
||||
rename($destination, dirname($destination) . DS . $_SERVER['REQUEST_TIME'] . '-' . basename($destination));
|
||||
rename($destination, dirname($destination) . DS . time() . '-' . basename($destination));
|
||||
$this->writed[$destination] = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,20 @@ use think\Model;
|
||||
|
||||
class Collection extends BaseCollection
|
||||
{
|
||||
/**
|
||||
* 返回数组中指定的一列
|
||||
* @param string $column_key
|
||||
* @param string|null $index_key
|
||||
* @return array
|
||||
*/
|
||||
public function column($column_key, $index_key = null)
|
||||
{
|
||||
if (function_exists('array_column')) {
|
||||
return array_column($this->toArray(), $column_key, $index_key);
|
||||
}
|
||||
return parent::column($column_key, $index_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟预载入关联查询
|
||||
* @access public
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Model;
|
||||
|
||||
@@ -120,22 +121,19 @@ class Merge extends Model
|
||||
* @access public
|
||||
* @param string $model 模型名称
|
||||
* @param array $data 数据
|
||||
* @param bool $insert 是否新增
|
||||
* @return array
|
||||
*/
|
||||
protected function parseData($model, $data, $insert = false)
|
||||
protected function parseData($model, $data)
|
||||
{
|
||||
$item = [];
|
||||
foreach ($data as $key => $val) {
|
||||
if ($insert || in_array($key, $this->change) || $this->isPk($key)) {
|
||||
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {
|
||||
list($name, $key) = explode('.', $this->mapFields[$key]);
|
||||
if ($model == $name) {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
} else {
|
||||
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {
|
||||
list($name, $key) = explode('.', $this->mapFields[$key]);
|
||||
if ($model == $name) {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
} else {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $item;
|
||||
@@ -174,6 +172,11 @@ class Merge extends Model
|
||||
$this->setAttr($this->updateTime, null);
|
||||
}
|
||||
|
||||
// 事件回调
|
||||
if (false === $this->trigger('before_write', $this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$db = $this->db();
|
||||
$db->startTrans();
|
||||
$pk = $this->getPk();
|
||||
@@ -190,8 +193,16 @@ class Merge extends Model
|
||||
$where = $this->updateWhere;
|
||||
}
|
||||
|
||||
// 获取有更新的数据
|
||||
$data = $this->getChangedData();
|
||||
// 保留主键数据
|
||||
foreach ($this->data as $key => $val) {
|
||||
if ($this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
// 处理模型数据
|
||||
$data = $this->parseData($this->name, $this->data);
|
||||
$data = $this->parseData($this->name, $data);
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
@@ -207,14 +218,12 @@ class Merge extends Model
|
||||
$name = is_int($key) ? $model : $key;
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $this->data);
|
||||
$query = new Query;
|
||||
if ($query->table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||
$data = $this->parseData($name, $data);
|
||||
if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||
$result = 1;
|
||||
}
|
||||
}
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
|
||||
// 新增回调
|
||||
$this->trigger('after_update', $this);
|
||||
} else {
|
||||
@@ -231,7 +240,7 @@ class Merge extends Model
|
||||
}
|
||||
|
||||
// 处理模型数据
|
||||
$data = $this->parseData($this->name, $this->data, true);
|
||||
$data = $this->parseData($this->name, $this->data);
|
||||
// 写入主表数据
|
||||
$result = $db->name($this->name)->strict(false)->insert($data);
|
||||
if ($result) {
|
||||
@@ -240,9 +249,6 @@ class Merge extends Model
|
||||
if ($insertId) {
|
||||
if (is_string($pk)) {
|
||||
$this->data[$pk] = $insertId;
|
||||
if ($this->fk == $pk) {
|
||||
$this->change[] = $pk;
|
||||
}
|
||||
}
|
||||
$this->data[$this->fk] = $insertId;
|
||||
}
|
||||
@@ -256,19 +262,20 @@ class Merge extends Model
|
||||
$name = is_int($key) ? $model : $key;
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $source, true);
|
||||
$query = new Query;
|
||||
$query->table($table)->strict(false)->insert($data);
|
||||
$data = $this->parseData($name, $source);
|
||||
Db::table($table)->strict(false)->insert($data);
|
||||
}
|
||||
}
|
||||
// 标记为更新
|
||||
$this->isUpdate = true;
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
// 新增回调
|
||||
$this->trigger('after_insert', $this);
|
||||
}
|
||||
$db->commit();
|
||||
// 写入回调
|
||||
$this->trigger('after_write', $this);
|
||||
|
||||
$this->origin = $this->data;
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
$db->rollback();
|
||||
|
||||
@@ -19,24 +19,26 @@ class Pivot extends Model
|
||||
/** @var Model */
|
||||
public $parent;
|
||||
|
||||
protected $autoWriteTimestamp = false;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param Model $parent
|
||||
* @param array|object $data 数据
|
||||
* @param string $table 中间数据表名
|
||||
* @param Model $parent 上级模型
|
||||
* @param array|object $data 数据
|
||||
* @param string $table 中间数据表名
|
||||
*/
|
||||
public function __construct(Model $parent, $data = [], $table = '')
|
||||
{
|
||||
if (is_object($data)) {
|
||||
$this->data = get_object_vars($data);
|
||||
} else {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
$this->parent = $parent;
|
||||
|
||||
$this->table = $table;
|
||||
if (is_null($this->name)) {
|
||||
$this->name = $table;
|
||||
}
|
||||
|
||||
parent::__construct($data);
|
||||
|
||||
$this->class = $this->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ abstract class Relation
|
||||
protected $foreignKey;
|
||||
// 关联表主键
|
||||
protected $localKey;
|
||||
// 关联查询参数
|
||||
protected $option;
|
||||
// 基础查询
|
||||
protected $baseQuery;
|
||||
|
||||
@@ -79,15 +77,30 @@ abstract class Relation
|
||||
return (new $this->model)->toCollection($resultSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除关联查询参数
|
||||
* @access public
|
||||
* @return $this
|
||||
*/
|
||||
public function removeOption()
|
||||
protected function getQueryFields($model)
|
||||
{
|
||||
$this->query->removeOption();
|
||||
return $this;
|
||||
$fields = $this->query->getOptions('field');
|
||||
return $this->getRelationQueryFields($fields, $model);
|
||||
}
|
||||
|
||||
protected function getRelationQueryFields($fields, $model)
|
||||
{
|
||||
if ($fields) {
|
||||
|
||||
if (is_string($fields)) {
|
||||
$fields = explode(',', $fields);
|
||||
}
|
||||
|
||||
foreach ($fields as &$field) {
|
||||
if (false === strpos($field, '.')) {
|
||||
$field = $model . '.' . $field;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fields = $model . '.*';
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,10 +118,8 @@ abstract class Relation
|
||||
|
||||
$result = call_user_func_array([$this->query, $method], $args);
|
||||
if ($result instanceof Query) {
|
||||
$this->option = $result->getOptions();
|
||||
return $this;
|
||||
} else {
|
||||
$this->option = [];
|
||||
$this->baseQuery = false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ class BelongsTo extends OneToOne
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $localKey 关联主键
|
||||
* @param string $joinType JOIN类型
|
||||
* @param string $relation 关联名
|
||||
*/
|
||||
public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER')
|
||||
public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER', $relation = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
@@ -33,6 +34,7 @@ class BelongsTo extends OneToOne
|
||||
$this->localKey = $localKey;
|
||||
$this->joinType = $joinType;
|
||||
$this->query = (new $model)->db();
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +50,16 @@ class BelongsTo extends OneToOne
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->query->where($this->localKey, $this->parent->$foreignKey)->relation($subRelation)->find();
|
||||
$relationModel = $this->query
|
||||
->where($this->localKey, $this->parent->$foreignKey)
|
||||
->relation($subRelation)
|
||||
->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +139,8 @@ class BelongsTo extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$foreignKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
@@ -135,7 +148,7 @@ class BelongsTo extends OneToOne
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($attr, $relationModel);
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,13 +172,46 @@ class BelongsTo extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$foreignKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr(Loader::parseName($relation), $relationModel);
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加关联数据
|
||||
* @access public
|
||||
* @param Model $model 关联模型对象
|
||||
* @return Model
|
||||
*/
|
||||
public function associate($model)
|
||||
{
|
||||
$foreignKey = $this->foreignKey;
|
||||
$pk = $model->getPk();
|
||||
|
||||
$this->parent->setAttr($foreignKey, $model->$pk);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销关联数据
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function dissociate()
|
||||
{
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$this->parent->setAttr($foreignKey, null);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ class BelongsToMany extends Relation
|
||||
{
|
||||
// 中间表表名
|
||||
protected $middle;
|
||||
|
||||
// 中间表模型
|
||||
// 中间表模型名称
|
||||
protected $pivotName;
|
||||
// 中间表模型对象
|
||||
protected $pivot;
|
||||
|
||||
/**
|
||||
@@ -43,8 +44,14 @@ class BelongsToMany extends Relation
|
||||
$this->model = $model;
|
||||
$this->foreignKey = $foreignKey;
|
||||
$this->localKey = $localKey;
|
||||
$this->middle = $table;
|
||||
$this->query = (new $model)->db();
|
||||
if (false !== strpos($table, '\\')) {
|
||||
$this->pivotName = $table;
|
||||
$this->middle = basename(str_replace('\\', '/', $table));
|
||||
} else {
|
||||
$this->middle = $table;
|
||||
}
|
||||
$this->query = (new $model)->db();
|
||||
$this->pivot = $this->newPivot();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +61,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function pivot($pivot)
|
||||
{
|
||||
$this->pivot = $pivot;
|
||||
$this->pivotName = $pivot;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -63,9 +70,9 @@ class BelongsToMany extends Relation
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function newPivot($data)
|
||||
protected function newPivot($data = [])
|
||||
{
|
||||
$pivot = $this->pivot ?: '\\think\\model\\Pivot';
|
||||
$pivot = $this->pivotName ?: '\\think\\model\\Pivot';
|
||||
return new $pivot($this->parent, $data, $this->middle);
|
||||
}
|
||||
|
||||
@@ -102,7 +109,7 @@ class BelongsToMany extends Relation
|
||||
// 关联查询
|
||||
$pk = $this->parent->getPk();
|
||||
$condition['pivot.' . $localKey] = $this->parent->$pk;
|
||||
return $this->belongsToManyQuery($middle, $foreignKey, $localKey, $condition);
|
||||
return $this->belongsToManyQuery($foreignKey, $localKey, $condition);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +121,7 @@ class BelongsToMany extends Relation
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [& $this->query]);
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$result = $this->buildQuery()->relation($subRelation)->select();
|
||||
$this->hydratePivot($result);
|
||||
@@ -260,7 +267,7 @@ class BelongsToMany extends Relation
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,7 +293,7 @@ class BelongsToMany extends Relation
|
||||
if (!isset($data[$pk])) {
|
||||
$data[$pk] = [];
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$pk]));
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$pk]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +310,7 @@ class BelongsToMany extends Relation
|
||||
$count = 0;
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
$count = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();
|
||||
$count = $this->belongsToManyQuery($this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
@@ -316,7 +323,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function getRelationCountQuery($closure)
|
||||
{
|
||||
return $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, [
|
||||
return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [
|
||||
'pivot.' . $this->localKey => [
|
||||
'exp',
|
||||
'=' . $this->parent->getTable() . '.' . $this->parent->getPk(),
|
||||
@@ -335,7 +342,7 @@ class BelongsToMany extends Relation
|
||||
protected function eagerlyManyToMany($where, $relation, $subRelation = '')
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
$list = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, $where)->with($subRelation)->select();
|
||||
$list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where)->with($subRelation)->select();
|
||||
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
@@ -359,21 +366,23 @@ class BelongsToMany extends Relation
|
||||
/**
|
||||
* BELONGS TO MANY 关联查询
|
||||
* @access public
|
||||
* @param string $table 中间表名
|
||||
* @param string $foreignKey 关联模型关联键
|
||||
* @param string $localKey 当前模型关联键
|
||||
* @param array $condition 关联查询条件
|
||||
* @return Query
|
||||
*/
|
||||
protected function belongsToManyQuery($table, $foreignKey, $localKey, $condition = [])
|
||||
protected function belongsToManyQuery($foreignKey, $localKey, $condition = [])
|
||||
{
|
||||
// 关联查询封装
|
||||
$tableName = $this->query->getTable();
|
||||
$relationFk = $this->query->getPk();
|
||||
$query = $this->query->field($tableName . '.*')
|
||||
$tableName = $this->query->getTable();
|
||||
$table = $this->pivot->getTable();
|
||||
$fields = $this->getQueryFields($tableName);
|
||||
|
||||
$query = $this->query->field($fields)
|
||||
->field(true, false, $table, 'pivot', 'pivot__');
|
||||
|
||||
if (empty($this->baseQuery)) {
|
||||
$relationFk = $this->query->getPk();
|
||||
$query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
||||
->where($condition);
|
||||
}
|
||||
@@ -450,7 +459,7 @@ class BelongsToMany extends Relation
|
||||
$ids = (array) $id;
|
||||
foreach ($ids as $id) {
|
||||
$pivot[$this->foreignKey] = $id;
|
||||
$this->query->table($this->middle)->insert($pivot, true);
|
||||
$this->pivot->insert($pivot, true);
|
||||
$result[] = $this->newPivot($pivot);
|
||||
}
|
||||
if (count($result) == 1) {
|
||||
@@ -488,8 +497,7 @@ class BelongsToMany extends Relation
|
||||
if (isset($id)) {
|
||||
$pivot[$this->foreignKey] = is_array($id) ? ['in', $id] : $id;
|
||||
}
|
||||
$this->query->table($this->middle)->where($pivot)->delete();
|
||||
|
||||
$this->pivot->where($pivot)->delete();
|
||||
// 删除关联表数据
|
||||
if (isset($id) && $relationDel) {
|
||||
$model = $this->model;
|
||||
@@ -497,6 +505,55 @@ class BelongsToMany extends Relation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据同步
|
||||
* @param array $ids
|
||||
* @param bool $detaching
|
||||
* @return array
|
||||
*/
|
||||
public function sync($ids, $detaching = true)
|
||||
{
|
||||
$changes = [
|
||||
'attached' => [],
|
||||
'detached' => [],
|
||||
'updated' => [],
|
||||
];
|
||||
$pk = $this->parent->getPk();
|
||||
$current = $this->pivot->where($this->localKey, $this->parent->$pk)
|
||||
->column($this->foreignKey);
|
||||
$records = [];
|
||||
|
||||
foreach ($ids as $key => $value) {
|
||||
if (!is_array($value)) {
|
||||
$records[$value] = [];
|
||||
} else {
|
||||
$records[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$detach = array_diff($current, array_keys($records));
|
||||
|
||||
if ($detaching && count($detach) > 0) {
|
||||
$this->detach($detach);
|
||||
|
||||
$changes['detached'] = $detach;
|
||||
}
|
||||
|
||||
foreach ($records as $id => $attributes) {
|
||||
if (!in_array($id, $current)) {
|
||||
$this->attach($id, $attributes);
|
||||
$changes['attached'][] = $id;
|
||||
} elseif (count($attributes) > 0 &&
|
||||
$this->attach($id, $attributes)
|
||||
) {
|
||||
$changes['updated'][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $changes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
* @access protected
|
||||
@@ -504,9 +561,10 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
$pk = $this->parent->getPk();
|
||||
$this->query->join($this->middle . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$table = $this->pivot->getTable();
|
||||
$this->query->join($table . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);
|
||||
$this->baseQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
@@ -47,7 +46,14 @@ class HasMany extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->relation($subRelation)->select();
|
||||
$list = $this->relation($subRelation)->select();
|
||||
$parent = clone $this->parent;
|
||||
|
||||
foreach ($list as &$model) {
|
||||
$model->setParent($parent);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +90,12 @@ class HasMany extends Relation
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$localKey]));
|
||||
|
||||
foreach ($data[$result->$localKey] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$localKey]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +119,12 @@ class HasMany extends Relation
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$result->$localKey]));
|
||||
|
||||
foreach ($data[$result->$localKey] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$localKey]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@@ -57,6 +56,7 @@ class HasManyThrough extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
|
||||
return $this->relation($subRelation)->select();
|
||||
}
|
||||
|
||||
@@ -96,8 +96,7 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 预载入关联查询 返回模型对象
|
||||
@@ -110,8 +109,7 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
@@ -121,8 +119,7 @@ class HasManyThrough extends Relation
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
@@ -131,12 +128,11 @@ class HasManyThrough extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$through = $this->through;
|
||||
$model = $this->model;
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $this->model)));
|
||||
$throughTable = $through::getTable();
|
||||
$pk = (new $this->model)->getPk();
|
||||
$pk = (new $through)->getPk();
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = $this->parent->getTable();
|
||||
$this->query->field($alias . '.*')->alias($alias)
|
||||
|
||||
@@ -50,7 +50,13 @@ class HasOne extends OneToOne
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
// 判断关联类型执行查询
|
||||
return $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find();
|
||||
$relationModel = $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,13 +138,15 @@ class HasOne extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$localKey];
|
||||
}
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($attr, $relationModel);
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,13 +171,15 @@ class HasOne extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$localKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
}
|
||||
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $relationModel);
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@@ -56,7 +55,14 @@ class MorphMany extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->relation($subRelation)->select();
|
||||
$list = $this->relation($subRelation)->select();
|
||||
$parent = clone $this->parent;
|
||||
|
||||
foreach ($list as &$model) {
|
||||
$model->setParent($parent);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +125,11 @@ class MorphMany extends Relation
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
foreach ($data[$result->$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +151,17 @@ class MorphMany extends Relation
|
||||
$this->morphKey => $result->$pk,
|
||||
$this->morphType => $this->type,
|
||||
], $relation, $subRelation, $closure);
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$result->$pk]));
|
||||
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
|
||||
foreach ($data[$result->$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +273,7 @@ class MorphMany extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$map[$this->morphKey] = $this->parent->$pk;
|
||||
$map[$this->morphType] = $this->type;
|
||||
|
||||
229
core/library/think/model/relation/MorphOne.php
Normal file
229
core/library/think/model/relation/MorphOne.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\model\Relation;
|
||||
|
||||
class MorphOne extends Relation
|
||||
{
|
||||
// 多态字段
|
||||
protected $morphKey;
|
||||
protected $morphType;
|
||||
// 多态类型
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @access public
|
||||
* @param Model $parent 上级模型对象
|
||||
* @param string $model 模型名
|
||||
* @param string $morphKey 关联外键
|
||||
* @param string $morphType 多态字段名
|
||||
* @param string $type 多态类型
|
||||
*/
|
||||
public function __construct(Model $parent, $model, $morphKey, $morphType, $type)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
$this->type = $type;
|
||||
$this->morphKey = $morphKey;
|
||||
$this->morphType = $morphType;
|
||||
$this->query = (new $model)->db();
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟获取关联数据
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包查询条件
|
||||
* @return false|\PDOStatement|string|\think\Collection
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$relationModel = $this->relation($subRelation)->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关联条件查询当前模型
|
||||
* @access public
|
||||
* @param string $operator 比较操作符
|
||||
* @param integer $count 个数
|
||||
* @param string $id 关联表的统计字段
|
||||
* @param string $joinType JOIN类型
|
||||
* @return Query
|
||||
*/
|
||||
public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关联条件查询当前模型
|
||||
* @access public
|
||||
* @param mixed $where 查询条件(数组或者闭包)
|
||||
* @return Query
|
||||
*/
|
||||
public function hasWhere($where = [])
|
||||
{
|
||||
throw new Exception('relation not support: hasWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
|
||||
{
|
||||
$morphType = $this->morphType;
|
||||
$morphKey = $this->morphKey;
|
||||
$type = $this->type;
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
$pk = $result->getPk();
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$pk)) {
|
||||
$range[] = $result->$pk;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$data = $this->eagerlyMorphToOne([
|
||||
$morphKey => ['in', $range],
|
||||
$morphType => $type,
|
||||
], $relation, $subRelation, $closure);
|
||||
// 关联属性名
|
||||
$attr = Loader::parseName($relation);
|
||||
// 关联数据封装
|
||||
foreach ($resultSet as $result) {
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$pk];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure)
|
||||
{
|
||||
$pk = $result->getPk();
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
$data = $this->eagerlyMorphToOne([
|
||||
$this->morphKey => $pk,
|
||||
$this->morphType => $this->type,
|
||||
], $relation, $subRelation, $closure);
|
||||
|
||||
if (isset($data[$pk])) {
|
||||
$relationModel = $data[$pk];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
} else {
|
||||
$relationModel = null;
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多态一对一 关联模型预查询
|
||||
* @access public
|
||||
* @param array $where 关联预查询条件
|
||||
* @param string $relation 关联名
|
||||
* @param string $subRelation 子关联
|
||||
* @param bool|\Closure $closure 闭包
|
||||
* @return array
|
||||
*/
|
||||
protected function eagerlyMorphToOne($where, $relation, $subRelation = '', $closure = false)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this]);
|
||||
}
|
||||
$list = $this->query->where($where)->with($subRelation)->find();
|
||||
$morphKey = $this->morphKey;
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
foreach ($list as $set) {
|
||||
$data[$set->$morphKey][] = $set;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存(新增)当前关联数据对象
|
||||
* @access public
|
||||
* @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键
|
||||
* @return Model|false
|
||||
*/
|
||||
public function save($data)
|
||||
{
|
||||
if ($data instanceof Model) {
|
||||
$data = $data->getData();
|
||||
}
|
||||
// 保存关联表数据
|
||||
$pk = $this->parent->getPk();
|
||||
|
||||
$model = new $this->model;
|
||||
$data[$this->morphKey] = $this->parent->$pk;
|
||||
$data[$this->morphType] = $this->type;
|
||||
return $model->save($data) ? $model : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$map[$this->morphKey] = $this->parent->$pk;
|
||||
$map[$this->morphType] = $this->type;
|
||||
$this->query->where($map);
|
||||
$this->baseQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ class MorphTo extends Relation
|
||||
protected $morphType;
|
||||
// 多态别名
|
||||
protected $alias;
|
||||
protected $relation;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
@@ -31,13 +32,15 @@ class MorphTo extends Relation
|
||||
* @param string $morphType 多态字段名
|
||||
* @param string $morphKey 外键名
|
||||
* @param array $alias 多态别名定义
|
||||
* @param string $relation 关联名
|
||||
*/
|
||||
public function __construct(Model $parent, $morphType, $morphKey, $alias = [])
|
||||
public function __construct(Model $parent, $morphType, $morphKey, $alias = [], $relation = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->morphType = $morphType;
|
||||
$this->morphKey = $morphKey;
|
||||
$this->alias = $alias;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +56,13 @@ class MorphTo extends Relation
|
||||
// 多态模型
|
||||
$model = $this->parseModel($this->parent->$morphType);
|
||||
// 主键数据
|
||||
$pk = $this->parent->$morphKey;
|
||||
return (new $model)->relation($subRelation)->find($pk);
|
||||
$pk = $this->parent->$morphKey;
|
||||
$relationModel = (new $model)->relation($subRelation)->find($pk);
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +173,11 @@ class MorphTo extends Relation
|
||||
if (!isset($data[$result->$morphKey])) {
|
||||
throw new Exception('relation data not exists :' . $this->model);
|
||||
} else {
|
||||
$result->setAttr($attr, $data[$result->$morphKey]);
|
||||
$relationModel = $data[$result->$morphKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,9 +229,46 @@ class MorphTo extends Relation
|
||||
$pk = $this->parent->{$this->morphKey};
|
||||
$data = (new $model)->with($subRelation)->find($pk);
|
||||
if ($data) {
|
||||
$data->setParent(clone $result);
|
||||
$data->isUpdate(true);
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $data ?: null);
|
||||
$result->setRelation(Loader::parseName($relation), $data ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加关联数据
|
||||
* @access public
|
||||
* @param Model $model 关联模型对象
|
||||
* @return Model
|
||||
*/
|
||||
public function associate($model)
|
||||
{
|
||||
$morphKey = $this->morphKey;
|
||||
$morphType = $this->morphType;
|
||||
$pk = $model->getPk();
|
||||
|
||||
$this->parent->setAttr($morphKey, $model->$pk);
|
||||
$this->parent->setAttr($morphType, get_class($model));
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销关联数据
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function dissociate()
|
||||
{
|
||||
$morphKey = $this->morphKey;
|
||||
$morphType = $this->morphType;
|
||||
|
||||
$this->parent->setAttr($morphKey, null);
|
||||
$this->parent->setAttr($morphType, null);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +277,5 @@ class MorphTo extends Relation
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ abstract class OneToOne extends Relation
|
||||
protected $joinType;
|
||||
// 要绑定的属性
|
||||
protected $bindAttr = [];
|
||||
// 关联方法名
|
||||
protected $relation;
|
||||
|
||||
/**
|
||||
* 设置join类型
|
||||
@@ -243,13 +245,19 @@ abstract class OneToOne extends Relation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($list[$relation])) {
|
||||
$relationModel = new $model($list[$relation]);
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
|
||||
if (!empty($this->bindAttr)) {
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
} else {
|
||||
$relationModel = null;
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), !isset($relationModel) ? null : $relationModel->isUpdate(true));
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,6 +317,5 @@ abstract class OneToOne extends Relation
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ trait SoftDelete
|
||||
{
|
||||
$model = new static();
|
||||
$field = $model->getDeleteTimeField(true);
|
||||
return $model->db(false);
|
||||
return $model->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ trait SoftDelete
|
||||
{
|
||||
$model = new static();
|
||||
$field = $model->getDeleteTimeField(true);
|
||||
return $model->db(false)
|
||||
return $model->getQuery()
|
||||
->useSoftDelete($field, ['not null', '']);
|
||||
}
|
||||
|
||||
@@ -60,11 +60,10 @@ trait SoftDelete
|
||||
$name = $this->getDeleteTimeField();
|
||||
if (!$force) {
|
||||
// 软删除
|
||||
$this->change[] = $name;
|
||||
$this->data[$name] = $this->autoWriteTimestamp($name);
|
||||
$result = $this->isUpdate()->save();
|
||||
} else {
|
||||
$result = $this->db(false)->delete($this->data);
|
||||
$result = $this->getQuery()->delete($this->data);
|
||||
}
|
||||
|
||||
$this->trigger('after_delete', $this);
|
||||
@@ -117,7 +116,7 @@ trait SoftDelete
|
||||
$where[$pk] = $this->getData($pk);
|
||||
}
|
||||
// 恢复删除
|
||||
return $this->db(false)
|
||||
return $this->getQuery()
|
||||
->useSoftDelete($name, ['not null', ''])
|
||||
->where($where)
|
||||
->update([$name => null]);
|
||||
@@ -143,7 +142,7 @@ trait SoftDelete
|
||||
*/
|
||||
protected function getDeleteTimeField($read = false)
|
||||
{
|
||||
$field = isset($this->deleteTime) ? $this->deleteTime : 'delete_time';
|
||||
$field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time';
|
||||
if (!strpos($field, '.')) {
|
||||
$field = '__TABLE__.' . $field;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?php echo lang('System Error'); ?></title>
|
||||
<title><?php echo \think\Lang::get('System Error'); ?></title>
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user