更新内核,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;
|
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>
|
// | 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_TIME', microtime(true));
|
||||||
define('THINK_START_MEM', memory_get_usage());
|
define('THINK_START_MEM', memory_get_usage());
|
||||||
define('EXT', '.php');
|
define('EXT', '.php');
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ return [
|
|||||||
// | 应用设置
|
// | 应用设置
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
// 应用命名空间
|
|
||||||
'app_namespace' => 'app',
|
|
||||||
// 应用调试模式
|
// 应用调试模式
|
||||||
'app_debug' => true,
|
'app_debug' => true,
|
||||||
// 应用Trace
|
// 应用Trace
|
||||||
@@ -91,6 +89,8 @@ return [
|
|||||||
'url_route_must' => false,
|
'url_route_must' => false,
|
||||||
// 域名部署
|
// 域名部署
|
||||||
'url_domain_deploy' => false,
|
'url_domain_deploy' => false,
|
||||||
|
// 默认Host地址
|
||||||
|
'default_host' => '',
|
||||||
// 域名根,如thinkphp.cn
|
// 域名根,如thinkphp.cn
|
||||||
'url_domain_root' => '',
|
'url_domain_root' => '',
|
||||||
// 是否自动转换URL中的控制器和操作名
|
// 是否自动转换URL中的控制器和操作名
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ if (!function_exists('db')) {
|
|||||||
* @param bool $force 是否强制重新连接
|
* @param bool $force 是否强制重新连接
|
||||||
* @return \think\db\Query
|
* @return \think\db\Query
|
||||||
*/
|
*/
|
||||||
function db($name = '', $config = [], $force = true)
|
function db($name = '', $config = [], $force = false)
|
||||||
{
|
{
|
||||||
return Db::connect($config, $force)->name($name);
|
return Db::connect($config, $force)->name($name);
|
||||||
}
|
}
|
||||||
@@ -354,22 +354,25 @@ if (!function_exists('cache')) {
|
|||||||
{
|
{
|
||||||
if (is_array($options)) {
|
if (is_array($options)) {
|
||||||
// 缓存操作的同时初始化
|
// 缓存操作的同时初始化
|
||||||
Cache::connect($options);
|
$cache = Cache::connect($options);
|
||||||
} elseif (is_array($name)) {
|
} elseif (is_array($name)) {
|
||||||
// 缓存初始化
|
// 缓存初始化
|
||||||
return Cache::connect($name);
|
return Cache::connect($name);
|
||||||
|
} else {
|
||||||
|
$cache = Cache::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($name)) {
|
if (is_null($name)) {
|
||||||
return Cache::clear($value);
|
return $cache->clear($value);
|
||||||
} elseif ('' === $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)) {
|
} elseif (is_null($value)) {
|
||||||
// 删除缓存
|
// 删除缓存
|
||||||
return Cache::rm($name);
|
return $cache->rm($name);
|
||||||
} elseif (0 === strpos($name, '?') && '' !== $value) {
|
} elseif (0 === strpos($name, '?') && '' !== $value) {
|
||||||
$expire = is_numeric($options) ? $options : null;
|
$expire = is_numeric($options) ? $options : null;
|
||||||
return Cache::remember(substr($name, 1), $value, $expire);
|
return $cache->remember(substr($name, 1), $value, $expire);
|
||||||
} else {
|
} else {
|
||||||
// 缓存数据
|
// 缓存数据
|
||||||
if (is_array($options)) {
|
if (is_array($options)) {
|
||||||
@@ -378,9 +381,9 @@ if (!function_exists('cache')) {
|
|||||||
$expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
|
$expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
|
||||||
}
|
}
|
||||||
if (is_null($tag)) {
|
if (is_null($tag)) {
|
||||||
return Cache::set($name, $value, $expire);
|
return $cache->set($name, $value, $expire);
|
||||||
} else {
|
} 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()
|
public static function initCommon()
|
||||||
{
|
{
|
||||||
if (empty(self::$init)) {
|
if (empty(self::$init)) {
|
||||||
|
if (defined('APP_NAMESPACE')) {
|
||||||
|
self::$namespace = APP_NAMESPACE;
|
||||||
|
}
|
||||||
|
Loader::addNamespace(self::$namespace, APP_PATH);
|
||||||
|
|
||||||
// 初始化应用
|
// 初始化应用
|
||||||
$config = self::init();
|
$config = self::init();
|
||||||
self::$suffix = $config['class_suffix'];
|
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'])) {
|
if (!empty($config['root_namespace'])) {
|
||||||
Loader::addNamespace($config['root_namespace']);
|
Loader::addNamespace($config['root_namespace']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,28 +51,29 @@ class Cache
|
|||||||
self::$instance[$name] = new $class($options);
|
self::$instance[$name] = new $class($options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self::$handler = self::$instance[$name];
|
return self::$instance[$name];
|
||||||
return self::$handler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自动初始化缓存
|
* 自动初始化缓存
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $options 配置数组
|
* @param array $options 配置数组
|
||||||
* @return void
|
* @return Driver
|
||||||
*/
|
*/
|
||||||
public static function init(array $options = [])
|
public static function init(array $options = [])
|
||||||
{
|
{
|
||||||
if (is_null(self::$handler)) {
|
if (is_null(self::$handler)) {
|
||||||
// 自动初始化缓存
|
// 自动初始化缓存
|
||||||
if (!empty($options)) {
|
if (!empty($options)) {
|
||||||
self::connect($options);
|
$connect = self::connect($options);
|
||||||
} elseif ('complex' == Config::get('cache.type')) {
|
} elseif ('complex' == Config::get('cache.type')) {
|
||||||
self::connect(Config::get('cache.default'));
|
$connect = self::connect(Config::get('cache.default'));
|
||||||
} else {
|
} 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 = '')
|
public static function store($name = '')
|
||||||
{
|
{
|
||||||
if ('' !== $name && 'complex' == Config::get('cache.type')) {
|
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)
|
public static function has($name)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$readTimes++;
|
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)
|
public static function get($name, $default = false)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$readTimes++;
|
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)
|
public static function set($name, $value, $expire = null)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$writeTimes++;
|
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)
|
public static function inc($name, $step = 1)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$writeTimes++;
|
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)
|
public static function dec($name, $step = 1)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$writeTimes++;
|
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)
|
public static function rm($name)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$writeTimes++;
|
self::$writeTimes++;
|
||||||
return self::$handler->rm($name);
|
return self::init()->rm($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,9 +175,8 @@ class Cache
|
|||||||
*/
|
*/
|
||||||
public static function clear($tag = null)
|
public static function clear($tag = null)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$writeTimes++;
|
self::$writeTimes++;
|
||||||
return self::$handler->clear($tag);
|
return self::init()->clear($tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,10 +187,9 @@ class Cache
|
|||||||
*/
|
*/
|
||||||
public static function pull($name)
|
public static function pull($name)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$readTimes++;
|
self::$readTimes++;
|
||||||
self::$writeTimes++;
|
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)
|
public static function remember($name, $value, $expire = null)
|
||||||
{
|
{
|
||||||
self::init();
|
|
||||||
self::$readTimes++;
|
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)
|
public static function tag($name, $keys = null, $overlay = false)
|
||||||
{
|
{
|
||||||
self::init();
|
return self::init()->tag($name, $keys, $overlay);
|
||||||
return self::$handler->tag($name, $keys, $overlay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,22 +135,35 @@ class Cookie
|
|||||||
* @param string|null $prefix cookie前缀
|
* @param string|null $prefix cookie前缀
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function get($name, $prefix = null)
|
public static function get($name = '', $prefix = null)
|
||||||
{
|
{
|
||||||
!isset(self::$init) && self::init();
|
!isset(self::$init) && self::init();
|
||||||
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
|
$prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
|
||||||
$name = $prefix . $name;
|
$key = $prefix . $name;
|
||||||
if (isset($_COOKIE[$name])) {
|
|
||||||
$value = $_COOKIE[$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:')) {
|
if (0 === strpos($value, 'think:')) {
|
||||||
$value = substr($value, 6);
|
$value = substr($value, 6);
|
||||||
$value = json_decode($value, true);
|
$value = json_decode($value, true);
|
||||||
array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
|
array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
|
||||||
}
|
}
|
||||||
return $value;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
$value = null;
|
||||||
}
|
}
|
||||||
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ use think\db\Query;
|
|||||||
* @method integer update(array $data) static 更新记录
|
* @method integer update(array $data) static 更新记录
|
||||||
* @method integer delete(mixed $data = null) static 删除记录
|
* @method integer delete(mixed $data = null) static 删除记录
|
||||||
* @method boolean chunk(integer $count, callable $callback, string $column = 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 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 Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) static 分页查询
|
||||||
* @method mixed transaction(callable $callback) static 执行数据库事务
|
* @method mixed transaction(callable $callback) static 执行数据库事务
|
||||||
@@ -44,6 +44,8 @@ use think\db\Query;
|
|||||||
* @method void commit() static 用于非自动提交状态下面的查询提交
|
* @method void commit() static 用于非自动提交状态下面的查询提交
|
||||||
* @method void rollback() static 事务回滚
|
* @method void rollback() static 事务回滚
|
||||||
* @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
|
* @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
|
||||||
|
* @method string quote(string $str) static SQL指令安全过滤
|
||||||
|
* @method string getLastInsID($sequence = null) static 获取最近插入的ID
|
||||||
*/
|
*/
|
||||||
class Db
|
class Db
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Debug
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统计某个区间的时间(微秒)使用情况
|
* 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
|
||||||
* @param string $start 开始标签
|
* @param string $start 开始标签
|
||||||
* @param string $end 结束标签
|
* @param string $end 结束标签
|
||||||
* @param integer|string $dec 小数位
|
* @param integer|string $dec 小数位
|
||||||
@@ -53,7 +53,7 @@ class Debug
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统计从开始到统计时的时间(微秒)使用情况
|
* 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
|
||||||
* @param integer|string $dec 小数位
|
* @param integer|string $dec 小数位
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ class Lang
|
|||||||
protected static $langCookieExpire = 3600;
|
protected static $langCookieExpire = 3600;
|
||||||
// 允许语言列表
|
// 允许语言列表
|
||||||
protected static $allowLangList = [];
|
protected static $allowLangList = [];
|
||||||
|
// Accept-Language转义为对应语言包名称 系统默认配置
|
||||||
|
protected static $acceptLanguage = [
|
||||||
|
'zh-hans-cn' => 'zh-cn',
|
||||||
|
];
|
||||||
|
|
||||||
// 设定当前的语言
|
// 设定当前的语言
|
||||||
public static function range($range = '')
|
public static function range($range = '')
|
||||||
@@ -34,6 +38,7 @@ class Lang
|
|||||||
} else {
|
} else {
|
||||||
self::$range = $range;
|
self::$range = $range;
|
||||||
}
|
}
|
||||||
|
return self::$range;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,7 +98,6 @@ class Lang
|
|||||||
/**
|
/**
|
||||||
* 获取语言定义(不区分大小写)
|
* 获取语言定义(不区分大小写)
|
||||||
* @param string|null $name 语言变量
|
* @param string|null $name 语言变量
|
||||||
* @param array $vars 变量替换
|
|
||||||
* @param string $range 语言作用域
|
* @param string $range 语言作用域
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@@ -152,26 +156,25 @@ class Lang
|
|||||||
{
|
{
|
||||||
// 自动侦测设置获取语言选择
|
// 自动侦测设置获取语言选择
|
||||||
$langSet = '';
|
$langSet = '';
|
||||||
|
|
||||||
if (isset($_GET[self::$langDetectVar])) {
|
if (isset($_GET[self::$langDetectVar])) {
|
||||||
// url中设置了语言变量
|
// url中设置了语言变量
|
||||||
$langSet = strtolower($_GET[self::$langDetectVar]);
|
$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'])) {
|
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||||
// 自动侦测浏览器语言
|
// 自动侦测浏览器语言
|
||||||
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
|
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
|
||||||
$langSet = strtolower($matches[1]);
|
$langSet = strtolower($matches[1]);
|
||||||
Cookie::set(self::$langCookieVar, $langSet, self::$langCookieExpire);
|
$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)) {
|
if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
|
||||||
// 合法的语言
|
// 合法的语言
|
||||||
self::$range = $langSet ?: self::$range;
|
self::$range = $langSet ?: self::$range;
|
||||||
}
|
}
|
||||||
if ('zh-hans-cn' == self::$range) {
|
|
||||||
self::$range = 'zh-cn';
|
|
||||||
}
|
|
||||||
return self::$range;
|
return self::$range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use think\model\relation\HasMany;
|
|||||||
use think\model\relation\HasManyThrough;
|
use think\model\relation\HasManyThrough;
|
||||||
use think\model\relation\HasOne;
|
use think\model\relation\HasOne;
|
||||||
use think\model\relation\MorphMany;
|
use think\model\relation\MorphMany;
|
||||||
|
use think\model\relation\MorphOne;
|
||||||
use think\model\relation\MorphTo;
|
use think\model\relation\MorphTo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,10 +32,12 @@ use think\model\relation\MorphTo;
|
|||||||
*/
|
*/
|
||||||
abstract class Model implements \JsonSerializable, \ArrayAccess
|
abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||||
{
|
{
|
||||||
// 数据库对象池
|
// 数据库查询对象池
|
||||||
protected static $links = [];
|
protected static $links = [];
|
||||||
// 数据库配置
|
// 数据库配置
|
||||||
protected $connection = [];
|
protected $connection = [];
|
||||||
|
// 父关联模型对象
|
||||||
|
protected $parent;
|
||||||
// 数据库查询对象
|
// 数据库查询对象
|
||||||
protected $query;
|
protected $query;
|
||||||
// 当前模型名称
|
// 当前模型名称
|
||||||
@@ -63,8 +66,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
protected $append = [];
|
protected $append = [];
|
||||||
// 数据信息
|
// 数据信息
|
||||||
protected $data = [];
|
protected $data = [];
|
||||||
// 记录改变字段
|
// 原始数据
|
||||||
protected $change = [];
|
protected $origin = [];
|
||||||
|
// 关联模型
|
||||||
|
protected $relation = [];
|
||||||
|
|
||||||
// 保存自动完成列表
|
// 保存自动完成列表
|
||||||
protected $auto = [];
|
protected $auto = [];
|
||||||
@@ -86,8 +91,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
protected $isUpdate = false;
|
protected $isUpdate = false;
|
||||||
// 更新条件
|
// 更新条件
|
||||||
protected $updateWhere;
|
protected $updateWhere;
|
||||||
// 当前执行的关联对象
|
|
||||||
protected $relation;
|
|
||||||
// 验证失败是否抛出异常
|
// 验证失败是否抛出异常
|
||||||
protected $failException = false;
|
protected $failException = false;
|
||||||
// 全局查询范围
|
// 全局查询范围
|
||||||
@@ -98,8 +101,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
protected $resultSetType;
|
protected $resultSetType;
|
||||||
// 关联自动写入
|
// 关联自动写入
|
||||||
protected $relationWrite;
|
protected $relationWrite;
|
||||||
//
|
|
||||||
protected static $db;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化过的模型.
|
* 初始化过的模型.
|
||||||
@@ -120,9 +121,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
} else {
|
} else {
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
// 记录原始数据
|
||||||
|
$this->origin = $this->data;
|
||||||
|
|
||||||
// 当前类名
|
// 当前类名
|
||||||
$this->class = get_class($this);
|
$this->class = get_called_class();
|
||||||
|
|
||||||
if (empty($this->name)) {
|
if (empty($this->name)) {
|
||||||
// 当前模型名
|
// 当前模型名
|
||||||
@@ -136,63 +139,94 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
|
|
||||||
if (is_null($this->autoWriteTimestamp)) {
|
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)) {
|
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)) {
|
if (is_null($this->resultSetType)) {
|
||||||
$this->resultSetType = $this->db(false)->getConfig('resultset_type');
|
$this->resultSetType = $this->getQuery()->getConfig('resultset_type');
|
||||||
}
|
}
|
||||||
// 执行初始化操作
|
// 执行初始化操作
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前模型的数据库查询对象
|
* 创建模型的查询对象
|
||||||
* @access public
|
* @access protected
|
||||||
* @param bool $baseQuery 是否调用全局查询范围
|
|
||||||
* @return Query
|
* @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)) {
|
||||||
if (!empty($this->connection)) {
|
$connection = array_merge(Config::get('database'), $this->connection);
|
||||||
if (is_array($this->connection)) {
|
|
||||||
$connection = array_merge(Config::get('database'), $this->connection);
|
|
||||||
} else {
|
|
||||||
$connection = $this->connection;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$connection = [];
|
$connection = $this->connection;
|
||||||
}
|
}
|
||||||
// 设置当前模型 确保查询返回模型对象
|
} else {
|
||||||
$query = Db::connect($connection)->getQuery($model, $this->query);
|
$connection = [];
|
||||||
|
|
||||||
// 设置当前数据表和模型名
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$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')) {
|
if ($useBaseQuery && method_exists($this, 'base')) {
|
||||||
call_user_func_array([$this, 'base'], [ & self::$links[$model]]);
|
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
|
* @access public
|
||||||
@@ -260,6 +317,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
return $this->data;
|
return $this->data;
|
||||||
} elseif (array_key_exists($name, $this->data)) {
|
} elseif (array_key_exists($name, $this->data)) {
|
||||||
return $this->data[$name];
|
return $this->data[$name];
|
||||||
|
} elseif (array_key_exists($name, $this->relation)) {
|
||||||
|
return $this->relation[$name];
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
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';
|
$method = 'set' . Loader::parseName($name, 1) . 'Attr';
|
||||||
if (method_exists($this, $method)) {
|
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])) {
|
} elseif (isset($this->type[$name])) {
|
||||||
// 类型转换
|
// 类型转换
|
||||||
$value = $this->writeTransform($value, $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;
|
$this->data[$name] = $value;
|
||||||
return $this;
|
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
|
* @access public
|
||||||
@@ -319,12 +400,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
case 'datetime':
|
case 'datetime':
|
||||||
case 'date':
|
case 'date':
|
||||||
$format = !empty($param) ? $param : $this->dateFormat;
|
$format = !empty($param) ? $param : $this->dateFormat;
|
||||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $format);
|
$value = $this->formatDateTime(time(), $format);
|
||||||
break;
|
break;
|
||||||
case 'timestamp':
|
case 'timestamp':
|
||||||
case 'integer':
|
case 'integer':
|
||||||
default:
|
default:
|
||||||
$value = $_SERVER['REQUEST_TIME'];
|
$value = time();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
|
} elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
|
||||||
@@ -333,9 +414,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
'timestamp',
|
'timestamp',
|
||||||
])
|
])
|
||||||
) {
|
) {
|
||||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat);
|
$value = $this->formatDateTime(time(), $this->dateFormat);
|
||||||
} else {
|
} else {
|
||||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat, true);
|
$value = $this->formatDateTime(time(), $this->dateFormat, true);
|
||||||
}
|
}
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
@@ -367,6 +448,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
protected function writeTransform($value, $type)
|
protected function writeTransform($value, $type)
|
||||||
{
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($type)) {
|
if (is_array($type)) {
|
||||||
list($type, $param) = $type;
|
list($type, $param) = $type;
|
||||||
} elseif (strpos($type, ':')) {
|
} elseif (strpos($type, ':')) {
|
||||||
@@ -451,14 +536,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$value = $this->formatDateTime($value, $this->dateFormat);
|
$value = $this->formatDateTime($value, $this->dateFormat);
|
||||||
}
|
}
|
||||||
} elseif ($notFound) {
|
} elseif ($notFound) {
|
||||||
$method = Loader::parseName($name, 1, false);
|
$relation = Loader::parseName($name, 1, false);
|
||||||
if (method_exists($this, $method) && $this->$method() instanceof Relation) {
|
if (method_exists($this, $relation)) {
|
||||||
// 清空之前的查询参数
|
$modelRelation = $this->$relation();
|
||||||
$this->$method()->removeOption();
|
|
||||||
// 不存在该字段 获取关联数据
|
// 不存在该字段 获取关联数据
|
||||||
$value = $this->$method()->getRelation();
|
$value = $this->getRelationData($modelRelation);
|
||||||
// 保存关联对象值
|
// 保存关联对象值
|
||||||
$this->data[$name] = $value;
|
$this->relation[$name] = $value;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
||||||
}
|
}
|
||||||
@@ -466,6 +550,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
return $value;
|
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
|
* @access public
|
||||||
@@ -475,6 +576,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
protected function readTransform($value, $type)
|
protected function readTransform($value, $type)
|
||||||
{
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($type)) {
|
if (is_array($type)) {
|
||||||
list($type, $param) = $type;
|
list($type, $param) = $type;
|
||||||
} elseif (strpos($type, ':')) {
|
} elseif (strpos($type, ':')) {
|
||||||
@@ -553,14 +658,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
if (is_string($append)) {
|
if (is_string($append)) {
|
||||||
$append = explode(',', $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) {
|
if ($model instanceof Model) {
|
||||||
foreach ($append as $key => $attr) {
|
foreach ($append as $key => $attr) {
|
||||||
$key = is_numeric($key) ? $attr : $key;
|
$key = is_numeric($key) ? $attr : $key;
|
||||||
if ($this->__isset($key)) {
|
if (isset($this->data[$key])) {
|
||||||
throw new Exception('bind attr has exists:' . $key);
|
throw new Exception('bind attr has exists:' . $key);
|
||||||
} else {
|
} else {
|
||||||
$this->setAttr($key, $model->$attr);
|
$this->data[$key] = $model->$attr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -653,15 +767,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$item = [];
|
$item = [];
|
||||||
$visible = [];
|
$visible = [];
|
||||||
$hidden = [];
|
$hidden = [];
|
||||||
|
|
||||||
|
$data = array_merge($this->data, $this->relation);
|
||||||
|
|
||||||
// 过滤属性
|
// 过滤属性
|
||||||
if (!empty($this->visible)) {
|
if (!empty($this->visible)) {
|
||||||
$array = $this->parseAttr($this->visible, $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)) {
|
} elseif (!empty($this->hidden)) {
|
||||||
$array = $this->parseAttr($this->hidden, $hidden, false);
|
$array = $this->parseAttr($this->hidden, $hidden, false);
|
||||||
$data = array_diff_key($this->data, array_flip($array));
|
$data = array_diff_key($data, array_flip($array));
|
||||||
} else {
|
|
||||||
$data = $this->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($data as $key => $val) {
|
foreach ($data as $key => $val) {
|
||||||
@@ -672,7 +787,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
// 关联模型数据集
|
// 关联模型数据集
|
||||||
$arr = [];
|
$arr = [];
|
||||||
foreach ($val as $k => $value) {
|
foreach ($val as $k => $value) {
|
||||||
$arr[$k] = $this->subToArray($value, $visible, $hidden, $k);
|
$arr[$k] = $this->subToArray($value, $visible, $hidden, $key);
|
||||||
}
|
}
|
||||||
$item[$key] = $arr;
|
$item[$key] = $arr;
|
||||||
} else {
|
} else {
|
||||||
@@ -754,10 +869,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
public function getPk($name = '')
|
public function getPk($name = '')
|
||||||
{
|
{
|
||||||
if (!empty($name)) {
|
if (!empty($name)) {
|
||||||
$table = $this->db(false)->getTable($name);
|
$table = $this->getQuery()->getTable($name);
|
||||||
return $this->db(false)->getPk($table);
|
return $this->getQuery()->getPk($table);
|
||||||
} elseif (empty($this->pk)) {
|
} elseif (empty($this->pk)) {
|
||||||
$this->pk = $this->db(false)->getPk();
|
$this->pk = $this->getQuery()->getPk();
|
||||||
}
|
}
|
||||||
return $this->pk;
|
return $this->pk;
|
||||||
}
|
}
|
||||||
@@ -807,31 +922,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
if (!empty($this->relationWrite)) {
|
if (!empty($this->relationWrite)) {
|
||||||
$relation = [];
|
$relation = [];
|
||||||
foreach ($this->relationWrite as $key => $name) {
|
foreach ($this->relationWrite as $key => $name) {
|
||||||
if (!is_numeric($key)) {
|
if (is_array($name)) {
|
||||||
$relation[$key] = [];
|
if (key($name) === 0) {
|
||||||
foreach ($name as $val) {
|
$relation[$key] = [];
|
||||||
if (isset($this->data[$val])) {
|
foreach ($name as $val) {
|
||||||
$relation[$key][$val] = $this->data[$val];
|
if (isset($this->data[$val])) {
|
||||||
unset($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])) {
|
} elseif (isset($this->data[$name])) {
|
||||||
$relation[$name] = $this->data[$name];
|
$relation[$name] = $this->data[$name];
|
||||||
if (!$this->isUpdate) {
|
unset($this->data[$name]);
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -845,33 +952,25 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
}
|
}
|
||||||
$pk = $this->getPk();
|
$pk = $this->getPk();
|
||||||
if ($this->isUpdate) {
|
if ($this->isUpdate) {
|
||||||
|
// 检测字段
|
||||||
|
$this->checkAllowField($this->data, array_merge($this->auto, $this->update));
|
||||||
|
|
||||||
// 自动更新
|
// 自动更新
|
||||||
$this->autoCompleteData($this->update);
|
$this->autoCompleteData($this->update);
|
||||||
|
|
||||||
|
// 获取有更新的数据
|
||||||
|
$data = $this->getChangedData();
|
||||||
|
|
||||||
// 事件回调
|
// 事件回调
|
||||||
if (false === $this->trigger('before_update', $this)) {
|
if (false === $this->trigger('before_update', $this)) {
|
||||||
return false;
|
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 (empty($data) || (count($data) == 1 && is_string($pk) && isset($data[$pk]))) {
|
||||||
// 没有更新
|
// 关联更新
|
||||||
|
if (isset($relation)) {
|
||||||
|
$this->autoRelationUpdate($relation);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
|
} elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
|
||||||
// 自动写入更新时间
|
// 自动写入更新时间
|
||||||
@@ -882,6 +981,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$where = $this->updateWhere;
|
$where = $this->updateWhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保留主键数据
|
||||||
|
foreach ($this->data as $key => $val) {
|
||||||
|
if ($this->isPk($key)) {
|
||||||
|
$data[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_string($pk) && isset($data[$pk])) {
|
if (is_string($pk) && isset($data[$pk])) {
|
||||||
if (!isset($where[$pk])) {
|
if (!isset($where[$pk])) {
|
||||||
unset($where);
|
unset($where);
|
||||||
@@ -890,40 +996,24 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
unset($data[$pk]);
|
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)) {
|
if (isset($relation)) {
|
||||||
foreach ($relation as $name => $val) {
|
$this->autoRelationUpdate($relation);
|
||||||
if ($val instanceof Model) {
|
|
||||||
$val->save();
|
|
||||||
} else {
|
|
||||||
unset($this->data[$name]);
|
|
||||||
$model = $this->getAttr($name);
|
|
||||||
if ($model instanceof Model) {
|
|
||||||
$model->save($val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空change
|
|
||||||
$this->change = [];
|
|
||||||
// 更新回调
|
// 更新回调
|
||||||
$this->trigger('after_update', $this);
|
$this->trigger('after_update', $this);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// 检测字段
|
||||||
|
$this->checkAllowField($this->data, array_merge($this->auto, $this->insert));
|
||||||
|
|
||||||
// 自动写入
|
// 自动写入
|
||||||
$this->autoCompleteData($this->insert);
|
$this->autoCompleteData($this->insert);
|
||||||
|
|
||||||
// 自动写入创建时间和更新时间
|
// 自动写入创建时间和更新时间
|
||||||
if ($this->autoWriteTimestamp) {
|
if ($this->autoWriteTimestamp) {
|
||||||
if ($this->createTime && !isset($this->data[$this->createTime])) {
|
if ($this->createTime && !isset($this->data[$this->createTime])) {
|
||||||
@@ -938,11 +1028,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
return false;
|
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])) {
|
if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
|
||||||
$insertId = $this->db()->getLastInsID($sequence);
|
$insertId = $this->getQuery()->getLastInsID($sequence);
|
||||||
if ($insertId) {
|
if ($insertId) {
|
||||||
$this->data[$pk] = $insertId;
|
$this->data[$pk] = $insertId;
|
||||||
}
|
}
|
||||||
@@ -958,17 +1048,78 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
|
|
||||||
// 标记为更新
|
// 标记为更新
|
||||||
$this->isUpdate = true;
|
$this->isUpdate = true;
|
||||||
// 清空change
|
|
||||||
$this->change = [];
|
|
||||||
// 新增回调
|
// 新增回调
|
||||||
$this->trigger('after_insert', $this);
|
$this->trigger('after_insert', $this);
|
||||||
}
|
}
|
||||||
// 写入回调
|
// 写入回调
|
||||||
$this->trigger('after_write', $this);
|
$this->trigger('after_write', $this);
|
||||||
|
|
||||||
|
// 重新记录原始数据
|
||||||
|
$this->origin = $this->data;
|
||||||
|
|
||||||
return $result;
|
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
|
* @access public
|
||||||
@@ -990,7 +1141,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
$db = $this->db();
|
$db = $this->getQuery();
|
||||||
$db->startTrans();
|
$db->startTrans();
|
||||||
try {
|
try {
|
||||||
$pk = $this->getPk();
|
$pk = $this->getPk();
|
||||||
@@ -1071,9 +1222,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$field = $value;
|
$field = $value;
|
||||||
$value = null;
|
$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)) {
|
if (!empty($this->relationWrite)) {
|
||||||
@@ -1113,6 +1269,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->trigger('after_delete', $this);
|
$this->trigger('after_delete', $this);
|
||||||
|
// 清空原始数据
|
||||||
|
$this->origin = [];
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1207,7 +1366,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
/**
|
/**
|
||||||
* 返回模型的错误信息
|
* 返回模型的错误信息
|
||||||
* @access public
|
* @access public
|
||||||
* @return string
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
public function getError()
|
public function getError()
|
||||||
{
|
{
|
||||||
@@ -1294,11 +1453,15 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
* @param mixed $data 主键值或者查询条件(闭包)
|
* @param mixed $data 主键值或者查询条件(闭包)
|
||||||
* @param array|string $with 关联预查询
|
* @param array|string $with 关联预查询
|
||||||
* @param bool $cache 是否缓存
|
* @param bool $cache 是否缓存
|
||||||
* @return static
|
* @return static|null
|
||||||
* @throws exception\DbException
|
* @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)) {
|
if (true === $with || is_int($with)) {
|
||||||
$cache = $with;
|
$cache = $with;
|
||||||
$with = [];
|
$with = [];
|
||||||
@@ -1366,7 +1529,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
} elseif ($data instanceof \Closure) {
|
} elseif ($data instanceof \Closure) {
|
||||||
call_user_func_array($data, [ & $query]);
|
call_user_func_array($data, [ & $query]);
|
||||||
$data = null;
|
$data = null;
|
||||||
} elseif (is_null($data)) {
|
} elseif (empty($data) && 0 !== $data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$resultSet = $query->select($data);
|
$resultSet = $query->select($data);
|
||||||
@@ -1385,16 +1548,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
* @access public
|
* @access public
|
||||||
* @param string|array|\Closure $name 命名范围名称 逗号分隔
|
* @param string|array|\Closure $name 命名范围名称 逗号分隔
|
||||||
* @internal mixed ...$params 参数调用
|
* @internal mixed ...$params 参数调用
|
||||||
* @return Model|Query
|
* @return Query
|
||||||
*/
|
*/
|
||||||
public static function scope($name)
|
public static function scope($name)
|
||||||
{
|
{
|
||||||
if ($name instanceof Query) {
|
$model = new static();
|
||||||
return $name;
|
$query = $model->db();
|
||||||
}
|
$params = func_get_args();
|
||||||
$model = new static();
|
array_unshift($params, $query);
|
||||||
$params = func_get_args();
|
|
||||||
$params[0] = $model->db();
|
|
||||||
if ($name instanceof \Closure) {
|
if ($name instanceof \Closure) {
|
||||||
call_user_func_array($name, $params);
|
call_user_func_array($name, $params);
|
||||||
} elseif (is_string($name)) {
|
} 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)
|
public static function useGlobalScope($use)
|
||||||
{
|
{
|
||||||
$model = new static();
|
$model = new static();
|
||||||
static::$db = $model->db($use);
|
return $model->db($use);
|
||||||
return $model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1638,7 +1798,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$model = $this->parseModel($model);
|
$model = $this->parseModel($model);
|
||||||
$foreignKey = $foreignKey ?: $this->getForeignKey($model);
|
$foreignKey = $foreignKey ?: $this->getForeignKey($model);
|
||||||
$localKey = $localKey ?: (new $model)->getPk();
|
$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);
|
$model = $this->parseModel($model);
|
||||||
$name = Loader::parseName(basename(str_replace('\\', '/', $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';
|
$foreignKey = $foreignKey ?: $name . '_id';
|
||||||
$localKey = $localKey ?: $this->getForeignKey($this->name);
|
$localKey = $localKey ?: $this->getForeignKey($this->name);
|
||||||
return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
|
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);
|
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 关联定义
|
* MORPH TO 关联定义
|
||||||
* @access public
|
* @access public
|
||||||
@@ -1734,9 +1922,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
public function morphTo($morph = null, $alias = [])
|
public function morphTo($morph = null, $alias = [])
|
||||||
{
|
{
|
||||||
|
$trace = debug_backtrace(false, 2);
|
||||||
|
$relation = Loader::parseName($trace[1]['function']);
|
||||||
|
|
||||||
if (is_null($morph)) {
|
if (is_null($morph)) {
|
||||||
$trace = debug_backtrace(false, 2);
|
$morph = $relation;
|
||||||
$morph = Loader::parseName($trace[1]['function']);
|
|
||||||
}
|
}
|
||||||
// 记录当前关联信息
|
// 记录当前关联信息
|
||||||
if (is_array($morph)) {
|
if (is_array($morph)) {
|
||||||
@@ -1745,17 +1935,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
$morphType = $morph . '_type';
|
$morphType = $morph . '_type';
|
||||||
$foreignKey = $morph . '_id';
|
$foreignKey = $morph . '_id';
|
||||||
}
|
}
|
||||||
return new MorphTo($this, $morphType, $foreignKey, $alias);
|
return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __call($method, $args)
|
public function __call($method, $args)
|
||||||
{
|
{
|
||||||
if (isset(static::$db)) {
|
$query = $this->db(true, false);
|
||||||
$query = static::$db;
|
|
||||||
static::$db = null;
|
|
||||||
} else {
|
|
||||||
$query = $this->db();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method_exists($this, 'scope' . $method)) {
|
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)) {
|
$model = new static();
|
||||||
$query = static::$db;
|
$query = $model->db();
|
||||||
static::$db = null;
|
|
||||||
} else {
|
|
||||||
$query = (new static())->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)
|
public function __isset($name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (array_key_exists($name, $this->data)) {
|
if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$this->getAttr($name);
|
$this->getAttr($name);
|
||||||
@@ -1832,7 +2022,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
*/
|
*/
|
||||||
public function __unset($name)
|
public function __unset($name)
|
||||||
{
|
{
|
||||||
unset($this->data[$name]);
|
unset($this->data[$name], $this->relation[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
|
|||||||
@@ -273,6 +273,23 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
|
|||||||
return $this->items->isEmpty();
|
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
|
* Retrieve an external iterator
|
||||||
* @return Traversable An instance of an object implementing <b>Iterator</b> or
|
* @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,
|
'total' => $total,
|
||||||
'per_page' => $this->listRows(),
|
'per_page' => $this->listRows(),
|
||||||
'current_page' => $this->currentPage(),
|
'current_page' => $this->currentPage(),
|
||||||
|
'last_page' => $this->lastPage,
|
||||||
'data' => $this->items->toArray(),
|
'data' => $this->items->toArray(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,20 +88,18 @@ class Request
|
|||||||
* @var array 资源类型
|
* @var array 资源类型
|
||||||
*/
|
*/
|
||||||
protected $mimeType = [
|
protected $mimeType = [
|
||||||
'xml' => 'application/xml,text/xml,application/x-xml',
|
'xml' => 'application/xml,text/xml,application/x-xml',
|
||||||
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
|
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
|
||||||
'js' => 'text/javascript,application/javascript,application/x-javascript',
|
'js' => 'text/javascript,application/javascript,application/x-javascript',
|
||||||
'css' => 'text/css',
|
'css' => 'text/css',
|
||||||
'rss' => 'application/rss+xml',
|
'rss' => 'application/rss+xml',
|
||||||
'yaml' => 'application/x-yaml,text/yaml',
|
'yaml' => 'application/x-yaml,text/yaml',
|
||||||
'atom' => 'application/atom+xml',
|
'atom' => 'application/atom+xml',
|
||||||
'pdf' => 'application/pdf',
|
'pdf' => 'application/pdf',
|
||||||
'text' => 'text/plain',
|
'text' => 'text/plain',
|
||||||
'png' => 'image/png',
|
'image' => 'image/png,image/jpg,image/jpeg,image/pjpeg,image/gif,image/webp,image/*',
|
||||||
'jpg' => 'image/jpg,image/jpeg,image/pjpeg',
|
'csv' => 'text/csv',
|
||||||
'gif' => 'image/gif',
|
'html' => 'text/html,application/xhtml+xml,*/*',
|
||||||
'csv' => 'text/csv',
|
|
||||||
'html' => 'text/html,application/xhtml+xml,*/*',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $content;
|
protected $content;
|
||||||
@@ -134,6 +132,7 @@ class Request
|
|||||||
if (is_null($this->filter)) {
|
if (is_null($this->filter)) {
|
||||||
$this->filter = Config::get('default_filter');
|
$this->filter = Config::get('default_filter');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存 php://input
|
// 保存 php://input
|
||||||
$this->input = file_get_contents('php://input');
|
$this->input = file_get_contents('php://input');
|
||||||
}
|
}
|
||||||
@@ -802,12 +801,26 @@ class Request
|
|||||||
public function cookie($name = '', $default = null, $filter = '')
|
public function cookie($name = '', $default = null, $filter = '')
|
||||||
{
|
{
|
||||||
if (empty($this->cookie)) {
|
if (empty($this->cookie)) {
|
||||||
$this->cookie = $_COOKIE;
|
$this->cookie = Cookie::get();
|
||||||
}
|
}
|
||||||
if (is_array($name)) {
|
if (is_array($name)) {
|
||||||
return $this->cookie = array_merge($this->cookie, $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 = $this->getFilter($filter, $default);
|
||||||
$filter = [];
|
|
||||||
} else {
|
|
||||||
$filter = $filter ?: $this->filter;
|
|
||||||
if (is_string($filter)) {
|
|
||||||
$filter = explode(',', $filter);
|
|
||||||
} else {
|
|
||||||
$filter = (array) $filter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$filter[] = $default;
|
|
||||||
if (is_array($data)) {
|
if (is_array($data)) {
|
||||||
array_walk_recursive($data, [$this, 'filterValue'], $filter);
|
array_walk_recursive($data, [$this, 'filterValue'], $filter);
|
||||||
reset($data);
|
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 键值
|
* @param mixed $value 键值
|
||||||
@@ -1039,7 +1059,7 @@ class Request
|
|||||||
// 调用函数或者方法过滤
|
// 调用函数或者方法过滤
|
||||||
$value = call_user_func($filter, $value);
|
$value = call_user_func($filter, $value);
|
||||||
} elseif (is_scalar($value)) {
|
} elseif (is_scalar($value)) {
|
||||||
if (strpos($filter, '/')) {
|
if (false !== strpos($filter, '/')) {
|
||||||
// 正则过滤
|
// 正则过滤
|
||||||
if (!preg_match($filter, $value)) {
|
if (!preg_match($filter, $value)) {
|
||||||
// 匹配不成功返回默认值
|
// 匹配不成功返回默认值
|
||||||
@@ -1527,13 +1547,13 @@ class Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 自动缓存功能
|
// 自动缓存功能
|
||||||
$key = md5($this->host()) . '__URL__';
|
$key = '__URL__';
|
||||||
} elseif (strpos($key, '|')) {
|
} elseif (strpos($key, '|')) {
|
||||||
list($key, $fun) = explode('|', $key);
|
list($key, $fun) = explode('|', $key);
|
||||||
}
|
}
|
||||||
// 特殊规则替换
|
// 特殊规则替换
|
||||||
if (false !== strpos($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, ':')) {
|
if (false !== strpos($key, ':')) {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use think\response\Xml as XmlResponse;
|
|||||||
|
|
||||||
class Response
|
class Response
|
||||||
{
|
{
|
||||||
|
|
||||||
// 原始数据
|
// 原始数据
|
||||||
protected $data;
|
protected $data;
|
||||||
|
|
||||||
@@ -50,12 +49,12 @@ class Response
|
|||||||
public function __construct($data = '', $code = 200, array $header = [], $options = [])
|
public function __construct($data = '', $code = 200, array $header = [], $options = [])
|
||||||
{
|
{
|
||||||
$this->data($data);
|
$this->data($data);
|
||||||
$this->header = $header;
|
|
||||||
$this->code = $code;
|
|
||||||
if (!empty($options)) {
|
if (!empty($options)) {
|
||||||
$this->options = array_merge($this->options, $options);
|
$this->options = array_merge($this->options, $options);
|
||||||
}
|
}
|
||||||
$this->contentType($this->contentType, $this->charset);
|
$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);
|
http_response_code($this->code);
|
||||||
// 发送头部信息
|
// 发送头部信息
|
||||||
foreach ($this->header as $name => $val) {
|
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());
|
$method = strtolower($request->method());
|
||||||
// 获取当前请求类型的路由规则
|
// 获取当前请求类型的路由规则
|
||||||
$rules = self::$rules[$method];
|
$rules = isset(self::$rules[$method]) ? self::$rules[$method] : [];
|
||||||
// 检测域名部署
|
// 检测域名部署
|
||||||
if ($checkDomain) {
|
if ($checkDomain) {
|
||||||
self::checkDomain($request, $rules, $method);
|
self::checkDomain($request, $rules, $method);
|
||||||
@@ -924,7 +924,7 @@ class Route
|
|||||||
} else {
|
} else {
|
||||||
$str = $key;
|
$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;
|
continue;
|
||||||
}
|
}
|
||||||
self::setOption($option);
|
self::setOption($option);
|
||||||
@@ -1184,9 +1184,9 @@ class Route
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pattern = array_merge(self::$rules['pattern'], $pattern);
|
$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;
|
return false;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class Session
|
|||||||
$isDoStart = true;
|
$isDoStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($config['prefix'])) {
|
if (isset($config['prefix']) && (self::$prefix === '' || self::$prefix === null)) {
|
||||||
self::$prefix = $config['prefix'];
|
self::$prefix = $config['prefix'];
|
||||||
}
|
}
|
||||||
if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {
|
if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ class Url
|
|||||||
$rootDomain = Config::get('url_domain_root');
|
$rootDomain = Config::get('url_domain_root');
|
||||||
if (true === $domain) {
|
if (true === $domain) {
|
||||||
// 自动判断域名
|
// 自动判断域名
|
||||||
$domain = $request->host();
|
$domain = Config::get('default_host') ?: $request->host();
|
||||||
|
|
||||||
$domains = Route::rules('domain');
|
$domains = Route::rules('domain');
|
||||||
if ($domains) {
|
if ($domains) {
|
||||||
@@ -265,7 +265,7 @@ class Url
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (empty($rootDomain)) {
|
if (empty($rootDomain)) {
|
||||||
$host = $request->host();
|
$host = Config::get('default_host') ?: $request->host();
|
||||||
$rootDomain = substr_count($host, '.') > 1 ? substr(strstr($host, '.'), 1) : $host;
|
$rootDomain = substr_count($host, '.') > 1 ? substr(strstr($host, '.'), 1) : $host;
|
||||||
}
|
}
|
||||||
if (substr_count($domain, '.') < 2 && !strpos($domain, $rootDomain)) {
|
if (substr_count($domain, '.') < 2 && !strpos($domain, $rootDomain)) {
|
||||||
@@ -297,7 +297,7 @@ class Url
|
|||||||
}
|
}
|
||||||
foreach ($pattern as $key => $val) {
|
foreach ($pattern as $key => $val) {
|
||||||
if (isset($vars[$key])) {
|
if (isset($vars[$key])) {
|
||||||
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], $vars[$key], $url);
|
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url);
|
||||||
unset($vars[$key]);
|
unset($vars[$key]);
|
||||||
$result = [$url, $domain, $suffix];
|
$result = [$url, $domain, $suffix];
|
||||||
} elseif (2 == $val) {
|
} elseif (2 == $val) {
|
||||||
|
|||||||
@@ -456,11 +456,13 @@ class Validate
|
|||||||
* @access protected
|
* @access protected
|
||||||
* @param mixed $value 字段值
|
* @param mixed $value 字段值
|
||||||
* @param mixed $rule 验证规则
|
* @param mixed $rule 验证规则
|
||||||
|
* @param array $data 数据
|
||||||
* @return bool
|
* @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
|
* @access protected
|
||||||
* @param mixed $value 字段值
|
* @param mixed $value 字段值
|
||||||
* @param mixed $rule 验证规则
|
* @param mixed $rule 验证规则
|
||||||
|
* @param array $data 数据
|
||||||
* @return bool
|
* @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
|
* @access protected
|
||||||
* @param mixed $value 字段值
|
* @param mixed $value 字段值
|
||||||
* @param mixed $rule 验证规则
|
* @param mixed $rule 验证规则
|
||||||
|
* @param array $data 数据
|
||||||
* @return bool
|
* @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
|
* @access protected
|
||||||
* @param mixed $value 字段值
|
* @param mixed $value 字段值
|
||||||
* @param mixed $rule 验证规则
|
* @param mixed $rule 验证规则
|
||||||
|
* @param array $data 数据
|
||||||
* @return bool
|
* @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
|
* @access protected
|
||||||
* @param array $data 数据
|
* @param array $data 数据
|
||||||
* @param string $key 数据标识 支持二维
|
* @param string $key 数据标识 支持二维
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
protected function getDataValue($data, $key)
|
protected function getDataValue($data, $key)
|
||||||
{
|
{
|
||||||
if (strpos($key, '.')) {
|
if (is_numeric($key)) {
|
||||||
|
$value = $key;
|
||||||
|
} elseif (strpos($key, '.')) {
|
||||||
// 支持二维数组验证
|
// 支持二维数组验证
|
||||||
list($name1, $name2) = explode('.', $key);
|
list($name1, $name2) = explode('.', $key);
|
||||||
$value = isset($data[$name1][$name2]) ? $data[$name1][$name2] : null;
|
$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)
|
public function inc($name, $step = 1)
|
||||||
{
|
{
|
||||||
$key = $this->getCacheKey($name);
|
$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)
|
public function inc($name, $step = 1)
|
||||||
{
|
{
|
||||||
$key = $this->getCacheKey($name);
|
$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表达式
|
// SQL表达式
|
||||||
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
|
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
|
||||||
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
|
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
|
||||||
protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
|
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
|
||||||
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
|
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
|
||||||
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %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']) {
|
if ('*' == $options['field']) {
|
||||||
$fields = array_keys($bind);
|
$fields = array_keys($bind);
|
||||||
} else {
|
} else {
|
||||||
@@ -222,6 +222,14 @@ abstract class Builder
|
|||||||
protected function parseWhere($where, $options)
|
protected function parseWhere($where, $options)
|
||||||
{
|
{
|
||||||
$whereStr = $this->buildWhere($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;
|
return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +251,7 @@ abstract class Builder
|
|||||||
}
|
}
|
||||||
|
|
||||||
$whereStr = '';
|
$whereStr = '';
|
||||||
$binds = $this->query->getFieldsBind($options);
|
$binds = $this->query->getFieldsBind($options['table']);
|
||||||
foreach ($where as $key => $val) {
|
foreach ($where as $key => $val) {
|
||||||
$str = [];
|
$str = [];
|
||||||
foreach ($val as $field => $value) {
|
foreach ($val as $field => $value) {
|
||||||
@@ -280,13 +288,7 @@ abstract class Builder
|
|||||||
|
|
||||||
$whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($key) + 1) : implode(' ', $str);
|
$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;
|
return $whereStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,9 +348,14 @@ abstract class Builder
|
|||||||
|
|
||||||
$whereStr = '';
|
$whereStr = '';
|
||||||
if (in_array($exp, ['=', '<>', '>', '>=', '<', '<='])) {
|
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) {
|
} elseif ('LIKE' == $exp || 'NOT LIKE' == $exp) {
|
||||||
|
// 模糊匹配
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
foreach ($value as $item) {
|
foreach ($value as $item) {
|
||||||
$array[] = $key . ' ' . $exp . ' ' . $this->parseValue($item, $field);
|
$array[] = $key . ' ' . $exp . ' ' . $this->parseValue($item, $field);
|
||||||
@@ -712,13 +719,14 @@ abstract class Builder
|
|||||||
* @access public
|
* @access public
|
||||||
* @param array $dataSet 数据集
|
* @param array $dataSet 数据集
|
||||||
* @param array $options 表达式
|
* @param array $options 表达式
|
||||||
|
* @param bool $replace 是否replace
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function insertAll($dataSet, $options)
|
public function insertAll($dataSet, $options, $replace = false)
|
||||||
{
|
{
|
||||||
// 获取合法的字段
|
// 获取合法的字段
|
||||||
if ('*' == $options['field']) {
|
if ('*' == $options['field']) {
|
||||||
$fields = array_keys($this->query->getFieldsType($options));
|
$fields = array_keys($this->query->getFieldsType($options['table']));
|
||||||
} else {
|
} else {
|
||||||
$fields = $options['field'];
|
$fields = $options['field'];
|
||||||
}
|
}
|
||||||
@@ -747,8 +755,9 @@ abstract class Builder
|
|||||||
}
|
}
|
||||||
$fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
|
$fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
|
||||||
$sql = str_replace(
|
$sql = str_replace(
|
||||||
['%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
|
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
|
||||||
[
|
[
|
||||||
|
$replace ? 'REPLACE' : 'INSERT',
|
||||||
$this->parseTable($options['table'], $options),
|
$this->parseTable($options['table'], $options),
|
||||||
implode(' , ', $fields),
|
implode(' , ', $fields),
|
||||||
implode(' UNION ALL ', $values),
|
implode(' UNION ALL ', $values),
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ abstract class Connection
|
|||||||
protected $attrCase = PDO::CASE_LOWER;
|
protected $attrCase = PDO::CASE_LOWER;
|
||||||
// 监听回调
|
// 监听回调
|
||||||
protected static $event = [];
|
protected static $event = [];
|
||||||
// 查询对象
|
|
||||||
protected $query = [];
|
|
||||||
// 使用Builder类
|
// 使用Builder类
|
||||||
protected $builder;
|
protected $builder;
|
||||||
// 数据库连接参数配置
|
// 数据库连接参数配置
|
||||||
@@ -137,19 +135,14 @@ abstract class Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建指定模型的查询对象
|
* 获取新的查询对象
|
||||||
* @access public
|
* @access protected
|
||||||
* @param string $model 模型类名称
|
|
||||||
* @param string $queryClass 查询对象类名
|
|
||||||
* @return Query
|
* @return Query
|
||||||
*/
|
*/
|
||||||
public function getQuery($model = 'db', $queryClass = '')
|
protected function getQuery()
|
||||||
{
|
{
|
||||||
if (!isset($this->query[$model])) {
|
$class = $this->config['query'];
|
||||||
$class = $queryClass ?: $this->config['query'];
|
return new $class($this);
|
||||||
$this->query[$model] = new $class($this, 'db' == $model ? '' : $model);
|
|
||||||
}
|
|
||||||
return $this->query[$model];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,13 +333,9 @@ abstract class Connection
|
|||||||
/**
|
/**
|
||||||
* 执行查询 返回数据集
|
* 执行查询 返回数据集
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $sql sql指令
|
|
||||||
* @param array $bind 参数绑定
|
|
||||||
* @param bool $master 是否在主服务器读操作
|
|
||||||
* @param bool $class 是否返回PDO对象
|
|
||||||
* @param string $sql sql指令
|
* @param string $sql sql指令
|
||||||
* @param array $bind 参数绑定
|
* @param array $bind 参数绑定
|
||||||
* @param boolean $master 是否在主服务器读操作
|
* @param bool $master 是否在主服务器读操作
|
||||||
* @param bool $pdo 是否返回PDO对象
|
* @param bool $pdo 是否返回PDO对象
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws BindParamException
|
* @throws BindParamException
|
||||||
@@ -393,10 +382,15 @@ abstract class Connection
|
|||||||
// 返回结果集
|
// 返回结果集
|
||||||
return $this->getResult($pdo, $procedure);
|
return $this->getResult($pdo, $procedure);
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
|
if ($this->isBreak($e)) {
|
||||||
return $this->close()->query($sql, $bind, $master, $pdo);
|
return $this->close()->query($sql, $bind, $master, $pdo);
|
||||||
}
|
}
|
||||||
throw new PDOException($e, $this->config, $this->getLastsql());
|
throw new PDOException($e, $this->config, $this->getLastsql());
|
||||||
|
} catch (\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();
|
$this->numRows = $this->PDOStatement->rowCount();
|
||||||
return $this->numRows;
|
return $this->numRows;
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
|
if ($this->isBreak($e)) {
|
||||||
return $this->close()->execute($sql, $bind);
|
return $this->close()->execute($sql, $bind);
|
||||||
}
|
}
|
||||||
throw new PDOException($e, $this->config, $this->getLastsql());
|
throw new PDOException($e, $this->config, $this->getLastsql());
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
if ($this->isBreak($e)) {
|
||||||
|
return $this->close()->execute($sql, $bind);
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,13 +628,25 @@ abstract class Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
++$this->transTimes;
|
++$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) {
|
} catch (\PDOException $e) {
|
||||||
$this->linkID->beginTransaction();
|
if ($this->isBreak($e)) {
|
||||||
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
|
return $this->close()->startTrans();
|
||||||
$this->linkID->exec(
|
}
|
||||||
$this->parseSavepoint('trans' . $this->transTimes)
|
throw $e;
|
||||||
);
|
} catch (\ErrorException $e) {
|
||||||
|
if ($this->isBreak($e)) {
|
||||||
|
return $this->close()->startTrans();
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,11 +782,35 @@ abstract class Connection
|
|||||||
/**
|
/**
|
||||||
* 是否断线
|
* 是否断线
|
||||||
* @access protected
|
* @access protected
|
||||||
* @param \PDOException $e 异常
|
* @param \PDOException $e 异常对象
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isBreak($e)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,7 +895,6 @@ abstract class Connection
|
|||||||
Debug::remark('queryEndTime', 'time');
|
Debug::remark('queryEndTime', 'time');
|
||||||
$runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime');
|
$runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime');
|
||||||
$sql = $sql ?: $this->getLastsql();
|
$sql = $sql ?: $this->getLastsql();
|
||||||
$log = $sql . ' [ RunTime:' . $runtime . 's ]';
|
|
||||||
$result = [];
|
$result = [];
|
||||||
// SQL性能分析
|
// SQL性能分析
|
||||||
if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) {
|
if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) {
|
||||||
@@ -918,7 +952,7 @@ abstract class Connection
|
|||||||
{
|
{
|
||||||
if (!empty($this->config['deploy'])) {
|
if (!empty($this->config['deploy'])) {
|
||||||
// 采用分布式数据库
|
// 采用分布式数据库
|
||||||
if ($master) {
|
if ($master || $this->transTimes) {
|
||||||
if (!$this->linkWrite) {
|
if (!$this->linkWrite) {
|
||||||
$this->linkWrite = $this->multiConnect(true);
|
$this->linkWrite = $this->multiConnect(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ class Query
|
|||||||
if (empty($this->options['table'])) {
|
if (empty($this->options['table'])) {
|
||||||
$this->options['table'] = $this->getTable();
|
$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);
|
$result = Cache::get($key);
|
||||||
}
|
}
|
||||||
if (false === $result) {
|
if (false === $result) {
|
||||||
@@ -444,14 +444,16 @@ class Query
|
|||||||
if (empty($this->options['table'])) {
|
if (empty($this->options['table'])) {
|
||||||
$this->options['table'] = $this->getTable();
|
$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);
|
$result = Cache::get($guid);
|
||||||
}
|
}
|
||||||
if (false === $result) {
|
if (false === $result) {
|
||||||
if (isset($this->options['field'])) {
|
if (isset($this->options['field'])) {
|
||||||
unset($this->options['field']);
|
unset($this->options['field']);
|
||||||
}
|
}
|
||||||
if ($key && '*' != $field) {
|
if (is_null($field)) {
|
||||||
|
$field = '*';
|
||||||
|
} elseif ($key && '*' != $field) {
|
||||||
$field = $key . ',' . $field;
|
$field = $key . ',' . $field;
|
||||||
}
|
}
|
||||||
$pdo = $this->field($field)->getPdo();
|
$pdo = $this->field($field)->getPdo();
|
||||||
@@ -594,7 +596,7 @@ class Query
|
|||||||
}
|
}
|
||||||
if ($lazyTime > 0) {
|
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);
|
$step = $this->lazyWrite('inc', $guid, $step, $lazyTime);
|
||||||
if (false === $step) {
|
if (false === $step) {
|
||||||
// 清空查询条件
|
// 清空查询条件
|
||||||
@@ -623,7 +625,7 @@ class Query
|
|||||||
}
|
}
|
||||||
if ($lazyTime > 0) {
|
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);
|
$step = $this->lazyWrite('dec', $guid, $step, $lazyTime);
|
||||||
if (false === $step) {
|
if (false === $step) {
|
||||||
// 清空查询条件
|
// 清空查询条件
|
||||||
@@ -649,16 +651,16 @@ class Query
|
|||||||
if (!Cache::has($guid . '_time')) {
|
if (!Cache::has($guid . '_time')) {
|
||||||
// 计时开始
|
// 计时开始
|
||||||
Cache::set($guid . '_time', $_SERVER['REQUEST_TIME'], 0);
|
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) {
|
} 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);
|
||||||
Cache::rm($guid . '_time');
|
Cache::rm($guid . '_time');
|
||||||
return 0 === $value ? false : $value;
|
return 0 === $value ? false : $value;
|
||||||
} else {
|
} else {
|
||||||
// 更新缓存
|
// 更新缓存
|
||||||
Cache::$type($guid, $step, 0);
|
Cache::$type($guid, $step);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1132,6 +1134,7 @@ class Query
|
|||||||
if ($field) {
|
if ($field) {
|
||||||
$this->options['soft_delete'] = [$field, $condition ?: ['null', '']];
|
$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 = [];
|
$bind = [];
|
||||||
if ($types) {
|
if ($types) {
|
||||||
foreach ($types as $key => $type) {
|
foreach ($types as $key => $type) {
|
||||||
@@ -1900,6 +1903,9 @@ class Query
|
|||||||
$closure = $relation;
|
$closure = $relation;
|
||||||
$relation = $key;
|
$relation = $key;
|
||||||
$with[$key] = $key;
|
$with[$key] = $key;
|
||||||
|
} elseif (is_array($relation)) {
|
||||||
|
$subRelation = $relation;
|
||||||
|
$relation = $key;
|
||||||
} elseif (is_string($relation) && strpos($relation, '.')) {
|
} elseif (is_string($relation) && strpos($relation, '.')) {
|
||||||
$with[$key] = $relation;
|
$with[$key] = $relation;
|
||||||
list($relation, $subRelation) = explode('.', $relation, 2);
|
list($relation, $subRelation) = explode('.', $relation, 2);
|
||||||
@@ -1909,7 +1915,7 @@ class Query
|
|||||||
$relation = Loader::parseName($relation, 1, false);
|
$relation = Loader::parseName($relation, 1, false);
|
||||||
$model = $class->$relation();
|
$model = $class->$relation();
|
||||||
if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {
|
if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {
|
||||||
$model->removeOption()->eagerly($this, $relation, $subRelation, $closure, $first);
|
$model->eagerly($this, $relation, $subRelation, $closure, $first);
|
||||||
$first = false;
|
$first = false;
|
||||||
} elseif ($closure) {
|
} elseif ($closure) {
|
||||||
$with[$key] = $closure;
|
$with[$key] = $closure;
|
||||||
@@ -1997,7 +2003,7 @@ class Query
|
|||||||
$relation = explode(',', $relation);
|
$relation = explode(',', $relation);
|
||||||
}
|
}
|
||||||
if (isset($this->options['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 {
|
} else {
|
||||||
$this->options['relation'] = $relation;
|
$this->options['relation'] = $relation;
|
||||||
}
|
}
|
||||||
@@ -2111,9 +2117,10 @@ class Query
|
|||||||
* 批量插入记录
|
* 批量插入记录
|
||||||
* @access public
|
* @access public
|
||||||
* @param mixed $dataSet 数据集
|
* @param mixed $dataSet 数据集
|
||||||
|
* @param boolean $replace 是否replace
|
||||||
* @return integer|string
|
* @return integer|string
|
||||||
*/
|
*/
|
||||||
public function insertAll(array $dataSet)
|
public function insertAll(array $dataSet, $replace = false)
|
||||||
{
|
{
|
||||||
// 分析查询表达式
|
// 分析查询表达式
|
||||||
$options = $this->parseExpress();
|
$options = $this->parseExpress();
|
||||||
@@ -2121,7 +2128,7 @@ class Query
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 生成SQL语句
|
// 生成SQL语句
|
||||||
$sql = $this->builder->insertAll($dataSet, $options);
|
$sql = $this->builder->insertAll($dataSet, $options, $replace);
|
||||||
// 获取参数绑定
|
// 获取参数绑定
|
||||||
$bind = $this->getBind();
|
$bind = $this->getBind();
|
||||||
if ($options['fetch_sql']) {
|
if ($options['fetch_sql']) {
|
||||||
@@ -2203,7 +2210,7 @@ class Query
|
|||||||
$options['where']['AND'] = $where;
|
$options['where']['AND'] = $where;
|
||||||
}
|
}
|
||||||
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
} 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语句
|
// 生成UPDATE SQL语句
|
||||||
@@ -2291,7 +2298,7 @@ class Query
|
|||||||
// 判断查询缓存
|
// 判断查询缓存
|
||||||
$cache = $options['cache'];
|
$cache = $options['cache'];
|
||||||
unset($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);
|
$resultSet = Cache::get($key);
|
||||||
}
|
}
|
||||||
if (!$resultSet) {
|
if (!$resultSet) {
|
||||||
@@ -2383,8 +2390,9 @@ class Query
|
|||||||
* @access public
|
* @access public
|
||||||
* @param mixed $value 缓存数据
|
* @param mixed $value 缓存数据
|
||||||
* @param array $options 缓存参数
|
* @param array $options 缓存参数
|
||||||
|
* @param array $bind 绑定参数
|
||||||
*/
|
*/
|
||||||
protected function getCacheKey($value, $options)
|
protected function getCacheKey($value, $options, $bind = [])
|
||||||
{
|
{
|
||||||
if (is_scalar($value)) {
|
if (is_scalar($value)) {
|
||||||
$data = $value;
|
$data = $value;
|
||||||
@@ -2392,9 +2400,9 @@ class Query
|
|||||||
$data = $value[1];
|
$data = $value[1];
|
||||||
}
|
}
|
||||||
if (isset($data)) {
|
if (isset($data)) {
|
||||||
return 'think:' . $options['table'] . '|' . $data;
|
return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
|
||||||
} else {
|
} else {
|
||||||
return md5(serialize($options));
|
return md5(serialize($options) . serialize($bind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2422,7 +2430,7 @@ class Query
|
|||||||
// AR模式分析主键条件
|
// AR模式分析主键条件
|
||||||
$this->parsePkWhere($data, $options);
|
$this->parsePkWhere($data, $options);
|
||||||
} elseif (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
} 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;
|
$options['limit'] = 1;
|
||||||
@@ -2435,7 +2443,7 @@ class Query
|
|||||||
} elseif (is_string($cache['key'])) {
|
} elseif (is_string($cache['key'])) {
|
||||||
$key = $cache['key'];
|
$key = $cache['key'];
|
||||||
} elseif (!isset($key)) {
|
} elseif (!isset($key)) {
|
||||||
$key = md5(serialize($options));
|
$key = md5(serialize($options) . serialize($this->bind));
|
||||||
}
|
}
|
||||||
$result = Cache::get($key);
|
$result = Cache::get($key);
|
||||||
}
|
}
|
||||||
@@ -2646,7 +2654,7 @@ class Query
|
|||||||
// AR模式分析主键条件
|
// AR模式分析主键条件
|
||||||
$this->parsePkWhere($data, $options);
|
$this->parsePkWhere($data, $options);
|
||||||
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
} 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'])) {
|
if (true !== $data && empty($options['where'])) {
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ class Mysql extends Builder
|
|||||||
$key = '`' . $key . '`';
|
$key = '`' . $key . '`';
|
||||||
}
|
}
|
||||||
if (isset($table)) {
|
if (isset($table)) {
|
||||||
|
if (strpos($table, '.')) {
|
||||||
|
$table = str_replace('.', '`.`', $table);
|
||||||
|
}
|
||||||
$key = '`' . $table . '`.' . $key;
|
$key = '`' . $table . '`.' . $key;
|
||||||
}
|
}
|
||||||
return $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 $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 $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%';
|
||||||
protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
||||||
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* order分析
|
* order分析
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Mysql extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getFields($tableName)
|
public function getFields($tableName)
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
list($tableName) = explode(' ', $tableName);
|
list($tableName) = explode(' ', $tableName);
|
||||||
if (false === strpos($tableName, '`')) {
|
if (false === strpos($tableName, '`')) {
|
||||||
if (strpos($tableName, '.')) {
|
if (strpos($tableName, '.')) {
|
||||||
@@ -91,7 +91,7 @@ class Mysql extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getTables($dbName = '')
|
public function getTables($dbName = '')
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
$sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';
|
$sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';
|
||||||
// 调试开始
|
// 调试开始
|
||||||
$this->debug(true);
|
$this->debug(true);
|
||||||
@@ -130,17 +130,4 @@ class Mysql extends Connection
|
|||||||
return true;
|
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)
|
public function getFields($tableName)
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
list($tableName) = explode(' ', $tableName);
|
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 . '\');';
|
$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 = '')
|
public function getTables($dbName = '')
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
$sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'";
|
$sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'";
|
||||||
// 调试开始
|
// 调试开始
|
||||||
$this->debug(true);
|
$this->debug(true);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Sqlite extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getFields($tableName)
|
public function getFields($tableName)
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
list($tableName) = explode(' ', $tableName);
|
list($tableName) = explode(' ', $tableName);
|
||||||
$sql = 'PRAGMA table_info( ' . $tableName . ' )';
|
$sql = 'PRAGMA table_info( ' . $tableName . ' )';
|
||||||
// 调试开始
|
// 调试开始
|
||||||
@@ -76,7 +76,7 @@ class Sqlite extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getTables($dbName = '')
|
public function getTables($dbName = '')
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
$sql = "SELECT name FROM sqlite_master WHERE type='table' "
|
$sql = "SELECT name FROM sqlite_master WHERE type='table' "
|
||||||
. "UNION ALL SELECT name FROM sqlite_temp_master "
|
. "UNION ALL SELECT name FROM sqlite_temp_master "
|
||||||
. "WHERE type='table' ORDER BY name";
|
. "WHERE type='table' ORDER BY name";
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class Sqlsrv extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getFields($tableName)
|
public function getFields($tableName)
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
list($tableName) = explode(' ', $tableName);
|
list($tableName) = explode(' ', $tableName);
|
||||||
$sql = "SELECT column_name, data_type, column_default, is_nullable
|
$sql = "SELECT column_name, data_type, column_default, is_nullable
|
||||||
FROM information_schema.tables AS t
|
FROM information_schema.tables AS t
|
||||||
@@ -99,7 +99,7 @@ class Sqlsrv extends Connection
|
|||||||
*/
|
*/
|
||||||
public function getTables($dbName = '')
|
public function getTables($dbName = '')
|
||||||
{
|
{
|
||||||
$this->initConnect(true);
|
$this->initConnect(false);
|
||||||
$sql = "SELECT TABLE_NAME
|
$sql = "SELECT TABLE_NAME
|
||||||
FROM INFORMATION_SCHEMA.TABLES
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
WHERE TABLE_TYPE = 'BASE TABLE'
|
WHERE TABLE_TYPE = 'BASE TABLE'
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class File
|
|||||||
{
|
{
|
||||||
//检测日志文件大小,超过配置大小则备份日志文件重新生成
|
//检测日志文件大小,超过配置大小则备份日志文件重新生成
|
||||||
if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) {
|
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;
|
$this->writed[$destination] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,20 @@ use think\Model;
|
|||||||
|
|
||||||
class Collection extends BaseCollection
|
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
|
* @access public
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace think\model;
|
namespace think\model;
|
||||||
|
|
||||||
|
use think\Db;
|
||||||
use think\db\Query;
|
use think\db\Query;
|
||||||
use think\Model;
|
use think\Model;
|
||||||
|
|
||||||
@@ -120,22 +121,19 @@ class Merge extends Model
|
|||||||
* @access public
|
* @access public
|
||||||
* @param string $model 模型名称
|
* @param string $model 模型名称
|
||||||
* @param array $data 数据
|
* @param array $data 数据
|
||||||
* @param bool $insert 是否新增
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function parseData($model, $data, $insert = false)
|
protected function parseData($model, $data)
|
||||||
{
|
{
|
||||||
$item = [];
|
$item = [];
|
||||||
foreach ($data as $key => $val) {
|
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)) {
|
||||||
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {
|
list($name, $key) = explode('.', $this->mapFields[$key]);
|
||||||
list($name, $key) = explode('.', $this->mapFields[$key]);
|
if ($model == $name) {
|
||||||
if ($model == $name) {
|
|
||||||
$item[$key] = $val;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$item[$key] = $val;
|
$item[$key] = $val;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$item[$key] = $val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $item;
|
return $item;
|
||||||
@@ -174,6 +172,11 @@ class Merge extends Model
|
|||||||
$this->setAttr($this->updateTime, null);
|
$this->setAttr($this->updateTime, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 事件回调
|
||||||
|
if (false === $this->trigger('before_write', $this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$db = $this->db();
|
$db = $this->db();
|
||||||
$db->startTrans();
|
$db->startTrans();
|
||||||
$pk = $this->getPk();
|
$pk = $this->getPk();
|
||||||
@@ -190,8 +193,16 @@ class Merge extends Model
|
|||||||
$where = $this->updateWhere;
|
$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 (is_string($pk) && isset($data[$pk])) {
|
||||||
if (!isset($where[$pk])) {
|
if (!isset($where[$pk])) {
|
||||||
unset($where);
|
unset($where);
|
||||||
@@ -207,14 +218,12 @@ class Merge extends Model
|
|||||||
$name = is_int($key) ? $model : $key;
|
$name = is_int($key) ? $model : $key;
|
||||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||||
// 处理关联模型数据
|
// 处理关联模型数据
|
||||||
$data = $this->parseData($name, $this->data);
|
$data = $this->parseData($name, $data);
|
||||||
$query = new Query;
|
if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||||
if ($query->table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
|
||||||
$result = 1;
|
$result = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 清空change
|
|
||||||
$this->change = [];
|
|
||||||
// 新增回调
|
// 新增回调
|
||||||
$this->trigger('after_update', $this);
|
$this->trigger('after_update', $this);
|
||||||
} else {
|
} 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);
|
$result = $db->name($this->name)->strict(false)->insert($data);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
@@ -240,9 +249,6 @@ class Merge extends Model
|
|||||||
if ($insertId) {
|
if ($insertId) {
|
||||||
if (is_string($pk)) {
|
if (is_string($pk)) {
|
||||||
$this->data[$pk] = $insertId;
|
$this->data[$pk] = $insertId;
|
||||||
if ($this->fk == $pk) {
|
|
||||||
$this->change[] = $pk;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$this->data[$this->fk] = $insertId;
|
$this->data[$this->fk] = $insertId;
|
||||||
}
|
}
|
||||||
@@ -256,19 +262,20 @@ class Merge extends Model
|
|||||||
$name = is_int($key) ? $model : $key;
|
$name = is_int($key) ? $model : $key;
|
||||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||||
// 处理关联模型数据
|
// 处理关联模型数据
|
||||||
$data = $this->parseData($name, $source, true);
|
$data = $this->parseData($name, $source);
|
||||||
$query = new Query;
|
Db::table($table)->strict(false)->insert($data);
|
||||||
$query->table($table)->strict(false)->insert($data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 标记为更新
|
// 标记为更新
|
||||||
$this->isUpdate = true;
|
$this->isUpdate = true;
|
||||||
// 清空change
|
|
||||||
$this->change = [];
|
|
||||||
// 新增回调
|
// 新增回调
|
||||||
$this->trigger('after_insert', $this);
|
$this->trigger('after_insert', $this);
|
||||||
}
|
}
|
||||||
$db->commit();
|
$db->commit();
|
||||||
|
// 写入回调
|
||||||
|
$this->trigger('after_write', $this);
|
||||||
|
|
||||||
|
$this->origin = $this->data;
|
||||||
return $result;
|
return $result;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$db->rollback();
|
$db->rollback();
|
||||||
|
|||||||
@@ -19,24 +19,26 @@ class Pivot extends Model
|
|||||||
/** @var Model */
|
/** @var Model */
|
||||||
public $parent;
|
public $parent;
|
||||||
|
|
||||||
|
protected $autoWriteTimestamp = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 架构函数
|
||||||
* @access public
|
* @access public
|
||||||
* @param Model $parent
|
* @param Model $parent 上级模型
|
||||||
* @param array|object $data 数据
|
* @param array|object $data 数据
|
||||||
* @param string $table 中间数据表名
|
* @param string $table 中间数据表名
|
||||||
*/
|
*/
|
||||||
public function __construct(Model $parent, $data = [], $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->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 $foreignKey;
|
||||||
// 关联表主键
|
// 关联表主键
|
||||||
protected $localKey;
|
protected $localKey;
|
||||||
// 关联查询参数
|
|
||||||
protected $option;
|
|
||||||
// 基础查询
|
// 基础查询
|
||||||
protected $baseQuery;
|
protected $baseQuery;
|
||||||
|
|
||||||
@@ -79,15 +77,30 @@ abstract class Relation
|
|||||||
return (new $this->model)->toCollection($resultSet);
|
return (new $this->model)->toCollection($resultSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function getQueryFields($model)
|
||||||
* 移除关联查询参数
|
|
||||||
* @access public
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function removeOption()
|
|
||||||
{
|
{
|
||||||
$this->query->removeOption();
|
$fields = $this->query->getOptions('field');
|
||||||
return $this;
|
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);
|
$result = call_user_func_array([$this->query, $method], $args);
|
||||||
if ($result instanceof Query) {
|
if ($result instanceof Query) {
|
||||||
$this->option = $result->getOptions();
|
|
||||||
return $this;
|
return $this;
|
||||||
} else {
|
} else {
|
||||||
$this->option = [];
|
|
||||||
$this->baseQuery = false;
|
$this->baseQuery = false;
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ class BelongsTo extends OneToOne
|
|||||||
* @param string $foreignKey 关联外键
|
* @param string $foreignKey 关联外键
|
||||||
* @param string $localKey 关联主键
|
* @param string $localKey 关联主键
|
||||||
* @param string $joinType JOIN类型
|
* @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->parent = $parent;
|
||||||
$this->model = $model;
|
$this->model = $model;
|
||||||
@@ -33,6 +34,7 @@ class BelongsTo extends OneToOne
|
|||||||
$this->localKey = $localKey;
|
$this->localKey = $localKey;
|
||||||
$this->joinType = $joinType;
|
$this->joinType = $joinType;
|
||||||
$this->query = (new $model)->db();
|
$this->query = (new $model)->db();
|
||||||
|
$this->relation = $relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +50,16 @@ class BelongsTo extends OneToOne
|
|||||||
if ($closure) {
|
if ($closure) {
|
||||||
call_user_func_array($closure, [ & $this->query]);
|
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;
|
$relationModel = null;
|
||||||
} else {
|
} else {
|
||||||
$relationModel = $data[$result->$foreignKey];
|
$relationModel = $data[$result->$foreignKey];
|
||||||
|
$relationModel->setParent(clone $result);
|
||||||
|
$relationModel->isUpdate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($relationModel && !empty($this->bindAttr)) {
|
if ($relationModel && !empty($this->bindAttr)) {
|
||||||
@@ -135,7 +148,7 @@ class BelongsTo extends OneToOne
|
|||||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||||
}
|
}
|
||||||
// 设置关联属性
|
// 设置关联属性
|
||||||
$result->setAttr($attr, $relationModel);
|
$result->setRelation($attr, $relationModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,13 +172,46 @@ class BelongsTo extends OneToOne
|
|||||||
$relationModel = null;
|
$relationModel = null;
|
||||||
} else {
|
} else {
|
||||||
$relationModel = $data[$result->$foreignKey];
|
$relationModel = $data[$result->$foreignKey];
|
||||||
|
$relationModel->setParent(clone $result);
|
||||||
|
$relationModel->isUpdate(true);
|
||||||
}
|
}
|
||||||
if ($relationModel && !empty($this->bindAttr)) {
|
if ($relationModel && !empty($this->bindAttr)) {
|
||||||
// 绑定关联属性
|
// 绑定关联属性
|
||||||
$this->bindAttr($relationModel, $result, $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 $middle;
|
||||||
|
// 中间表模型名称
|
||||||
// 中间表模型
|
protected $pivotName;
|
||||||
|
// 中间表模型对象
|
||||||
protected $pivot;
|
protected $pivot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,8 +44,14 @@ class BelongsToMany extends Relation
|
|||||||
$this->model = $model;
|
$this->model = $model;
|
||||||
$this->foreignKey = $foreignKey;
|
$this->foreignKey = $foreignKey;
|
||||||
$this->localKey = $localKey;
|
$this->localKey = $localKey;
|
||||||
$this->middle = $table;
|
if (false !== strpos($table, '\\')) {
|
||||||
$this->query = (new $model)->db();
|
$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)
|
public function pivot($pivot)
|
||||||
{
|
{
|
||||||
$this->pivot = $pivot;
|
$this->pivotName = $pivot;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,9 +70,9 @@ class BelongsToMany extends Relation
|
|||||||
* @param $data
|
* @param $data
|
||||||
* @return mixed
|
* @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);
|
return new $pivot($this->parent, $data, $this->middle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +109,7 @@ class BelongsToMany extends Relation
|
|||||||
// 关联查询
|
// 关联查询
|
||||||
$pk = $this->parent->getPk();
|
$pk = $this->parent->getPk();
|
||||||
$condition['pivot.' . $localKey] = $this->parent->$pk;
|
$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)
|
public function getRelation($subRelation = '', $closure = null)
|
||||||
{
|
{
|
||||||
if ($closure) {
|
if ($closure) {
|
||||||
call_user_func_array($closure, [& $this->query]);
|
call_user_func_array($closure, [ & $this->query]);
|
||||||
}
|
}
|
||||||
$result = $this->buildQuery()->relation($subRelation)->select();
|
$result = $this->buildQuery()->relation($subRelation)->select();
|
||||||
$this->hydratePivot($result);
|
$this->hydratePivot($result);
|
||||||
@@ -260,7 +267,7 @@ class BelongsToMany extends Relation
|
|||||||
$data[$result->$pk] = [];
|
$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])) {
|
if (!isset($data[$pk])) {
|
||||||
$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;
|
$count = 0;
|
||||||
if (isset($result->$pk)) {
|
if (isset($result->$pk)) {
|
||||||
$pk = $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;
|
return $count;
|
||||||
}
|
}
|
||||||
@@ -316,7 +323,7 @@ class BelongsToMany extends Relation
|
|||||||
*/
|
*/
|
||||||
public function getRelationCountQuery($closure)
|
public function getRelationCountQuery($closure)
|
||||||
{
|
{
|
||||||
return $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, [
|
return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [
|
||||||
'pivot.' . $this->localKey => [
|
'pivot.' . $this->localKey => [
|
||||||
'exp',
|
'exp',
|
||||||
'=' . $this->parent->getTable() . '.' . $this->parent->getPk(),
|
'=' . $this->parent->getTable() . '.' . $this->parent->getPk(),
|
||||||
@@ -335,7 +342,7 @@ class BelongsToMany extends Relation
|
|||||||
protected function eagerlyManyToMany($where, $relation, $subRelation = '')
|
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 = [];
|
$data = [];
|
||||||
@@ -359,21 +366,23 @@ class BelongsToMany extends Relation
|
|||||||
/**
|
/**
|
||||||
* BELONGS TO MANY 关联查询
|
* BELONGS TO MANY 关联查询
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $table 中间表名
|
|
||||||
* @param string $foreignKey 关联模型关联键
|
* @param string $foreignKey 关联模型关联键
|
||||||
* @param string $localKey 当前模型关联键
|
* @param string $localKey 当前模型关联键
|
||||||
* @param array $condition 关联查询条件
|
* @param array $condition 关联查询条件
|
||||||
* @return Query
|
* @return Query
|
||||||
*/
|
*/
|
||||||
protected function belongsToManyQuery($table, $foreignKey, $localKey, $condition = [])
|
protected function belongsToManyQuery($foreignKey, $localKey, $condition = [])
|
||||||
{
|
{
|
||||||
// 关联查询封装
|
// 关联查询封装
|
||||||
$tableName = $this->query->getTable();
|
$tableName = $this->query->getTable();
|
||||||
$relationFk = $this->query->getPk();
|
$table = $this->pivot->getTable();
|
||||||
$query = $this->query->field($tableName . '.*')
|
$fields = $this->getQueryFields($tableName);
|
||||||
|
|
||||||
|
$query = $this->query->field($fields)
|
||||||
->field(true, false, $table, 'pivot', 'pivot__');
|
->field(true, false, $table, 'pivot', 'pivot__');
|
||||||
|
|
||||||
if (empty($this->baseQuery)) {
|
if (empty($this->baseQuery)) {
|
||||||
|
$relationFk = $this->query->getPk();
|
||||||
$query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
$query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
||||||
->where($condition);
|
->where($condition);
|
||||||
}
|
}
|
||||||
@@ -450,7 +459,7 @@ class BelongsToMany extends Relation
|
|||||||
$ids = (array) $id;
|
$ids = (array) $id;
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$pivot[$this->foreignKey] = $id;
|
$pivot[$this->foreignKey] = $id;
|
||||||
$this->query->table($this->middle)->insert($pivot, true);
|
$this->pivot->insert($pivot, true);
|
||||||
$result[] = $this->newPivot($pivot);
|
$result[] = $this->newPivot($pivot);
|
||||||
}
|
}
|
||||||
if (count($result) == 1) {
|
if (count($result) == 1) {
|
||||||
@@ -488,8 +497,7 @@ class BelongsToMany extends Relation
|
|||||||
if (isset($id)) {
|
if (isset($id)) {
|
||||||
$pivot[$this->foreignKey] = is_array($id) ? ['in', $id] : $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) {
|
if (isset($id) && $relationDel) {
|
||||||
$model = $this->model;
|
$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
|
* @access protected
|
||||||
@@ -504,9 +561,10 @@ class BelongsToMany extends Relation
|
|||||||
*/
|
*/
|
||||||
protected function baseQuery()
|
protected function baseQuery()
|
||||||
{
|
{
|
||||||
if (empty($this->baseQuery)) {
|
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||||
$pk = $this->parent->getPk();
|
$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);
|
$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;
|
$this->baseQuery = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace think\model\relation;
|
namespace think\model\relation;
|
||||||
|
|
||||||
use think\Db;
|
|
||||||
use think\db\Query;
|
use think\db\Query;
|
||||||
use think\Loader;
|
use think\Loader;
|
||||||
use think\Model;
|
use think\Model;
|
||||||
@@ -47,7 +46,14 @@ class HasMany extends Relation
|
|||||||
if ($closure) {
|
if ($closure) {
|
||||||
call_user_func_array($closure, [ & $this->query]);
|
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])) {
|
if (!isset($data[$result->$localKey])) {
|
||||||
$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])) {
|
if (!isset($data[$result->$localKey])) {
|
||||||
$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;
|
namespace think\model\relation;
|
||||||
|
|
||||||
use think\Db;
|
|
||||||
use think\db\Query;
|
use think\db\Query;
|
||||||
use think\Exception;
|
use think\Exception;
|
||||||
use think\Loader;
|
use think\Loader;
|
||||||
@@ -57,6 +56,7 @@ class HasManyThrough extends Relation
|
|||||||
if ($closure) {
|
if ($closure) {
|
||||||
call_user_func_array($closure, [ & $this->query]);
|
call_user_func_array($closure, [ & $this->query]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->relation($subRelation)->select();
|
return $this->relation($subRelation)->select();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +96,7 @@ class HasManyThrough extends Relation
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预载入关联查询 返回模型对象
|
* 预载入关联查询 返回模型对象
|
||||||
@@ -110,8 +109,7 @@ class HasManyThrough extends Relation
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联统计
|
* 关联统计
|
||||||
@@ -121,8 +119,7 @@ class HasManyThrough extends Relation
|
|||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function relationCount($result, $closure)
|
public function relationCount($result, $closure)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行基础查询(进执行一次)
|
* 执行基础查询(进执行一次)
|
||||||
@@ -131,12 +128,11 @@ class HasManyThrough extends Relation
|
|||||||
*/
|
*/
|
||||||
protected function baseQuery()
|
protected function baseQuery()
|
||||||
{
|
{
|
||||||
if (empty($this->baseQuery)) {
|
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||||
$through = $this->through;
|
$through = $this->through;
|
||||||
$model = $this->model;
|
$alias = Loader::parseName(basename(str_replace('\\', '/', $this->model)));
|
||||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
|
||||||
$throughTable = $through::getTable();
|
$throughTable = $through::getTable();
|
||||||
$pk = (new $this->model)->getPk();
|
$pk = (new $through)->getPk();
|
||||||
$throughKey = $this->throughKey;
|
$throughKey = $this->throughKey;
|
||||||
$modelTable = $this->parent->getTable();
|
$modelTable = $this->parent->getTable();
|
||||||
$this->query->field($alias . '.*')->alias($alias)
|
$this->query->field($alias . '.*')->alias($alias)
|
||||||
|
|||||||
@@ -50,7 +50,13 @@ class HasOne extends OneToOne
|
|||||||
call_user_func_array($closure, [ & $this->query]);
|
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;
|
$relationModel = null;
|
||||||
} else {
|
} else {
|
||||||
$relationModel = $data[$result->$localKey];
|
$relationModel = $data[$result->$localKey];
|
||||||
}
|
$relationModel->setParent(clone $result);
|
||||||
if ($relationModel && !empty($this->bindAttr)) {
|
$relationModel->isUpdate(true);
|
||||||
// 绑定关联属性
|
if (!empty($this->bindAttr)) {
|
||||||
$this->bindAttr($relationModel, $result, $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;
|
$relationModel = null;
|
||||||
} else {
|
} else {
|
||||||
$relationModel = $data[$result->$localKey];
|
$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)) {
|
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||||
// 绑定关联属性
|
|
||||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
|
||||||
}
|
|
||||||
$result->setAttr(Loader::parseName($relation), $relationModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace think\model\relation;
|
namespace think\model\relation;
|
||||||
|
|
||||||
use think\Db;
|
|
||||||
use think\db\Query;
|
use think\db\Query;
|
||||||
use think\Exception;
|
use think\Exception;
|
||||||
use think\Loader;
|
use think\Loader;
|
||||||
@@ -56,7 +55,14 @@ class MorphMany extends Relation
|
|||||||
if ($closure) {
|
if ($closure) {
|
||||||
call_user_func_array($closure, [ & $this->query]);
|
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])) {
|
if (!isset($data[$result->$pk])) {
|
||||||
$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->morphKey => $result->$pk,
|
||||||
$this->morphType => $this->type,
|
$this->morphType => $this->type,
|
||||||
], $relation, $subRelation, $closure);
|
], $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()
|
protected function baseQuery()
|
||||||
{
|
{
|
||||||
if (empty($this->baseQuery)) {
|
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||||
$pk = $this->parent->getPk();
|
$pk = $this->parent->getPk();
|
||||||
$map[$this->morphKey] = $this->parent->$pk;
|
$map[$this->morphKey] = $this->parent->$pk;
|
||||||
$map[$this->morphType] = $this->type;
|
$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 $morphType;
|
||||||
// 多态别名
|
// 多态别名
|
||||||
protected $alias;
|
protected $alias;
|
||||||
|
protected $relation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
@@ -31,13 +32,15 @@ class MorphTo extends Relation
|
|||||||
* @param string $morphType 多态字段名
|
* @param string $morphType 多态字段名
|
||||||
* @param string $morphKey 外键名
|
* @param string $morphKey 外键名
|
||||||
* @param array $alias 多态别名定义
|
* @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->parent = $parent;
|
||||||
$this->morphType = $morphType;
|
$this->morphType = $morphType;
|
||||||
$this->morphKey = $morphKey;
|
$this->morphKey = $morphKey;
|
||||||
$this->alias = $alias;
|
$this->alias = $alias;
|
||||||
|
$this->relation = $relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,8 +56,13 @@ class MorphTo extends Relation
|
|||||||
// 多态模型
|
// 多态模型
|
||||||
$model = $this->parseModel($this->parent->$morphType);
|
$model = $this->parseModel($this->parent->$morphType);
|
||||||
// 主键数据
|
// 主键数据
|
||||||
$pk = $this->parent->$morphKey;
|
$pk = $this->parent->$morphKey;
|
||||||
return (new $model)->relation($subRelation)->find($pk);
|
$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])) {
|
if (!isset($data[$result->$morphKey])) {
|
||||||
throw new Exception('relation data not exists :' . $this->model);
|
throw new Exception('relation data not exists :' . $this->model);
|
||||||
} else {
|
} 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};
|
$pk = $this->parent->{$this->morphKey};
|
||||||
$data = (new $model)->with($subRelation)->find($pk);
|
$data = (new $model)->with($subRelation)->find($pk);
|
||||||
if ($data) {
|
if ($data) {
|
||||||
|
$data->setParent(clone $result);
|
||||||
$data->isUpdate(true);
|
$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
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function baseQuery()
|
protected function baseQuery()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ abstract class OneToOne extends Relation
|
|||||||
protected $joinType;
|
protected $joinType;
|
||||||
// 要绑定的属性
|
// 要绑定的属性
|
||||||
protected $bindAttr = [];
|
protected $bindAttr = [];
|
||||||
|
// 关联方法名
|
||||||
|
protected $relation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置join类型
|
* 设置join类型
|
||||||
@@ -243,13 +245,19 @@ abstract class OneToOne extends Relation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($list[$relation])) {
|
if (isset($list[$relation])) {
|
||||||
$relationModel = new $model($list[$relation]);
|
$relationModel = new $model($list[$relation]);
|
||||||
|
$relationModel->setParent(clone $result);
|
||||||
|
$relationModel->isUpdate(true);
|
||||||
|
|
||||||
if (!empty($this->bindAttr)) {
|
if (!empty($this->bindAttr)) {
|
||||||
$this->bindAttr($relationModel, $result, $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
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function baseQuery()
|
protected function baseQuery()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ trait SoftDelete
|
|||||||
{
|
{
|
||||||
$model = new static();
|
$model = new static();
|
||||||
$field = $model->getDeleteTimeField(true);
|
$field = $model->getDeleteTimeField(true);
|
||||||
return $model->db(false);
|
return $model->getQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +42,7 @@ trait SoftDelete
|
|||||||
{
|
{
|
||||||
$model = new static();
|
$model = new static();
|
||||||
$field = $model->getDeleteTimeField(true);
|
$field = $model->getDeleteTimeField(true);
|
||||||
return $model->db(false)
|
return $model->getQuery()
|
||||||
->useSoftDelete($field, ['not null', '']);
|
->useSoftDelete($field, ['not null', '']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,11 +60,10 @@ trait SoftDelete
|
|||||||
$name = $this->getDeleteTimeField();
|
$name = $this->getDeleteTimeField();
|
||||||
if (!$force) {
|
if (!$force) {
|
||||||
// 软删除
|
// 软删除
|
||||||
$this->change[] = $name;
|
|
||||||
$this->data[$name] = $this->autoWriteTimestamp($name);
|
$this->data[$name] = $this->autoWriteTimestamp($name);
|
||||||
$result = $this->isUpdate()->save();
|
$result = $this->isUpdate()->save();
|
||||||
} else {
|
} else {
|
||||||
$result = $this->db(false)->delete($this->data);
|
$result = $this->getQuery()->delete($this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->trigger('after_delete', $this);
|
$this->trigger('after_delete', $this);
|
||||||
@@ -117,7 +116,7 @@ trait SoftDelete
|
|||||||
$where[$pk] = $this->getData($pk);
|
$where[$pk] = $this->getData($pk);
|
||||||
}
|
}
|
||||||
// 恢复删除
|
// 恢复删除
|
||||||
return $this->db(false)
|
return $this->getQuery()
|
||||||
->useSoftDelete($name, ['not null', ''])
|
->useSoftDelete($name, ['not null', ''])
|
||||||
->where($where)
|
->where($where)
|
||||||
->update([$name => null]);
|
->update([$name => null]);
|
||||||
@@ -143,7 +142,7 @@ trait SoftDelete
|
|||||||
*/
|
*/
|
||||||
protected function getDeleteTimeField($read = false)
|
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, '.')) {
|
if (!strpos($field, '.')) {
|
||||||
$field = '__TABLE__.' . $field;
|
$field = '__TABLE__.' . $field;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<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="robots" content="noindex,nofollow" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
Reference in New Issue
Block a user