1、内核更新
2、模板管理优化
This commit is contained in:
@@ -87,7 +87,7 @@ class Config extends Base{
|
|||||||
$files = $path . $filename . '/info.php';
|
$files = $path . $filename . '/info.php';
|
||||||
if (is_file($files)) {
|
if (is_file($files)) {
|
||||||
$info = include($files);
|
$info = include($files);
|
||||||
if ($info['type'] == $type) {
|
if (isset($info['type']) && $info['type'] == $type) {
|
||||||
$info['id'] = $filename;
|
$info['id'] = $filename;
|
||||||
$info['img'] = '/template/' . $filename . '/' . $info['img'];
|
$info['img'] = '/template/' . $filename . '/' . $info['img'];
|
||||||
$list[] = $info;
|
$list[] = $info;
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class User extends Base{
|
|||||||
return 0; //参数错误
|
return 0; //参数错误
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->db()->where($map)->find()->toArray();
|
$user = $this->where($map)->find();
|
||||||
if(is_array($user) && $user['status']){
|
if(is_array($user) && $user['status']){
|
||||||
/* 验证用户密码 */
|
/* 验证用户密码 */
|
||||||
if(md5($password.$user['salt']) === $user['password']){
|
if(md5($password.$user['salt']) === $user['password']){
|
||||||
|
|||||||
@@ -347,6 +347,8 @@ class App
|
|||||||
// 初始化模块
|
// 初始化模块
|
||||||
$request->module($module);
|
$request->module($module);
|
||||||
$config = self::init($module);
|
$config = self::init($module);
|
||||||
|
// 模块请求缓存检查
|
||||||
|
$request->cache($config['request_cache'], $config['request_cache_expire']);
|
||||||
} else {
|
} else {
|
||||||
throw new HttpException(404, 'module not exists:' . $module);
|
throw new HttpException(404, 'module not exists:' . $module);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ class Log
|
|||||||
const SQL = 'sql';
|
const SQL = 'sql';
|
||||||
const NOTICE = 'notice';
|
const NOTICE = 'notice';
|
||||||
const ALERT = 'alert';
|
const ALERT = 'alert';
|
||||||
|
const DEBUG = 'debug';
|
||||||
|
|
||||||
// 日志信息
|
// 日志信息
|
||||||
protected static $log = [];
|
protected static $log = [];
|
||||||
// 配置参数
|
// 配置参数
|
||||||
protected static $config = [];
|
protected static $config = [];
|
||||||
// 日志类型
|
// 日志类型
|
||||||
protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert'];
|
protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
|
||||||
// 日志写入驱动
|
// 日志写入驱动
|
||||||
protected static $driver;
|
protected static $driver;
|
||||||
|
|
||||||
@@ -136,6 +137,9 @@ class Log
|
|||||||
if (empty(self::$config['level'])) {
|
if (empty(self::$config['level'])) {
|
||||||
// 获取全部日志
|
// 获取全部日志
|
||||||
$log = self::$log;
|
$log = self::$log;
|
||||||
|
if (!App::$debug && isset($log['debug'])) {
|
||||||
|
unset($log['debug']);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 记录允许级别
|
// 记录允许级别
|
||||||
$log = [];
|
$log = [];
|
||||||
@@ -180,7 +184,7 @@ class Log
|
|||||||
self::init(Config::get('log'));
|
self::init(Config::get('log'));
|
||||||
}
|
}
|
||||||
// 写入日志
|
// 写入日志
|
||||||
return self::$driver->save($log);
|
return self::$driver->save($log, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1363,6 +1363,51 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
|||||||
return $this->relation()->belongsToMany($model, $table, $foreignKey, $localKey, $alias);
|
return $this->relation()->belongsToMany($model, $table, $foreignKey, $localKey, $alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MORPH MANY 关联定义
|
||||||
|
* @access public
|
||||||
|
* @param string $model 模型名
|
||||||
|
* @param string|array $morph 多态字段信息
|
||||||
|
* @param string $type 多态类型
|
||||||
|
* @return Relation
|
||||||
|
*/
|
||||||
|
public function morphMany($model, $morph, $type = '')
|
||||||
|
{
|
||||||
|
// 记录当前关联信息
|
||||||
|
$model = $this->parseModel($model);
|
||||||
|
$type = $type ?: Loader::parseName($this->name);
|
||||||
|
if (is_array($morph)) {
|
||||||
|
list($morphType, $foreignKey) = $morph;
|
||||||
|
} else {
|
||||||
|
$morphType = $morph . '_type';
|
||||||
|
$foreignKey = $morph . '_id';
|
||||||
|
}
|
||||||
|
return $this->relation()->morphMany($model, $foreignKey, $morphType, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MORPH TO 关联定义
|
||||||
|
* @access public
|
||||||
|
* @param string|array $morph 多态字段信息
|
||||||
|
* @param array $alias 多态别名定义
|
||||||
|
* @return Relation
|
||||||
|
*/
|
||||||
|
public function morphTo($morph = null, $alias = [])
|
||||||
|
{
|
||||||
|
if (is_null($morph)) {
|
||||||
|
$trace = debug_backtrace(false, 2);
|
||||||
|
$morph = Loader::parseName($trace[1]['function']);
|
||||||
|
}
|
||||||
|
// 记录当前关联信息
|
||||||
|
if (is_array($morph)) {
|
||||||
|
list($morphType, $foreignKey) = $morph;
|
||||||
|
} else {
|
||||||
|
$morphType = $morph . '_type';
|
||||||
|
$foreignKey = $morph . '_id';
|
||||||
|
}
|
||||||
|
return $this->relation()->morphTo($morphType, $foreignKey, $alias);
|
||||||
|
}
|
||||||
|
|
||||||
public function __call($method, $args)
|
public function __call($method, $args)
|
||||||
{
|
{
|
||||||
$query = $this->db();
|
$query = $this->db();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
namespace think;
|
namespace think;
|
||||||
|
|
||||||
use think\exception\TemplateNotFoundException;
|
use think\exception\TemplateNotFoundException;
|
||||||
|
use think\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThinkPHP分离出来的模板引擎
|
* ThinkPHP分离出来的模板引擎
|
||||||
@@ -25,6 +26,7 @@ class Template
|
|||||||
// 引擎配置
|
// 引擎配置
|
||||||
protected $config = [
|
protected $config = [
|
||||||
'view_path' => '', // 模板路径
|
'view_path' => '', // 模板路径
|
||||||
|
'view_base' => '',
|
||||||
'view_suffix' => 'html', // 默认模板文件后缀
|
'view_suffix' => 'html', // 默认模板文件后缀
|
||||||
'view_depr' => DS,
|
'view_depr' => DS,
|
||||||
'cache_suffix' => 'php', // 默认模板缓存后缀
|
'cache_suffix' => 'php', // 默认模板缓存后缀
|
||||||
@@ -1061,14 +1063,18 @@ class Template
|
|||||||
{
|
{
|
||||||
if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
|
if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
|
||||||
if (strpos($template, '@')) {
|
if (strpos($template, '@')) {
|
||||||
// 跨模块调用模板
|
list($module, $template) = explode('@', $template);
|
||||||
$template = str_replace(['/', ':'], $this->config['view_depr'], $template);
|
|
||||||
$template = APP_PATH . str_replace('@', '/' . basename($this->config['view_path']) . '/', $template);
|
|
||||||
} else {
|
|
||||||
$template = str_replace(['/', ':'], $this->config['view_depr'], $template);
|
|
||||||
$template = $this->config['view_path'] . $template;
|
|
||||||
}
|
}
|
||||||
$template .= '.' . ltrim($this->config['view_suffix'], '.');
|
if (0 !== strpos($template, '/')) {
|
||||||
|
$template = str_replace(['/', ':'], $this->config['view_depr'], $template);
|
||||||
|
}
|
||||||
|
if ($this->config['view_base']) {
|
||||||
|
$module = isset($module) ? $module : Request::instance()->module();
|
||||||
|
$path = $this->config['view_base'] . ($module ? $module . DS : '');
|
||||||
|
} else {
|
||||||
|
$path = $this->config['view_path'];
|
||||||
|
}
|
||||||
|
$template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_file($template)) {
|
if (is_file($template)) {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ class Validate
|
|||||||
{
|
{
|
||||||
$this->rule = array_merge($this->rule, $rules);
|
$this->rule = array_merge($this->rule, $rules);
|
||||||
$this->message = array_merge($this->message, $message);
|
$this->message = array_merge($this->message, $message);
|
||||||
$this->field = $field;
|
$this->field = array_merge($this->field, $field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace think\log\driver;
|
namespace think\log\driver;
|
||||||
|
|
||||||
|
use think\App;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地化调试输出到文件
|
* 本地化调试输出到文件
|
||||||
*/
|
*/
|
||||||
@@ -35,9 +37,10 @@ class File
|
|||||||
* 日志写入接口
|
* 日志写入接口
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $log 日志信息
|
* @param array $log 日志信息
|
||||||
|
* @param bool $depr 是否写入分割线
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function save(array $log = [])
|
public function save(array $log = [], $depr = true)
|
||||||
{
|
{
|
||||||
$now = date($this->config['time_format']);
|
$now = date($this->config['time_format']);
|
||||||
$destination = $this->config['path'] . date('Ym') . DS . date('d') . '.log';
|
$destination = $this->config['path'] . date('Ym') . DS . date('d') . '.log';
|
||||||
@@ -50,25 +53,29 @@ class File
|
|||||||
rename($destination, dirname($destination) . DS . $_SERVER['REQUEST_TIME'] . '-' . basename($destination));
|
rename($destination, dirname($destination) . DS . $_SERVER['REQUEST_TIME'] . '-' . basename($destination));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取基本信息
|
$depr = $depr ? "---------------------------------------------------------------\r\n" : '';
|
||||||
if (isset($_SERVER['HTTP_HOST'])) {
|
|
||||||
$current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
if (App::$debug) {
|
||||||
} else {
|
// 获取基本信息
|
||||||
$current_uri = "cmd:" . implode(' ', $_SERVER['argv']);
|
if (isset($_SERVER['HTTP_HOST'])) {
|
||||||
|
$current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||||
|
} else {
|
||||||
|
$current_uri = "cmd:" . implode(' ', $_SERVER['argv']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
||||||
|
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
||||||
|
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
||||||
|
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
||||||
|
$memory_str = ' [内存消耗:' . $memory_use . 'kb]';
|
||||||
|
$file_load = ' [文件加载:' . count(get_included_files()) . ']';
|
||||||
|
|
||||||
|
$info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n";
|
||||||
|
$server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0';
|
||||||
|
$remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
|
||||||
|
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI';
|
||||||
|
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
|
||||||
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
|
||||||
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
|
||||||
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
|
||||||
$memory_str = ' [内存消耗:' . $memory_use . 'kb]';
|
|
||||||
$file_load = ' [文件加载:' . count(get_included_files()) . ']';
|
|
||||||
|
|
||||||
$info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n";
|
|
||||||
$server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0';
|
|
||||||
$remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
|
|
||||||
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI';
|
|
||||||
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
|
||||||
foreach ($log as $type => $val) {
|
foreach ($log as $type => $val) {
|
||||||
$level = '';
|
$level = '';
|
||||||
foreach ($val as $msg) {
|
foreach ($val as $msg) {
|
||||||
@@ -80,12 +87,15 @@ class File
|
|||||||
if (in_array($type, $this->config['apart_level'])) {
|
if (in_array($type, $this->config['apart_level'])) {
|
||||||
// 独立记录的日志级别
|
// 独立记录的日志级别
|
||||||
$filename = $path . DS . date('d') . '_' . $type . '.log';
|
$filename = $path . DS . date('d') . '_' . $type . '.log';
|
||||||
error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$level}\r\n---------------------------------------------------------------\r\n", 3, $filename);
|
error_log("[{$now}] {$level}\r\n{$depr}", 3, $filename);
|
||||||
} else {
|
} else {
|
||||||
$info .= $level;
|
$info .= $level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$info}\r\n---------------------------------------------------------------\r\n", 3, $destination);
|
if (App::$debug) {
|
||||||
|
$info = "{$server} {$remote} {$method} {$uri}\r\n" . $info;
|
||||||
|
}
|
||||||
|
return error_log("[{$now}] {$info}\r\n{$depr}", 3, $destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,24 +63,27 @@ class Socket
|
|||||||
if (!$this->check()) {
|
if (!$this->check()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
$trace = [];
|
||||||
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
if (App::$debug) {
|
||||||
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
$runtime = number_format(microtime(true) - THINK_START_TIME, 10);
|
||||||
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
|
||||||
$memory_str = ' [内存消耗:' . $memory_use . 'kb]';
|
$time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]';
|
||||||
$file_load = ' [文件加载:' . count(get_included_files()) . ']';
|
$memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
|
||||||
|
$memory_str = ' [内存消耗:' . $memory_use . 'kb]';
|
||||||
|
$file_load = ' [文件加载:' . count(get_included_files()) . ']';
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_HOST'])) {
|
if (isset($_SERVER['HTTP_HOST'])) {
|
||||||
$current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
$current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||||
} else {
|
} else {
|
||||||
$current_uri = 'cmd:' . implode(' ', $_SERVER['argv']);
|
$current_uri = 'cmd:' . implode(' ', $_SERVER['argv']);
|
||||||
|
}
|
||||||
|
// 基本信息
|
||||||
|
$trace[] = [
|
||||||
|
'type' => 'group',
|
||||||
|
'msg' => $current_uri . $time_str . $memory_str . $file_load,
|
||||||
|
'css' => $this->css['page'],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
// 基本信息
|
|
||||||
$trace[] = [
|
|
||||||
'type' => 'group',
|
|
||||||
'msg' => $current_uri . $time_str . $memory_str . $file_load,
|
|
||||||
'css' => $this->css['page'],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($log as $type => $val) {
|
foreach ($log as $type => $val) {
|
||||||
$trace[] = [
|
$trace[] = [
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ class Relation
|
|||||||
{
|
{
|
||||||
const HAS_ONE = 1;
|
const HAS_ONE = 1;
|
||||||
const HAS_MANY = 2;
|
const HAS_MANY = 2;
|
||||||
const HAS_MANY_THROUGH = 5;
|
|
||||||
const BELONGS_TO = 3;
|
const BELONGS_TO = 3;
|
||||||
const BELONGS_TO_MANY = 4;
|
const BELONGS_TO_MANY = 4;
|
||||||
|
const HAS_MANY_THROUGH = 5;
|
||||||
|
const MORPH_TO = 6;
|
||||||
|
const MORPH_MANY = 7;
|
||||||
|
|
||||||
// 父模型对象
|
// 父模型对象
|
||||||
protected $parent;
|
protected $parent;
|
||||||
@@ -49,6 +51,7 @@ class Relation
|
|||||||
protected $where;
|
protected $where;
|
||||||
// 关联查询参数
|
// 关联查询参数
|
||||||
protected $option;
|
protected $option;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 架构函数
|
* 架构函数
|
||||||
* @access public
|
* @access public
|
||||||
@@ -59,6 +62,44 @@ class Relation
|
|||||||
$this->parent = $model;
|
$this->parent = $model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取关联的所属模型
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function getModel()
|
||||||
|
{
|
||||||
|
return $this->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取关联的查询对象
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function getQuery()
|
||||||
|
{
|
||||||
|
return $this->query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析模型的完整命名空间
|
||||||
|
* @access public
|
||||||
|
* @param string $model 模型名(或者完整类名)
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function parseModel($model)
|
||||||
|
{
|
||||||
|
if (isset($this->alias[$model])) {
|
||||||
|
$model = $this->alias[$model];
|
||||||
|
}
|
||||||
|
if (false === strpos($model, '\\')) {
|
||||||
|
$path = explode('\\', get_class($this->parent));
|
||||||
|
array_pop($path);
|
||||||
|
array_push($path, Loader::parseName($model, 1));
|
||||||
|
$model = implode('\\', $path);
|
||||||
|
}
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前关联信息
|
* 获取当前关联信息
|
||||||
* @access public
|
* @access public
|
||||||
@@ -87,6 +128,7 @@ class Relation
|
|||||||
$relation = $this->parent->$name();
|
$relation = $this->parent->$name();
|
||||||
$foreignKey = $this->foreignKey;
|
$foreignKey = $this->foreignKey;
|
||||||
$localKey = $this->localKey;
|
$localKey = $this->localKey;
|
||||||
|
$middle = $this->middle;
|
||||||
|
|
||||||
// 判断关联类型执行查询
|
// 判断关联类型执行查询
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
@@ -106,7 +148,7 @@ class Relation
|
|||||||
// 关联查询
|
// 关联查询
|
||||||
$pk = $this->parent->getPk();
|
$pk = $this->parent->getPk();
|
||||||
$condition['pivot.' . $localKey] = $this->parent->$pk;
|
$condition['pivot.' . $localKey] = $this->parent->$pk;
|
||||||
$result = $this->belongsToManyQuery($relation, $this->middle, $foreignKey, $localKey, $condition)->select();
|
$result = $this->belongsToManyQuery($relation->getQuery(), $middle, $foreignKey, $localKey, $condition)->select();
|
||||||
foreach ($result as $set) {
|
foreach ($result as $set) {
|
||||||
$pivot = [];
|
$pivot = [];
|
||||||
foreach ($set->getData() as $key => $val) {
|
foreach ($set->getData() as $key => $val) {
|
||||||
@@ -121,6 +163,16 @@ class Relation
|
|||||||
$set->pivot = new Pivot($pivot, $this->middle);
|
$set->pivot = new Pivot($pivot, $this->middle);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case self::MORPH_MANY:
|
||||||
|
$result = $relation->select();
|
||||||
|
break;
|
||||||
|
case self::MORPH_TO:
|
||||||
|
// 多态模型
|
||||||
|
$model = $this->parseModel($this->parent->$middle);
|
||||||
|
// 主键数据
|
||||||
|
$pk = $this->parent->$foreignKey;
|
||||||
|
$result = (new $model)->find($pk);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// 直接返回
|
// 直接返回
|
||||||
$result = $relation;
|
$result = $relation;
|
||||||
@@ -156,6 +208,7 @@ class Relation
|
|||||||
// 获取关联信息
|
// 获取关联信息
|
||||||
$localKey = $this->localKey;
|
$localKey = $this->localKey;
|
||||||
$foreignKey = $this->foreignKey;
|
$foreignKey = $this->foreignKey;
|
||||||
|
$middle = $this->middle;
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
case self::HAS_ONE:
|
case self::HAS_ONE:
|
||||||
case self::BELONGS_TO:
|
case self::BELONGS_TO:
|
||||||
@@ -220,6 +273,64 @@ class Relation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case self::MORPH_MANY:
|
||||||
|
$range = [];
|
||||||
|
foreach ($resultSet as $result) {
|
||||||
|
$pk = $result->getPk();
|
||||||
|
// 获取关联外键列表
|
||||||
|
if (isset($result->$pk)) {
|
||||||
|
$range[] = $result->$pk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($range)) {
|
||||||
|
$this->where[$foreignKey] = ['in', $range];
|
||||||
|
$this->where[$localKey] = $middle;
|
||||||
|
$data = $this->eagerlyMorphToMany($model, [
|
||||||
|
$foreignKey => ['in', $range],
|
||||||
|
$localKey => $middle,
|
||||||
|
], $relation, $subRelation, $closure);
|
||||||
|
|
||||||
|
// 关联数据封装
|
||||||
|
foreach ($resultSet as $result) {
|
||||||
|
if (!isset($data[$result->$pk])) {
|
||||||
|
$data[$result->$pk] = [];
|
||||||
|
}
|
||||||
|
$result->setAttr($relation, $this->resultSetBuild($data[$result->$pk], $class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case self::MORPH_TO:
|
||||||
|
$range = [];
|
||||||
|
foreach ($resultSet as $result) {
|
||||||
|
// 获取关联外键列表
|
||||||
|
if (!empty($result->$foreignKey)) {
|
||||||
|
$range[$result->$middle][] = $result->$foreignKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($range)) {
|
||||||
|
foreach ($range as $key => $val) {
|
||||||
|
// 多态类型映射
|
||||||
|
$model = $this->parseModel($key);
|
||||||
|
$obj = new $model;
|
||||||
|
$pk = $obj->getPk();
|
||||||
|
$list = $obj->all($val, $subRelation);
|
||||||
|
$data = [];
|
||||||
|
foreach ($list as $k => $vo) {
|
||||||
|
$data[$vo->$pk] = $vo;
|
||||||
|
}
|
||||||
|
foreach ($resultSet as $result) {
|
||||||
|
if ($key == $result->$middle) {
|
||||||
|
if (!isset($data[$result->$foreignKey])) {
|
||||||
|
$data[$result->$foreignKey] = [];
|
||||||
|
}
|
||||||
|
$result->setAttr($relation, $this->resultSetBuild($data[$result->$foreignKey], $class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $resultSet;
|
return $resultSet;
|
||||||
@@ -263,6 +374,7 @@ class Relation
|
|||||||
$model = $this->parent->$relation();
|
$model = $this->parent->$relation();
|
||||||
$localKey = $this->localKey;
|
$localKey = $this->localKey;
|
||||||
$foreignKey = $this->foreignKey;
|
$foreignKey = $this->foreignKey;
|
||||||
|
$middle = $this->middle;
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
case self::HAS_ONE:
|
case self::HAS_ONE:
|
||||||
case self::BELONGS_TO:
|
case self::BELONGS_TO:
|
||||||
@@ -293,6 +405,18 @@ class Relation
|
|||||||
$result->setAttr($relation, $this->resultSetBuild($data[$pk], $class));
|
$result->setAttr($relation, $this->resultSetBuild($data[$pk], $class));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case self::MORPH_MANY:
|
||||||
|
$pk = $result->getPk();
|
||||||
|
if (isset($result->$pk)) {
|
||||||
|
$data = $this->eagerlyMorphToMany($model, [$foreignKey => $result->$pk, $localKey => $middle], $relation, $subRelation, $closure);
|
||||||
|
$result->setAttr($relation, $this->resultSetBuild($data[$result->$pk], $class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case self::MORPH_TO:
|
||||||
|
// 多态类型映射
|
||||||
|
$model = $this->parseModel($result->{$this->middle});
|
||||||
|
$this->eagerlyMorphToOne($model, $relation, $result, $subRelation);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,7 +488,7 @@ class Relation
|
|||||||
$foreignKey = $this->foreignKey;
|
$foreignKey = $this->foreignKey;
|
||||||
$localKey = $this->localKey;
|
$localKey = $this->localKey;
|
||||||
// 预载入关联查询 支持嵌套预载入
|
// 预载入关联查询 支持嵌套预载入
|
||||||
$list = $this->belongsToManyQuery($model, $this->middle, $foreignKey, $localKey, $where)->with($subRelation)->select();
|
$list = $this->belongsToManyQuery($model->getQuery(), $this->middle, $foreignKey, $localKey, $where)->with($subRelation)->select();
|
||||||
|
|
||||||
// 组装模型数据
|
// 组装模型数据
|
||||||
$data = [];
|
$data = [];
|
||||||
@@ -385,6 +509,51 @@ class Relation
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多态MorphTo 关联模型预查询
|
||||||
|
* @access public
|
||||||
|
* @param object $model 关联模型对象
|
||||||
|
* @param array $where 关联预查询条件
|
||||||
|
* @param string $relation 关联名
|
||||||
|
* @param string $subRelation 子关联
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function eagerlyMorphToOne($model, $relation, &$result, $subRelation = '')
|
||||||
|
{
|
||||||
|
// 预载入关联查询 支持嵌套预载入
|
||||||
|
$pk = $this->parent->{$this->foreignKey};
|
||||||
|
$data = (new $model)->with($subRelation)->find($pk);
|
||||||
|
if ($data) {
|
||||||
|
$data->isUpdate(true);
|
||||||
|
}
|
||||||
|
$result->setAttr($relation, $data ?: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多态一对多 关联模型预查询
|
||||||
|
* @access public
|
||||||
|
* @param object $model 关联模型对象
|
||||||
|
* @param array $where 关联预查询条件
|
||||||
|
* @param string $relation 关联名
|
||||||
|
* @param string $subRelation 子关联
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function eagerlyMorphToMany($model, $where, $relation, $subRelation = '', $closure = false)
|
||||||
|
{
|
||||||
|
// 预载入关联查询 支持嵌套预载入
|
||||||
|
if ($closure) {
|
||||||
|
call_user_func_array($closure, [ & $model]);
|
||||||
|
}
|
||||||
|
$list = $model->getQuery()->where($where)->with($subRelation)->select();
|
||||||
|
$foreignKey = $this->foreignKey;
|
||||||
|
// 组装模型数据
|
||||||
|
$data = [];
|
||||||
|
foreach ($list as $set) {
|
||||||
|
$data[$set->$foreignKey][] = $set;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置当前关联定义的数据表别名
|
* 设置当前关联定义的数据表别名
|
||||||
* @access public
|
* @access public
|
||||||
@@ -516,6 +685,47 @@ class Relation
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MORPH_MANY 关联定义
|
||||||
|
* @access public
|
||||||
|
* @param string $model 模型名
|
||||||
|
* @param string $id 关联外键
|
||||||
|
* @param string $morphType 多态字段名
|
||||||
|
* @param string $type 多态类型
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function morphMany($model, $foreignKey, $morphType, $type)
|
||||||
|
{
|
||||||
|
// 记录当前关联信息
|
||||||
|
$this->type = self::MORPH_MANY;
|
||||||
|
$this->model = $model;
|
||||||
|
$this->middle = $type;
|
||||||
|
$this->foreignKey = $foreignKey;
|
||||||
|
$this->localKey = $morphType;
|
||||||
|
$this->query = (new $model)->db();
|
||||||
|
// 返回关联的模型对象
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MORPH_TO 关联定义
|
||||||
|
* @access public
|
||||||
|
* @param string $morphType 多态字段名
|
||||||
|
* @param string $foreignKey 外键名
|
||||||
|
* @param array $alias 多态别名定义
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function morphTo($morphType, $foreignKey, $alias)
|
||||||
|
{
|
||||||
|
// 记录当前关联信息
|
||||||
|
$this->type = self::MORPH_TO;
|
||||||
|
$this->middle = $morphType;
|
||||||
|
$this->foreignKey = $foreignKey;
|
||||||
|
$this->alias = $alias;
|
||||||
|
// 返回关联的模型对象
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BELONGS TO MANY 关联查询
|
* BELONGS TO MANY 关联查询
|
||||||
* @access public
|
* @access public
|
||||||
@@ -531,7 +741,7 @@ class Relation
|
|||||||
// 关联查询封装
|
// 关联查询封装
|
||||||
$tableName = $model->getTable();
|
$tableName = $model->getTable();
|
||||||
$relationFk = $model->getPk();
|
$relationFk = $model->getPk();
|
||||||
return $model::field($tableName . '.*')
|
return $model->field($tableName . '.*')
|
||||||
->field(true, false, $table, 'pivot', 'pivot__')
|
->field(true, false, $table, 'pivot', 'pivot__')
|
||||||
->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
||||||
->where($condition);
|
->where($condition);
|
||||||
@@ -662,39 +872,52 @@ class Relation
|
|||||||
|
|
||||||
public function __call($method, $args)
|
public function __call($method, $args)
|
||||||
{
|
{
|
||||||
|
static $baseQuery = [];
|
||||||
if ($this->query) {
|
if ($this->query) {
|
||||||
switch ($this->type) {
|
if (empty($baseQuery[$this->type])) {
|
||||||
case self::HAS_MANY:
|
$baseQuery[$this->type] = true;
|
||||||
if (isset($this->where)) {
|
switch ($this->type) {
|
||||||
$this->query->where($this->where);
|
case self::HAS_MANY:
|
||||||
} elseif (isset($this->parent->{$this->localKey})) {
|
if (isset($this->where)) {
|
||||||
// 关联查询带入关联条件
|
$this->query->where($this->where);
|
||||||
$this->query->where($this->foreignKey, $this->parent->{$this->localKey});
|
} elseif (isset($this->parent->{$this->localKey})) {
|
||||||
}
|
// 关联查询带入关联条件
|
||||||
break;
|
$this->query->where($this->foreignKey, $this->parent->{$this->localKey});
|
||||||
case self::HAS_MANY_THROUGH:
|
}
|
||||||
$through = $this->middle;
|
break;
|
||||||
$model = $this->model;
|
case self::HAS_MANY_THROUGH:
|
||||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
$through = $this->middle;
|
||||||
$throughTable = $through::getTable();
|
$model = $this->model;
|
||||||
$pk = (new $this->model)->getPk();
|
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||||
$throughKey = $this->throughKey;
|
$throughTable = $through::getTable();
|
||||||
$modelTable = $this->parent->getTable();
|
$pk = (new $this->model)->getPk();
|
||||||
$this->query->field($alias . '.*')->alias($alias)
|
$throughKey = $this->throughKey;
|
||||||
->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)
|
$modelTable = $this->parent->getTable();
|
||||||
->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)
|
$this->query->field($alias . '.*')->alias($alias)
|
||||||
->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey});
|
->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)
|
||||||
break;
|
->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)
|
||||||
case self::BELONGS_TO_MANY:
|
->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey});
|
||||||
// TODO
|
break;
|
||||||
|
case self::BELONGS_TO_MANY:
|
||||||
|
$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);
|
||||||
|
break;
|
||||||
|
case self::MORPH_MANY:
|
||||||
|
$pk = $this->parent->getPk();
|
||||||
|
$map[$this->foreignKey] = $this->parent->$pk;
|
||||||
|
$map[$this->localKey] = $this->middle;
|
||||||
|
$this->query->where($map);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = call_user_func_array([$this->query, $method], $args);
|
$result = call_user_func_array([$this->query, $method], $args);
|
||||||
if ($result instanceof \think\db\Query) {
|
if ($result instanceof \think\db\Query) {
|
||||||
$this->option = $result->getOptions();
|
$this->option = $result->getOptions();
|
||||||
return $this;
|
return $this;
|
||||||
} else {
|
} else {
|
||||||
$this->option = [];
|
$this->option = [];
|
||||||
|
$baseQuery = false;
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user