mirror of
https://gitee.com/zongzhige/shopxo.git
synced 2026-07-07 06:15:29 +08:00
thinkphp框架升级
This commit is contained in:
@ -26,7 +26,7 @@
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.0|^6.0",
|
||||
"johnkary/phpunit-speedtrap": "^1.0",
|
||||
"mikey179/vfsStream": "~1.6",
|
||||
"mikey179/vfsstream": "~1.6",
|
||||
"phploc/phploc": "2.*",
|
||||
"sebastian/phpcpd": "2.*",
|
||||
"squizlabs/php_codesniffer": "2.*",
|
||||
|
||||
@ -313,9 +313,9 @@ if (!function_exists('download')) {
|
||||
* @param integer $expire 有效期(秒)
|
||||
* @return \think\response\Download
|
||||
*/
|
||||
function download($filename, $name = '', $content = false, $expire = 360, $openinBrower = false)
|
||||
function download($filename, $name = '', $content = false, $expire = 360, $openinBrowser = false)
|
||||
{
|
||||
return Response::create($filename, 'download')->name($name)->isContent($content)->expire($expire)->openinBrower($openinBrower);
|
||||
return Response::create($filename, 'download')->name($name)->isContent($content)->expire($expire)->openinBrowser($openinBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ if (!function_exists('response')) {
|
||||
* @param string $type
|
||||
* @return Response
|
||||
*/
|
||||
function response($data = [], $code = 200, $header = [], $type = 'html')
|
||||
function response($data = '', $code = 200, $header = [], $type = 'html')
|
||||
{
|
||||
return Response::create($data, $type, $code, $header);
|
||||
}
|
||||
@ -686,7 +686,13 @@ if (!function_exists('widget')) {
|
||||
*/
|
||||
function widget($name, $data = [])
|
||||
{
|
||||
return app()->action($name, $data, 'widget');
|
||||
$result = app()->action($name, $data, 'widget');
|
||||
|
||||
if (is_object($result)) {
|
||||
$result = $result->getContent();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ use think\route\Dispatch;
|
||||
*/
|
||||
class App extends Container
|
||||
{
|
||||
const VERSION = '5.1.32 LTS';
|
||||
const VERSION = '5.1.38 LTS';
|
||||
|
||||
/**
|
||||
* 当前模块路径
|
||||
@ -179,6 +179,11 @@ class App extends Container
|
||||
|
||||
$this->instance('app', $this);
|
||||
|
||||
// 加载环境变量配置文件
|
||||
if (is_file($this->rootPath . '.env')) {
|
||||
$this->env->load($this->rootPath . '.env');
|
||||
}
|
||||
|
||||
$this->configExt = $this->env->get('config_ext', '.php');
|
||||
|
||||
// 加载惯例配置文件
|
||||
@ -196,11 +201,6 @@ class App extends Container
|
||||
'vendor_path' => $this->rootPath . 'vendor' . DIRECTORY_SEPARATOR,
|
||||
]);
|
||||
|
||||
// 加载环境变量配置文件
|
||||
if (is_file($this->rootPath . '.env')) {
|
||||
$this->env->load($this->rootPath . '.env');
|
||||
}
|
||||
|
||||
$this->namespace = $this->env->get('app_namespace', $this->namespace);
|
||||
$this->env->set('app_namespace', $this->namespace);
|
||||
|
||||
|
||||
@ -353,7 +353,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
|
||||
$result = isset($data[$field]) ? $data[$field] : null;
|
||||
}
|
||||
|
||||
switch ($operator) {
|
||||
switch (strtolower($operator)) {
|
||||
case '===':
|
||||
return $result === $value;
|
||||
case '!==':
|
||||
|
||||
@ -487,12 +487,17 @@ class Console
|
||||
public function getNamespaces()
|
||||
{
|
||||
$namespaces = [];
|
||||
foreach ($this->commands as $command) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
foreach ($this->commands as $name => $command) {
|
||||
if (is_string($command)) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($name));
|
||||
} else {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_filter($namespaces)));
|
||||
|
||||
@ -158,7 +158,7 @@ class Controller
|
||||
*/
|
||||
protected function fetch($template = '', $vars = [], $config = [])
|
||||
{
|
||||
return $this->view->fetch($template, $vars, $config);
|
||||
return Response::create($template, 'view')->assign($vars)->config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +171,7 @@ class Controller
|
||||
*/
|
||||
protected function display($content = '', $vars = [], $config = [])
|
||||
{
|
||||
return $this->view->display($content, $vars, $config);
|
||||
return Response::create($content, 'view')->assign($vars)->config($config)->isContent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -300,7 +300,7 @@ class File extends SplFileObject
|
||||
*/
|
||||
public function checkSize($size)
|
||||
{
|
||||
if ($this->getSize() > $size) {
|
||||
if ($this->getSize() > (int) $size) {
|
||||
$this->error = 'filesize not match';
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -127,8 +127,10 @@ class Log implements LoggerInterface
|
||||
}
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
// 命令行日志实时写入
|
||||
$this->write($msg, $type, true);
|
||||
if (empty($this->config['level']) || in_array($type, $this->config['level'])) {
|
||||
// 命令行日志实时写入
|
||||
$this->write($msg, $type, true);
|
||||
}
|
||||
} else {
|
||||
$this->log[$type][] = $msg;
|
||||
}
|
||||
|
||||
@ -18,6 +18,33 @@ use think\db\Query;
|
||||
* Class Model
|
||||
* @package think
|
||||
* @mixin Query
|
||||
* @method Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
|
||||
* @method Query whereRaw(string $where, array $bind = []) static 表达式查询
|
||||
* @method Query whereExp(string $field, string $condition, array $bind = []) static 字段表达式查询
|
||||
* @method Query when(mixed $condition, mixed $query, mixed $otherwise = null) static 条件查询
|
||||
* @method Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询
|
||||
* @method Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询
|
||||
* @method Query with(mixed $with) static 关联预载入
|
||||
* @method Query count(string $field) static Count统计查询
|
||||
* @method Query min(string $field) static Min统计查询
|
||||
* @method Query max(string $field) static Max统计查询
|
||||
* @method Query sum(string $field) static SUM统计查询
|
||||
* @method Query avg(string $field) static Avg统计查询
|
||||
* @method Query field(mixed $field, boolean $except = false) static 指定查询字段
|
||||
* @method Query fieldRaw(string $field, array $bind = []) static 指定查询字段
|
||||
* @method Query union(mixed $union, boolean $all = false) static UNION查询
|
||||
* @method Query limit(mixed $offset, integer $length = null) static 查询LIMIT
|
||||
* @method Query order(mixed $field, string $order = null) static 查询ORDER
|
||||
* @method Query orderRaw(string $field, array $bind = []) static 查询ORDER
|
||||
* @method Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存
|
||||
* @method mixed value(string $field) static 获取某个字段的值
|
||||
* @method array column(string $field, string $key = '') static 获取某个列的值
|
||||
* @method mixed find(mixed $data = null) static 查询单个记录
|
||||
* @method mixed select(mixed $data = null) static 查询多个记录
|
||||
* @method mixed get(mixed $data = null,mixed $with =[],bool $cache= false) static 查询单个记录 支持关联预载入
|
||||
* @method mixed getOrFail(mixed $data = null,mixed $with =[],bool $cache= false) static 查询单个记录 不存在则抛出异常
|
||||
* @method mixed findOrEmpty(mixed $data = null,mixed $with =[],bool $cache= false) static 查询单个记录 不存在则返回空模型
|
||||
* @method mixed all(mixed $data = null,mixed $with =[],bool $cache= false) static 查询多个记录 支持关联预载入
|
||||
* @method \think\Model withAttr(array $name,\Closure $closure) 动态定义获取器
|
||||
*/
|
||||
abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
@ -410,6 +437,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this->exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模型是否为空
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前数据对象
|
||||
* @access public
|
||||
@ -534,7 +571,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$this->autoRelationUpdate();
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
} elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
|
||||
// 自动写入更新时间
|
||||
$data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
|
||||
@ -743,12 +780,19 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 删除条件
|
||||
$pk = $this->getPk();
|
||||
|
||||
$where = [];
|
||||
if (is_string($pk) && isset($this->data[$pk])) {
|
||||
$where[] = [$pk, '=', $this->data[$pk]];
|
||||
} elseif (!empty($this->updateWhere)) {
|
||||
$where = $this->updateWhere;
|
||||
} else {
|
||||
$where = null;
|
||||
} elseif (is_array($pk)) {
|
||||
foreach ($pk as $field) {
|
||||
if (isset($this->data[$field])) {
|
||||
$where[] = [$field, '=', $this->data[$field]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($where)) {
|
||||
$where = empty($this->updateWhere) ? null : $this->updateWhere;
|
||||
}
|
||||
|
||||
return $where;
|
||||
|
||||
@ -682,6 +682,7 @@ class Request
|
||||
// 判断URL里面是否有兼容模式参数
|
||||
$pathinfo = $_GET[$this->config['var_pathinfo']];
|
||||
unset($_GET[$this->config['var_pathinfo']]);
|
||||
unset($this->get[$this->config['var_pathinfo']]);
|
||||
} elseif ($this->isCli()) {
|
||||
// CLI模式下 index.php module/controller/action/params/...
|
||||
$pathinfo = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
|
||||
@ -702,6 +703,10 @@ class Request
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($pathinfo)) {
|
||||
unset($this->get[$pathinfo], $this->request[$pathinfo]);
|
||||
}
|
||||
|
||||
$this->pathinfo = empty($pathinfo) || '/' == $pathinfo ? '' : ltrim($pathinfo, '/');
|
||||
}
|
||||
|
||||
@ -809,9 +814,14 @@ class Request
|
||||
return $this->server('REQUEST_METHOD') ?: 'GET';
|
||||
} elseif (!$this->method) {
|
||||
if (isset($_POST[$this->config['var_method']])) {
|
||||
$this->method = strtoupper($_POST[$this->config['var_method']]);
|
||||
$method = strtolower($this->method);
|
||||
$this->{$method} = $_POST;
|
||||
$method = strtolower($_POST[$this->config['var_method']]);
|
||||
if (in_array($method, ['get', 'post', 'put', 'patch', 'delete'])) {
|
||||
$this->method = strtoupper($method);
|
||||
$this->{$method} = $_POST;
|
||||
} else {
|
||||
$this->method = 'POST';
|
||||
}
|
||||
unset($_POST[$this->config['var_method']]);
|
||||
} elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) {
|
||||
$this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE'));
|
||||
} else {
|
||||
@ -1034,7 +1044,7 @@ class Request
|
||||
|
||||
protected function getInputData($content)
|
||||
{
|
||||
if (false !== strpos($this->contentType(), 'application/json') || 0 === strpos($content, '{"')) {
|
||||
if (false !== strpos($this->contentType(), 'json')) {
|
||||
return (array) json_decode($content, true);
|
||||
} elseif (strpos($content, '=')) {
|
||||
parse_str($content, $data);
|
||||
@ -1320,7 +1330,8 @@ class Request
|
||||
* @param array $data 数据源
|
||||
* @return void
|
||||
*/
|
||||
public function arrayReset(array &$data) {
|
||||
public function arrayReset(array &$data)
|
||||
{
|
||||
foreach ($data as &$value) {
|
||||
if (is_array($value)) {
|
||||
$this->arrayReset($value);
|
||||
@ -1523,7 +1534,7 @@ class Request
|
||||
*/
|
||||
public function has($name, $type = 'param', $checkEmpty = false)
|
||||
{
|
||||
if (!in_array($type, ['param', 'get', 'post', 'request', 'put', 'file', 'session', 'cookie', 'env', 'header', 'route'])) {
|
||||
if (!in_array($type, ['param', 'get', 'post', 'request', 'put', 'patch', 'file', 'session', 'cookie', 'env', 'header', 'route'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1625,6 +1636,16 @@ class Request
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否JSON请求
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isJson()
|
||||
{
|
||||
return false !== strpos($this->type(), 'json');
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否Ajax请求
|
||||
* @access public
|
||||
|
||||
@ -408,7 +408,7 @@ class Route
|
||||
$result = $this->bind[$domain];
|
||||
} elseif (isset($name) && isset($this->bind[$name])) {
|
||||
$result = $this->bind[$name];
|
||||
} elseif (isset($this->bind['*'])) {
|
||||
} elseif (!empty($subDomain) && isset($this->bind['*'])) {
|
||||
$result = $this->bind['*'];
|
||||
} else {
|
||||
$result = null;
|
||||
|
||||
@ -1311,7 +1311,7 @@ class Template
|
||||
public function __debugInfo()
|
||||
{
|
||||
$data = get_object_vars($this);
|
||||
unset($data['app'], $data['storege']);
|
||||
unset($data['app'], $data['storage']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -130,7 +130,9 @@ class Url
|
||||
// 匹配路由命名标识
|
||||
$url = $match[0];
|
||||
|
||||
$domain = $match[1];
|
||||
if ($domain) {
|
||||
$domain = $match[1];
|
||||
}
|
||||
|
||||
if (!is_null($match[2])) {
|
||||
$suffix = $match[2];
|
||||
@ -347,6 +349,7 @@ class Url
|
||||
// 匹配路由地址
|
||||
public function getRuleUrl($rule, &$vars = [], $allowDomain = '')
|
||||
{
|
||||
$port = $this->app['request']->port();
|
||||
foreach ($rule as $item) {
|
||||
list($url, $pattern, $domain, $suffix, $method) = $item;
|
||||
|
||||
@ -354,8 +357,8 @@ class Url
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($this->app['request']->port(), [80, 443])) {
|
||||
$domain .= ':' . $this->app['request']->port();
|
||||
if ($port && !in_array($port, [80, 443])) {
|
||||
$domain .= ':' . $port;
|
||||
}
|
||||
|
||||
if (empty($pattern)) {
|
||||
|
||||
@ -131,7 +131,7 @@ class Validate
|
||||
* 内置正则验证规则
|
||||
* @var array
|
||||
*/
|
||||
protected $regex = [
|
||||
protected $defaultRegex = [
|
||||
'alphaDash' => '/^[A-Za-z0-9\-\_]+$/',
|
||||
'chs' => '/^[\x{4e00}-\x{9fa5}]+$/u',
|
||||
'chsAlpha' => '/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u',
|
||||
@ -178,6 +178,12 @@ class Validate
|
||||
*/
|
||||
protected $append = [];
|
||||
|
||||
/**
|
||||
* 验证正则定义
|
||||
* @var array
|
||||
*/
|
||||
protected $regex = [];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
@ -513,7 +519,7 @@ class Validate
|
||||
|
||||
if (isset($this->append[$field])) {
|
||||
// 追加额外的验证规则
|
||||
$rules = array_merge($rules, $this->append[$field]);
|
||||
$rules = array_unique(array_merge($rules, $this->append[$field]), SORT_REGULAR);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
@ -561,10 +567,11 @@ class Validate
|
||||
} elseif (true !== $result) {
|
||||
// 返回自定义错误信息
|
||||
if (is_string($result) && false !== strpos($result, ':')) {
|
||||
$result = str_replace(
|
||||
[':attribute', ':rule'],
|
||||
[$title, (string) $rule],
|
||||
$result);
|
||||
$result = str_replace(':attribute', $title, $result);
|
||||
|
||||
if (strpos($result, ':rule') && is_scalar($rule)) {
|
||||
$result = str_replace(':rule', (string) $rule, $result);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -927,8 +934,8 @@ class Validate
|
||||
if (isset($rule[2])) {
|
||||
$imageType = strtolower($rule[2]);
|
||||
|
||||
if ('jpeg' == $imageType) {
|
||||
$imageType = 'jpg';
|
||||
if ('jpg' == $imageType) {
|
||||
$imageType = 'jpeg';
|
||||
}
|
||||
|
||||
if (image_type_to_extension($type, false) != $imageType) {
|
||||
@ -1006,6 +1013,8 @@ class Validate
|
||||
$map[] = [$key, '=', $data[$key]];
|
||||
}
|
||||
}
|
||||
} elseif (strpos($key, '=')) {
|
||||
parse_str($key, $map);
|
||||
} elseif (isset($data[$field])) {
|
||||
$map[] = [$key, '=', $data[$field]];
|
||||
} else {
|
||||
@ -1360,6 +1369,8 @@ class Validate
|
||||
{
|
||||
if (isset($this->regex[$rule])) {
|
||||
$rule = $this->regex[$rule];
|
||||
} elseif (isset($this->defaultRegex[$rule])) {
|
||||
$rule = $this->defaultRegex[$rule];
|
||||
}
|
||||
|
||||
if (0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
|
||||
@ -1461,13 +1472,17 @@ class Validate
|
||||
$msg = $title . $lang->get('not conform to the rules');
|
||||
}
|
||||
|
||||
if (is_string($msg) && 0 === strpos($msg, '{%')) {
|
||||
if (!is_string($msg)) {
|
||||
return $msg;
|
||||
}
|
||||
|
||||
if (0 === strpos($msg, '{%')) {
|
||||
$msg = $lang->get(substr($msg, 2, -1));
|
||||
} elseif ($lang->has($msg)) {
|
||||
$msg = $lang->get($msg);
|
||||
}
|
||||
|
||||
if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) {
|
||||
if (is_scalar($rule) && false !== strpos($msg, ':')) {
|
||||
// 变量替换
|
||||
if (is_string($rule) && strpos($rule, ',')) {
|
||||
$array = array_pad(explode(',', $rule), 3, '');
|
||||
@ -1475,9 +1490,12 @@ class Validate
|
||||
$array = array_pad([], 3, '');
|
||||
}
|
||||
$msg = str_replace(
|
||||
[':attribute', ':rule', ':1', ':2', ':3'],
|
||||
[$title, (string) $rule, $array[0], $array[1], $array[2]],
|
||||
[':attribute', ':1', ':2', ':3'],
|
||||
[$title, $array[0], $array[1], $array[2]],
|
||||
$msg);
|
||||
if (strpos($msg, ':rule')) {
|
||||
$msg = str_replace(':rule', (string) $rule, $msg);
|
||||
}
|
||||
}
|
||||
|
||||
return $msg;
|
||||
@ -1496,12 +1514,12 @@ class Validate
|
||||
$scene = $this->currentScene;
|
||||
}
|
||||
|
||||
$this->only = $this->append = $this->remove = [];
|
||||
|
||||
if (empty($scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->only = $this->append = $this->remove = [];
|
||||
|
||||
if (method_exists($this, 'scene' . $scene)) {
|
||||
call_user_func([$this, 'scene' . $scene]);
|
||||
} elseif (isset($this->scene[$scene])) {
|
||||
|
||||
@ -160,7 +160,10 @@ class View
|
||||
*/
|
||||
public function filter($filter)
|
||||
{
|
||||
$this->filter = $filter;
|
||||
if ($filter) {
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
7
thinkphp/library/think/cache/Driver.php
vendored
7
thinkphp/library/think/cache/Driver.php
vendored
@ -249,7 +249,6 @@ abstract class Driver
|
||||
{
|
||||
if ($this->tag) {
|
||||
$key = $this->getTagkey($this->tag);
|
||||
$prev = $this->tag;
|
||||
$this->tag = null;
|
||||
|
||||
if ($this->has($key)) {
|
||||
@ -266,7 +265,6 @@ abstract class Driver
|
||||
}
|
||||
|
||||
$this->set($key, $value, 0);
|
||||
$this->tag = $prev;
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,4 +358,9 @@ abstract class Driver
|
||||
{
|
||||
return $this->writeTimes;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->handler, $method], $args);
|
||||
}
|
||||
}
|
||||
|
||||
6
thinkphp/library/think/cache/driver/File.php
vendored
6
thinkphp/library/think/cache/driver/File.php
vendored
@ -278,11 +278,13 @@ class File extends Driver
|
||||
if (is_dir($path)) {
|
||||
$matches = glob($path . DIRECTORY_SEPARATOR . '*.php');
|
||||
if (is_array($matches)) {
|
||||
array_map('unlink', $matches);
|
||||
array_map(function ($v) {
|
||||
$this->unlink($v);
|
||||
}, $matches);
|
||||
}
|
||||
rmdir($path);
|
||||
} else {
|
||||
unlink($path);
|
||||
$this->unlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ class Memcached extends Driver
|
||||
}
|
||||
|
||||
$this->handler->addServers($servers);
|
||||
|
||||
$this->handler->setOption(\Memcached::OPT_COMPRESSION, false);
|
||||
if ('' != $this->options['username']) {
|
||||
$this->handler->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
$this->handler->setSaslAuthData($this->options['username'], $this->options['password']);
|
||||
@ -232,7 +232,7 @@ class Memcached extends Driver
|
||||
$this->handler->delete($tagName);
|
||||
}
|
||||
|
||||
if (!$this->handler->has($tagName)) {
|
||||
if (!$this->has($tagName)) {
|
||||
$this->handler->set($tagName, '');
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ class Memcached extends Driver
|
||||
if ($this->tag) {
|
||||
$tagName = $this->getTagKey($this->tag);
|
||||
|
||||
if ($this->handler->has($tagName)) {
|
||||
if ($this->has($tagName)) {
|
||||
$this->handler->append($tagName, ',' . $name);
|
||||
} else {
|
||||
$this->handler->set($tagName, $name);
|
||||
|
||||
@ -313,9 +313,10 @@ abstract class Builder
|
||||
// 使用闭包查询
|
||||
$newQuery = $query->newQuery()->setConnection($this->connection);
|
||||
$value($newQuery);
|
||||
$whereClause = $this->buildWhere($query, $newQuery->getOptions('where'));
|
||||
$whereClause = $this->buildWhere($newQuery, $newQuery->getOptions('where'));
|
||||
|
||||
if (!empty($whereClause)) {
|
||||
$query->bind($newQuery->getBind(false));
|
||||
$str[] = ' ' . $logic . ' ( ' . $whereClause . ' )';
|
||||
}
|
||||
} elseif (is_array($field)) {
|
||||
@ -407,7 +408,7 @@ abstract class Builder
|
||||
$jsonType = $query->getJsonFieldType($field);
|
||||
$bindType = $this->connection->getFieldBindType($jsonType);
|
||||
} else {
|
||||
$bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;
|
||||
$bindType = isset($binds[$field]) && 'LIKE' != $exp ? $binds[$field] : PDO::PARAM_STR;
|
||||
}
|
||||
|
||||
if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {
|
||||
@ -450,11 +451,11 @@ abstract class Builder
|
||||
// 模糊匹配
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$name = $query->bind($item, $bindType);
|
||||
$name = $query->bind($item, PDO::PARAM_STR);
|
||||
$array[] = $key . ' ' . $exp . ' :' . $name;
|
||||
}
|
||||
|
||||
$whereStr = '(' . implode($array, ' ' . strtoupper($logic) . ' ') . ')';
|
||||
$whereStr = '(' . implode(' ' . strtoupper($logic) . ' ', $array) . ')';
|
||||
} else {
|
||||
$whereStr = $key . ' ' . $exp . ' ' . $value;
|
||||
}
|
||||
@ -604,6 +605,10 @@ abstract class Builder
|
||||
$value = $this->parseClosure($query, $value);
|
||||
}
|
||||
|
||||
if ('=' == $exp && is_null($value)) {
|
||||
return $key . ' IS NULL';
|
||||
}
|
||||
|
||||
return $key . ' ' . $exp . ' ' . $value;
|
||||
}
|
||||
|
||||
@ -647,9 +652,10 @@ abstract class Builder
|
||||
// IN 查询
|
||||
if ($value instanceof \Closure) {
|
||||
$value = $this->parseClosure($query, $value, false);
|
||||
} elseif ($value instanceof Expression) {
|
||||
$value = $value->getValue();
|
||||
} else {
|
||||
$value = array_unique(is_array($value) ? $value : explode(',', $value));
|
||||
|
||||
$array = [];
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
@ -657,9 +663,12 @@ abstract class Builder
|
||||
$array[] = ':' . $name;
|
||||
}
|
||||
|
||||
$zone = implode(',', $array);
|
||||
|
||||
$value = empty($zone) ? "''" : $zone;
|
||||
if (count($array) == 1) {
|
||||
return $key . ('IN' == $exp ? ' = ' : ' <> ') . $array[0];
|
||||
} else {
|
||||
$zone = implode(',', $array);
|
||||
$value = empty($zone) ? "''" : $zone;
|
||||
}
|
||||
}
|
||||
|
||||
return $key . ' ' . $exp . ' (' . $value . ')';
|
||||
|
||||
@ -1246,22 +1246,14 @@ abstract class Connection
|
||||
* @access public
|
||||
* @param Query $query 查询对象
|
||||
* @param string $field 字段名
|
||||
* @param bool $default 默认值
|
||||
* @param mixed $default 默认值
|
||||
* @param bool $one 是否返回一个值
|
||||
* @return mixed
|
||||
*/
|
||||
public function value(Query $query, $field, $default = null)
|
||||
public function value(Query $query, $field, $default = null, $one = true)
|
||||
{
|
||||
$options = $query->getOptions();
|
||||
|
||||
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
||||
$cache = $options['cache'];
|
||||
$result = $this->getCacheData($query, $cache, null, $key);
|
||||
|
||||
if (false !== $result) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['field'])) {
|
||||
$query->removeOption('field');
|
||||
}
|
||||
@ -1271,7 +1263,19 @@ abstract class Connection
|
||||
}
|
||||
|
||||
$query->setOption('field', $field);
|
||||
$query->setOption('limit', 1);
|
||||
|
||||
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
||||
$cache = $options['cache'];
|
||||
$result = $this->getCacheData($query, $cache, null, $key);
|
||||
|
||||
if (false !== $result) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if ($one) {
|
||||
$query->setOption('limit', 1);
|
||||
}
|
||||
|
||||
// 生成查询SQL
|
||||
$sql = $this->builder->select($query);
|
||||
@ -1320,7 +1324,7 @@ abstract class Connection
|
||||
|
||||
$field = $aggregate . '(' . (!empty($distinct) ? 'DISTINCT ' : '') . $this->builder->parseKey($query, $field, true) . ') AS tp_' . strtolower($aggregate);
|
||||
|
||||
return $this->value($query, $field, 0);
|
||||
return $this->value($query, $field, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1335,16 +1339,6 @@ abstract class Connection
|
||||
{
|
||||
$options = $query->getOptions();
|
||||
|
||||
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
||||
// 判断查询缓存
|
||||
$cache = $options['cache'];
|
||||
$result = $this->getCacheData($query, $cache, null, $guid);
|
||||
|
||||
if (false !== $result) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['field'])) {
|
||||
$query->removeOption('field');
|
||||
}
|
||||
@ -1362,6 +1356,16 @@ abstract class Connection
|
||||
|
||||
$query->setOption('field', $field);
|
||||
|
||||
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
||||
// 判断查询缓存
|
||||
$cache = $options['cache'];
|
||||
$result = $this->getCacheData($query, $cache, null, $guid);
|
||||
|
||||
if (false !== $result) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// 生成查询SQL
|
||||
$sql = $this->builder->select($query);
|
||||
|
||||
@ -1463,9 +1467,7 @@ abstract class Connection
|
||||
$value = is_array($val) ? $val[0] : $val;
|
||||
$type = is_array($val) ? $val[1] : PDO::PARAM_STR;
|
||||
|
||||
if (self::PARAM_FLOAT == $type) {
|
||||
$value = (float) $value;
|
||||
} elseif (PDO::PARAM_STR == $type) {
|
||||
if ((self::PARAM_FLOAT == $type || PDO::PARAM_STR == $type) && is_string($value)) {
|
||||
$value = '\'' . addslashes($value) . '\'';
|
||||
} elseif (PDO::PARAM_INT == $type && '' === $value) {
|
||||
$value = 0;
|
||||
@ -1499,7 +1501,7 @@ abstract class Connection
|
||||
if (PDO::PARAM_INT == $val[1] && '' === $val[0]) {
|
||||
$val[0] = 0;
|
||||
} elseif (self::PARAM_FLOAT == $val[1]) {
|
||||
$val[0] = (float) $val[0];
|
||||
$val[0] = is_string($val[0]) ? (float) $val[0] : $val[0];
|
||||
$val[1] = PDO::PARAM_STR;
|
||||
}
|
||||
|
||||
|
||||
@ -95,14 +95,14 @@ class Query
|
||||
* @var array
|
||||
*/
|
||||
protected $timeRule = [
|
||||
'today' => ['today', 'tomorrow'],
|
||||
'yesterday' => ['yesterday', 'today'],
|
||||
'week' => ['this week 00:00:00', 'next week 00:00:00'],
|
||||
'last week' => ['last week 00:00:00', 'this week 00:00:00'],
|
||||
'month' => ['first Day of this month 00:00:00', 'first Day of next month 00:00:00'],
|
||||
'last month' => ['first Day of last month 00:00:00', 'first Day of this month 00:00:00'],
|
||||
'year' => ['this year 1/1', 'next year 1/1'],
|
||||
'last year' => ['last year 1/1', 'this year 1/1'],
|
||||
'today' => ['today', 'tomorrow -1second'],
|
||||
'yesterday' => ['yesterday', 'today -1second'],
|
||||
'week' => ['this week 00:00:00', 'next week 00:00:00 -1second'],
|
||||
'last week' => ['last week 00:00:00', 'this week 00:00:00 -1second'],
|
||||
'month' => ['first Day of this month 00:00:00', 'first Day of next month 00:00:00 -1second'],
|
||||
'last month' => ['first Day of last month 00:00:00', 'first Day of this month 00:00:00 -1second'],
|
||||
'year' => ['this year 1/1', 'next year 1/1 -1second'],
|
||||
'last year' => ['last year 1/1', 'this year 1/1 -1second'],
|
||||
];
|
||||
|
||||
/**
|
||||
@ -133,7 +133,27 @@ class Query
|
||||
*/
|
||||
public function newQuery()
|
||||
{
|
||||
return new static($this->connection);
|
||||
$query = new static($this->connection);
|
||||
|
||||
if ($this->model) {
|
||||
$query->model($this->model);
|
||||
}
|
||||
|
||||
if (isset($this->options['table'])) {
|
||||
$query->table($this->options['table']);
|
||||
} else {
|
||||
$query->name($this->name);
|
||||
}
|
||||
|
||||
if (isset($this->options['json'])) {
|
||||
$query->json($this->options['json'], $this->options['json_assoc']);
|
||||
}
|
||||
|
||||
if (isset($this->options['field_type'])) {
|
||||
$query->setJsonFieldType($this->options['field_type']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -611,9 +631,9 @@ class Query
|
||||
/**
|
||||
* 聚合查询
|
||||
* @access public
|
||||
* @param string $aggregate 聚合方法
|
||||
* @param string $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @param string $aggregate 聚合方法
|
||||
* @param string|Expression $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @return mixed
|
||||
*/
|
||||
public function aggregate($aggregate, $field, $force = false)
|
||||
@ -634,7 +654,7 @@ class Query
|
||||
/**
|
||||
* COUNT查询
|
||||
* @access public
|
||||
* @param string $field 字段名
|
||||
* @param string|Expression $field 字段名
|
||||
* @return float|string
|
||||
*/
|
||||
public function count($field = '*')
|
||||
@ -664,7 +684,7 @@ class Query
|
||||
/**
|
||||
* SUM查询
|
||||
* @access public
|
||||
* @param string $field 字段名
|
||||
* @param string|Expression $field 字段名
|
||||
* @return float
|
||||
*/
|
||||
public function sum($field)
|
||||
@ -675,8 +695,8 @@ class Query
|
||||
/**
|
||||
* MIN查询
|
||||
* @access public
|
||||
* @param string $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @param string|Expression $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @return mixed
|
||||
*/
|
||||
public function min($field, $force = true)
|
||||
@ -687,8 +707,8 @@ class Query
|
||||
/**
|
||||
* MAX查询
|
||||
* @access public
|
||||
* @param string $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @param string|Expression $field 字段名
|
||||
* @param bool $force 强制转为数字类型
|
||||
* @return mixed
|
||||
*/
|
||||
public function max($field, $force = true)
|
||||
@ -699,7 +719,7 @@ class Query
|
||||
/**
|
||||
* AVG查询
|
||||
* @access public
|
||||
* @param string $field 字段名
|
||||
* @param string|Expression $field 字段名
|
||||
* @return float
|
||||
*/
|
||||
public function avg($field)
|
||||
@ -834,9 +854,10 @@ class Query
|
||||
* @param mixed $join 关联的表名
|
||||
* @param mixed $condition 条件
|
||||
* @param string $type JOIN类型
|
||||
* @param array $bind 参数绑定
|
||||
* @return $this
|
||||
*/
|
||||
public function join($join, $condition = null, $type = 'INNER')
|
||||
public function join($join, $condition = null, $type = 'INNER', $bind = [])
|
||||
{
|
||||
if (empty($condition)) {
|
||||
// 如果为组数,则循环调用join
|
||||
@ -847,7 +868,9 @@ class Query
|
||||
}
|
||||
} else {
|
||||
$table = $this->getJoinTable($join);
|
||||
|
||||
if ($bind) {
|
||||
$this->bindParams($condition, $bind);
|
||||
}
|
||||
$this->options['join'][] = [$table, strtoupper($type), $condition];
|
||||
}
|
||||
|
||||
@ -859,9 +882,10 @@ class Query
|
||||
* @access public
|
||||
* @param mixed $join 关联的表名
|
||||
* @param mixed $condition 条件
|
||||
* @param array $bind 参数绑定
|
||||
* @return $this
|
||||
*/
|
||||
public function leftJoin($join, $condition = null)
|
||||
public function leftJoin($join, $condition = null, $bind = [])
|
||||
{
|
||||
return $this->join($join, $condition, 'LEFT');
|
||||
}
|
||||
@ -871,9 +895,10 @@ class Query
|
||||
* @access public
|
||||
* @param mixed $join 关联的表名
|
||||
* @param mixed $condition 条件
|
||||
* @param array $bind 参数绑定
|
||||
* @return $this
|
||||
*/
|
||||
public function rightJoin($join, $condition = null)
|
||||
public function rightJoin($join, $condition = null, $bind = [])
|
||||
{
|
||||
return $this->join($join, $condition, 'RIGHT');
|
||||
}
|
||||
@ -883,9 +908,10 @@ class Query
|
||||
* @access public
|
||||
* @param mixed $join 关联的表名
|
||||
* @param mixed $condition 条件
|
||||
* @param array $bind 参数绑定
|
||||
* @return $this
|
||||
*/
|
||||
public function fullJoin($join, $condition = null)
|
||||
public function fullJoin($join, $condition = null, $bind = [])
|
||||
{
|
||||
return $this->join($join, $condition, 'FULL');
|
||||
}
|
||||
@ -943,6 +969,10 @@ class Query
|
||||
*/
|
||||
public function union($union, $all = false)
|
||||
{
|
||||
if (empty($union)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION';
|
||||
|
||||
if (is_array($union)) {
|
||||
@ -1502,6 +1532,7 @@ class Query
|
||||
{
|
||||
if ($field instanceof $this) {
|
||||
$this->options['where'] = $field->getOptions('where');
|
||||
$this->bind($field->getBind(false));
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -1517,10 +1548,10 @@ class Query
|
||||
}
|
||||
|
||||
if ($field instanceof Expression) {
|
||||
return $this->whereRaw($field, is_array($op) ? $op : []);
|
||||
return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
|
||||
} elseif ($strict) {
|
||||
// 使用严格模式查询
|
||||
$where = [$field, $op, $condition];
|
||||
$where = [$field, $op, $condition, $logic];
|
||||
} elseif (is_array($field)) {
|
||||
// 解析数组批量查询
|
||||
return $this->parseArrayWhereItems($field, $logic);
|
||||
@ -1528,7 +1559,7 @@ class Query
|
||||
$where = $field;
|
||||
} elseif (is_string($field)) {
|
||||
if (preg_match('/[,=\<\'\"\(\s]/', $field)) {
|
||||
return $this->whereRaw($field, $op);
|
||||
return $this->whereRaw($field, $op, $logic);
|
||||
} elseif (is_string($op) && strtolower($op) == 'exp') {
|
||||
$bind = isset($param[2]) && is_array($param[2]) ? $param[2] : null;
|
||||
return $this->whereExp($field, $condition, $bind, $logic);
|
||||
@ -1572,7 +1603,7 @@ class Query
|
||||
// 字段相等查询
|
||||
$where = [$field, '=', $op];
|
||||
}
|
||||
} elseif (in_array(strtoupper($op), ['REGEXP', 'NOT REGEXP', 'EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
|
||||
} elseif (in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
|
||||
$where = [$field, $op, is_string($condition) ? $this->raw($condition) : $condition];
|
||||
} else {
|
||||
$where = $field ? [$field, $op, $condition, isset($param[2]) ? $param[2] : null] : null;
|
||||
@ -1645,6 +1676,7 @@ class Query
|
||||
{
|
||||
if (true === $option) {
|
||||
$this->options = [];
|
||||
$this->bind = [];
|
||||
} elseif (is_string($option) && isset($this->options[$option])) {
|
||||
unset($this->options[$option]);
|
||||
}
|
||||
@ -2186,12 +2218,12 @@ class Query
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置需要追加输出的属性
|
||||
* 设置需要附加的输出属性
|
||||
* @access public
|
||||
* @param array $append 需要追加的属性
|
||||
* @param array $append 属性列表
|
||||
* @return $this
|
||||
*/
|
||||
public function append(array $append)
|
||||
public function append(array $append = [])
|
||||
{
|
||||
$this->options['append'] = $append;
|
||||
return $this;
|
||||
@ -2458,7 +2490,7 @@ class Query
|
||||
if (is_array($value)) {
|
||||
$this->bind = array_merge($this->bind, $value);
|
||||
} else {
|
||||
$name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_';
|
||||
$name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_' . mt_rand() . '_';
|
||||
|
||||
$this->bind[$name] = [$value, $type];
|
||||
return $name;
|
||||
@ -3344,13 +3376,13 @@ class Query
|
||||
|
||||
// 输出属性控制
|
||||
if (!empty($options['visible'])) {
|
||||
$result->visible($options['visible']);
|
||||
$result->visible($options['visible'], true);
|
||||
} elseif (!empty($options['hidden'])) {
|
||||
$result->hidden($options['hidden']);
|
||||
$result->hidden($options['hidden'], true);
|
||||
}
|
||||
|
||||
if (!empty($options['append'])) {
|
||||
$result->append($options['append']);
|
||||
$result->append($options['append'], true);
|
||||
}
|
||||
|
||||
// 关联查询
|
||||
|
||||
@ -62,7 +62,7 @@ class Mysql extends Builder
|
||||
$bind = $this->connection->getFieldsBind($options['table']);
|
||||
|
||||
foreach ($dataSet as $k => $data) {
|
||||
$data = $this->parseData($query, $data, $allowFields, $bind, '_' . $k);
|
||||
$data = $this->parseData($query, $data, $allowFields, $bind);
|
||||
|
||||
$values[] = '( ' . implode(',', array_values($data)) . ' )';
|
||||
|
||||
@ -94,13 +94,17 @@ class Mysql extends Builder
|
||||
* @param Query $query 查询对象
|
||||
* @param string $key
|
||||
* @param string $exp
|
||||
* @param Expression $value
|
||||
* @param mixed $value
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
protected function parseRegexp(Query $query, $key, $exp, Expression $value, $field)
|
||||
protected function parseRegexp(Query $query, $key, $exp, $value, $field)
|
||||
{
|
||||
return $key . ' ' . $exp . ' ' . $value->getValue();
|
||||
if ($value instanceof Expression) {
|
||||
$value = $value->getValue();
|
||||
}
|
||||
|
||||
return $key . ' ' . $exp . ' ' . $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +129,7 @@ class Mysql extends Builder
|
||||
// JSON字段支持
|
||||
list($field, $name) = explode('->', $key, 2);
|
||||
|
||||
return 'json_extract(' . $this->parseKey($query, $field, true) . ', \'$.' . str_replace('->', '.', $name) . '\')';
|
||||
return 'json_extract(' . $this->parseKey($query, $field, true) . ', \'$' . (strpos($name, '[') === 0 ? '' : '.') . str_replace('->', '.', $name) . '\')';
|
||||
} elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
|
||||
list($table, $key) = explode('.', $key, 2);
|
||||
|
||||
@ -145,7 +149,7 @@ class Mysql extends Builder
|
||||
throw new Exception('not support data:' . $key);
|
||||
}
|
||||
|
||||
if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) {
|
||||
if ('*' != $key && !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
|
||||
$key = '`' . $key . '`';
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ class Sqlsrv extends Builder
|
||||
throw new Exception('not support data:' . $key);
|
||||
}
|
||||
|
||||
if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {
|
||||
if ('*' != $key && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
|
||||
$key = '[' . $key . ']';
|
||||
}
|
||||
|
||||
|
||||
@ -136,7 +136,27 @@ class Mysql extends Connection
|
||||
*/
|
||||
protected function getExplain($sql)
|
||||
{
|
||||
$pdo = $this->linkID->query("EXPLAIN " . $sql);
|
||||
$pdo = $this->linkID->prepare("EXPLAIN " . $this->queryStr);
|
||||
|
||||
foreach ($this->bind as $key => $val) {
|
||||
// 占位符
|
||||
$param = is_int($key) ? $key + 1 : ':' . $key;
|
||||
|
||||
if (is_array($val)) {
|
||||
if (PDO::PARAM_INT == $val[1] && '' === $val[0]) {
|
||||
$val[0] = 0;
|
||||
} elseif (self::PARAM_FLOAT == $val[1]) {
|
||||
$val[0] = is_string($val[0]) ? (float) $val[0] : $val[0];
|
||||
$val[1] = PDO::PARAM_STR;
|
||||
}
|
||||
|
||||
$result = $pdo->bindValue($param, $val[0], $val[1]);
|
||||
} else {
|
||||
$result = $pdo->bindValue($param, $val);
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->execute();
|
||||
$result = $pdo->fetch(PDO::FETCH_ASSOC);
|
||||
$result = array_change_key_case($result);
|
||||
|
||||
|
||||
@ -37,6 +37,10 @@ DECLARE
|
||||
v_sql varchar;
|
||||
v_rec RECORD;
|
||||
v_key varchar;
|
||||
v_conkey smallint[];
|
||||
v_pk varchar[];
|
||||
v_len smallint;
|
||||
v_pos smallint := 1;
|
||||
BEGIN
|
||||
SELECT
|
||||
pg_class.oid INTO v_oid
|
||||
@ -49,6 +53,31 @@ BEGIN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT
|
||||
pg_constraint.conkey INTO v_conkey
|
||||
FROM
|
||||
pg_constraint
|
||||
INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
|
||||
INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid
|
||||
INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid
|
||||
WHERE
|
||||
pg_class.relname = a_table_name
|
||||
AND pg_constraint.contype = 'p';
|
||||
|
||||
v_len := array_length(v_conkey,1) + 1;
|
||||
WHILE v_pos < v_len LOOP
|
||||
SELECT
|
||||
pg_attribute.attname INTO v_key
|
||||
FROM pg_constraint
|
||||
INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
|
||||
INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid AND pg_attribute.attnum = pg_constraint.conkey [ v_conkey[v_pos] ]
|
||||
INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid
|
||||
WHERE pg_class.relname = a_table_name AND pg_constraint.contype = 'p';
|
||||
v_pk := array_append(v_pk,v_key);
|
||||
|
||||
v_pos := v_pos + 1;
|
||||
END LOOP;
|
||||
|
||||
v_sql='
|
||||
SELECT
|
||||
pg_attribute.attname AS fields_name,
|
||||
@ -83,12 +112,19 @@ BEGIN
|
||||
v_ret.fields_not_null=v_rec.fields_not_null;
|
||||
v_ret.fields_default=v_rec.fields_default;
|
||||
v_ret.fields_comment=v_rec.fields_comment;
|
||||
SELECT constraint_name INTO v_key FROM information_schema.key_column_usage WHERE table_schema=a_schema_name AND table_name=a_table_name AND column_name=v_rec.fields_name;
|
||||
IF FOUND THEN
|
||||
v_ret.fields_key_name=v_key;
|
||||
ELSE
|
||||
v_ret.fields_key_name='';
|
||||
END IF;
|
||||
|
||||
v_ret.fields_key_name='';
|
||||
|
||||
v_len := array_length(v_pk,1) + 1;
|
||||
v_pos := 1;
|
||||
WHILE v_pos < v_len LOOP
|
||||
IF v_rec.fields_name = v_pk[v_pos] THEN
|
||||
v_ret.fields_key_name=v_pk[v_pos];
|
||||
EXIT;
|
||||
END IF;
|
||||
v_pos := v_pos + 1;
|
||||
END LOOP;
|
||||
|
||||
RETURN NEXT v_ret;
|
||||
END LOOP;
|
||||
RETURN ;
|
||||
|
||||
@ -26,7 +26,7 @@ class DbException extends Exception
|
||||
* @param string $sql
|
||||
* @param int $code
|
||||
*/
|
||||
public function __construct($message, array $config, $sql, $code = 10500)
|
||||
public function __construct($message, array $config = [], $sql = '', $code = 10500)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
|
||||
@ -18,7 +18,7 @@ class ValidateException extends \RuntimeException
|
||||
public function __construct($error, $code = 0)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->message = is_array($error) ? implode("\n\r", $error) : $error;
|
||||
$this->message = is_array($error) ? implode(PHP_EOL, $error) : $error;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
|
||||
@ -16,11 +16,14 @@ use think\Facade;
|
||||
/**
|
||||
* @see \think\Config
|
||||
* @mixin \think\Config
|
||||
* @method array load(string $file, string $name = '') static 加载配置文件
|
||||
* @method bool has(string $name) static 检测配置是否存在
|
||||
* @method array pull(string $name) static 获取一级配置
|
||||
* @method array pull(string $name) static 获取一级配置参数
|
||||
* @method mixed get(string $name,mixed $default = null) static 获取配置参数
|
||||
* @method mixed set(string $name, mixed $value = null) static 设置配置参数
|
||||
* @method array reset(string $prefix ='') static 重置配置参数
|
||||
* @method array set(mixed $name, mixed $value = null) static 设置配置参数
|
||||
* @method array reset(string $name ='') static 重置配置参数
|
||||
* @method void remove(string $name = '') static 移除配置
|
||||
* @method void setYaconf(mixed $yaconf) static 设置开启Yaconf 或者指定配置文件名
|
||||
*/
|
||||
class Config extends Facade
|
||||
{
|
||||
|
||||
@ -21,6 +21,7 @@ use think\Facade;
|
||||
* @method \think\Log record(mixed $msg, string $type = 'info', array $context = []) static 记录日志信息
|
||||
* @method \think\Log clear() static 清空日志信息
|
||||
* @method \think\Log key(string $key) static 当前日志记录的授权key
|
||||
* @method \think\Log close() static 关闭本次请求日志写入
|
||||
* @method bool check(array $config) static 检查日志写入权限
|
||||
* @method bool save() static 保存调试信息
|
||||
* @method void write(mixed $msg, string $type = 'info', bool $force = false) static 实时写入日志信息
|
||||
|
||||
@ -19,7 +19,7 @@ use think\App;
|
||||
class File
|
||||
{
|
||||
protected $config = [
|
||||
'time_format' => ' c ',
|
||||
'time_format' => 'c',
|
||||
'single' => false,
|
||||
'file_size' => 2097152,
|
||||
'path' => '',
|
||||
@ -107,7 +107,13 @@ class File
|
||||
$info['timestamp'] = date($this->config['time_format']);
|
||||
|
||||
foreach ($message as $type => $msg) {
|
||||
$info[$type] = is_array($msg) ? implode("\r\n", $msg) : $msg;
|
||||
$msg = is_array($msg) ? implode(PHP_EOL, $msg) : $msg;
|
||||
if (PHP_SAPI == 'cli') {
|
||||
$info['msg'] = $msg;
|
||||
$info['type'] = $type;
|
||||
} else {
|
||||
$info[$type] = $msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (PHP_SAPI == 'cli') {
|
||||
@ -140,13 +146,13 @@ class File
|
||||
}
|
||||
}
|
||||
|
||||
$cli = PHP_SAPI == 'cli' ? '_cli' : '';
|
||||
|
||||
if ($this->config['single']) {
|
||||
$name = is_string($this->config['single']) ? $this->config['single'] : 'single';
|
||||
|
||||
$destination = $this->config['path'] . $name . '.log';
|
||||
$destination = $this->config['path'] . $name . $cli . '.log';
|
||||
} else {
|
||||
$cli = PHP_SAPI == 'cli' ? '_cli' : '';
|
||||
|
||||
if ($this->config['max_files']) {
|
||||
$filename = date('Ymd') . $cli . '.log';
|
||||
} else {
|
||||
@ -172,15 +178,13 @@ class File
|
||||
|
||||
if ($this->config['single']) {
|
||||
$name = is_string($this->config['single']) ? $this->config['single'] : 'single';
|
||||
|
||||
$name .= '_' . $type;
|
||||
} elseif ($this->config['max_files']) {
|
||||
$name = date('Ymd') . '_' . $type . $cli;
|
||||
$name = date('Ymd');
|
||||
} else {
|
||||
$name = date('d') . '_' . $type . $cli;
|
||||
$name = date('d');
|
||||
}
|
||||
|
||||
return $path . DIRECTORY_SEPARATOR . $name . '.log';
|
||||
return $path . DIRECTORY_SEPARATOR . $name . '_' . $type . $cli . '.log';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,14 +212,14 @@ class File
|
||||
protected function parseCliLog($info)
|
||||
{
|
||||
if ($this->config['json']) {
|
||||
$message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n";
|
||||
$message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
|
||||
} else {
|
||||
$now = $info['timestamp'];
|
||||
unset($info['timestamp']);
|
||||
|
||||
$message = implode("\r\n", $info);
|
||||
$message = implode(PHP_EOL, $info);
|
||||
|
||||
$message = "[{$now}]" . $message . "\r\n";
|
||||
$message = "[{$now}]" . $message . PHP_EOL;
|
||||
}
|
||||
|
||||
return $message;
|
||||
@ -238,13 +242,13 @@ class File
|
||||
|
||||
if ($this->config['json']) {
|
||||
$info = $requestInfo + $info;
|
||||
return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n";
|
||||
return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
|
||||
}
|
||||
|
||||
array_unshift($info, "---------------------------------------------------------------\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}");
|
||||
array_unshift($info, "---------------------------------------------------------------" . PHP_EOL . "\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}");
|
||||
unset($info['timestamp']);
|
||||
|
||||
return implode("\r\n", $info) . "\r\n";
|
||||
return implode(PHP_EOL, $info) . PHP_EOL;
|
||||
}
|
||||
|
||||
protected function getDebugLog(&$info, $append, $apart)
|
||||
|
||||
@ -24,8 +24,10 @@ class Collection extends BaseCollection
|
||||
*/
|
||||
public function load($relation)
|
||||
{
|
||||
$item = current($this->items);
|
||||
$item->eagerlyResultSet($this->items, $relation);
|
||||
if (!$this->isEmpty()) {
|
||||
$item = current($this->items);
|
||||
$item->eagerlyResultSet($this->items, $relation);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -58,6 +58,16 @@ abstract class Relation
|
||||
return $this->query->getModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的关联模型类的实例
|
||||
* @access public
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前关联为自关联
|
||||
* @access public
|
||||
@ -129,6 +139,17 @@ abstract class Relation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
* @access public
|
||||
* @param array $data 更新数据
|
||||
* @return integer|string
|
||||
*/
|
||||
public function update(array $data = [])
|
||||
{
|
||||
return $this->query->update($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
* @access public
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
namespace think\model\concern;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use think\db\Expression;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\model\Relation;
|
||||
@ -326,9 +327,13 @@ trait Attribute
|
||||
$method = 'set' . Loader::parseName($name, 1) . 'Attr';
|
||||
|
||||
if (method_exists($this, $method)) {
|
||||
$value = $this->$method($value, array_merge($this->data, $data));
|
||||
$origin = $this->data;
|
||||
$value = $this->$method($value, array_merge($this->data, $data));
|
||||
|
||||
$this->set[$name] = true;
|
||||
if (is_null($value) && $origin !== $this->data) {
|
||||
return;
|
||||
}
|
||||
} elseif (isset($this->type[$name])) {
|
||||
// 类型转换
|
||||
$value = $this->writeTransform($value, $this->type[$name]);
|
||||
@ -370,9 +375,7 @@ trait Attribute
|
||||
switch ($type) {
|
||||
case 'datetime':
|
||||
case 'date':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$format .= strpos($format, 'u') || false !== strpos($format, '\\') ? '' : '.u';
|
||||
$value = $this->formatDateTime($format);
|
||||
$value = $this->formatDateTime('Y-m-d H:i:s.u');
|
||||
break;
|
||||
case 'timestamp':
|
||||
case 'integer':
|
||||
@ -385,8 +388,7 @@ trait Attribute
|
||||
'date',
|
||||
'timestamp',
|
||||
])) {
|
||||
$format = strpos($this->dateFormat, 'u') || false !== strpos($this->dateFormat, '\\') ? '' : '.u';
|
||||
$value = $this->formatDateTime($this->dateFormat . $format);
|
||||
$value = $this->formatDateTime('Y-m-d H:i:s.u');
|
||||
} else {
|
||||
$value = time();
|
||||
}
|
||||
@ -407,6 +409,10 @@ trait Attribute
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value instanceof Expression) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (is_array($type)) {
|
||||
list($type, $param) = $type;
|
||||
} elseif (strpos($type, ':')) {
|
||||
@ -433,9 +439,8 @@ trait Attribute
|
||||
}
|
||||
break;
|
||||
case 'datetime':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = is_numeric($value) ? $value : strtotime($value);
|
||||
$value = $this->formatDateTime($format, $value);
|
||||
$value = is_numeric($value) ? $value : strtotime($value);
|
||||
$value = $this->formatDateTime('Y-m-d H:i:s.u', $value);
|
||||
break;
|
||||
case 'object':
|
||||
if (is_object($value)) {
|
||||
|
||||
@ -130,34 +130,52 @@ trait Conversion
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$item = [];
|
||||
$visible = [];
|
||||
$hidden = [];
|
||||
$item = [];
|
||||
$hasVisible = false;
|
||||
|
||||
foreach ($this->visible as $key => $val) {
|
||||
if (is_string($val)) {
|
||||
if (strpos($val, '.')) {
|
||||
list($relation, $name) = explode('.', $val);
|
||||
$this->visible[$relation][] = $name;
|
||||
} else {
|
||||
$this->visible[$val] = true;
|
||||
$hasVisible = true;
|
||||
}
|
||||
unset($this->visible[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->hidden as $key => $val) {
|
||||
if (is_string($val)) {
|
||||
if (strpos($val, '.')) {
|
||||
list($relation, $name) = explode('.', $val);
|
||||
$this->hidden[$relation][] = $name;
|
||||
} else {
|
||||
$this->hidden[$val] = true;
|
||||
}
|
||||
unset($this->hidden[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// 合并关联数据
|
||||
$data = array_merge($this->data, $this->relation);
|
||||
|
||||
// 过滤属性
|
||||
if (!empty($this->visible)) {
|
||||
$array = $this->parseAttr($this->visible, $visible);
|
||||
$data = array_intersect_key($data, array_flip($array));
|
||||
} elseif (!empty($this->hidden)) {
|
||||
$array = $this->parseAttr($this->hidden, $hidden, false);
|
||||
$data = array_diff_key($data, array_flip($array));
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if ($val instanceof Model || $val instanceof ModelCollection) {
|
||||
// 关联模型对象
|
||||
if (isset($visible[$key])) {
|
||||
$val->visible($visible[$key]);
|
||||
} elseif (isset($hidden[$key])) {
|
||||
$val->hidden($hidden[$key]);
|
||||
if (isset($this->visible[$key]) && is_array($this->visible[$key])) {
|
||||
$val->visible($this->visible[$key]);
|
||||
} elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {
|
||||
$val->hidden($this->hidden[$key]);
|
||||
}
|
||||
// 关联模型对象
|
||||
$item[$key] = $val->toArray();
|
||||
} else {
|
||||
// 模型属性
|
||||
if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) {
|
||||
$item[$key] = $val->toArray();
|
||||
}
|
||||
} elseif (isset($this->visible[$key])) {
|
||||
$item[$key] = $this->getAttr($key);
|
||||
} elseif (!isset($this->hidden[$key]) && !$hasVisible) {
|
||||
$item[$key] = $this->getAttr($key);
|
||||
}
|
||||
}
|
||||
@ -171,10 +189,12 @@ trait Conversion
|
||||
|
||||
if (!$relation) {
|
||||
$relation = $this->getAttr($key);
|
||||
$relation->visible($name);
|
||||
if ($relation) {
|
||||
$relation->visible($name);
|
||||
}
|
||||
}
|
||||
|
||||
$item[$key] = $relation->append($name)->toArray();
|
||||
$item[$key] = $relation ? $relation->append($name)->toArray() : [];
|
||||
} elseif (strpos($name, '.')) {
|
||||
list($key, $attr) = explode('.', $name);
|
||||
// 追加关联对象属性
|
||||
@ -182,15 +202,14 @@ trait Conversion
|
||||
|
||||
if (!$relation) {
|
||||
$relation = $this->getAttr($key);
|
||||
$relation->visible([$attr]);
|
||||
if ($relation) {
|
||||
$relation->visible([$attr]);
|
||||
}
|
||||
}
|
||||
|
||||
$item[$key] = $relation->append([$attr])->toArray();
|
||||
$item[$key] = $relation ? $relation->append([$attr])->toArray() : [];
|
||||
} else {
|
||||
$value = $this->getAttr($name, $item);
|
||||
if (false !== $value) {
|
||||
$item[$name] = $value;
|
||||
}
|
||||
$item[$name] = $this->getAttr($name, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,38 +270,4 @@ trait Conversion
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析隐藏及显示属性
|
||||
* @access protected
|
||||
* @param array $attrs 属性
|
||||
* @param array $result 结果集
|
||||
* @param bool $visible
|
||||
* @return array
|
||||
*/
|
||||
protected function parseAttr($attrs, &$result, $visible = true)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
foreach ($attrs as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
if ($visible) {
|
||||
$array[] = $key;
|
||||
}
|
||||
|
||||
$result[$key] = $val;
|
||||
} elseif (strpos($val, '.')) {
|
||||
list($key, $name) = explode('.', $val);
|
||||
|
||||
if ($visible) {
|
||||
$array[] = $key;
|
||||
}
|
||||
|
||||
$result[$key][] = $name;
|
||||
} else {
|
||||
$array[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ trait RelationShip
|
||||
$relationResult = $this->$method();
|
||||
|
||||
if (isset($withRelationAttr[$relationName])) {
|
||||
$relationResult->withAttr($withRelationAttr[$relationName]);
|
||||
$relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
|
||||
}
|
||||
|
||||
$this->relation[$relation] = $relationResult->getRelation($subRelation, $closure);
|
||||
@ -248,7 +248,7 @@ trait RelationShip
|
||||
$relationResult = $this->$relation();
|
||||
|
||||
if (isset($withRelationAttr[$relationName])) {
|
||||
$relationResult->withAttr($withRelationAttr[$relationName]);
|
||||
$relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
|
||||
}
|
||||
|
||||
$relationResult->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $join);
|
||||
@ -290,7 +290,7 @@ trait RelationShip
|
||||
$relationResult = $this->$relation();
|
||||
|
||||
if (isset($withRelationAttr[$relationName])) {
|
||||
$relationResult->withAttr($withRelationAttr[$relationName]);
|
||||
$relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
|
||||
}
|
||||
|
||||
$relationResult->eagerlyResult($result, $relation, $subRelation, $closure, $join);
|
||||
|
||||
@ -235,7 +235,8 @@ trait SoftDelete
|
||||
$field = $this->getDeleteTimeField(true);
|
||||
|
||||
if ($field) {
|
||||
$query->useSoftDelete($field, $this->defaultSoftDelete);
|
||||
$condition = is_null($this->defaultSoftDelete) ? ['null', ''] : ['=', $this->defaultSoftDelete];
|
||||
$query->useSoftDelete($field, $condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
|
||||
@ -49,7 +50,7 @@ class BelongsTo extends OneToOne
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -79,7 +80,7 @@ class BelongsTo extends OneToOne
|
||||
*/
|
||||
public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '')
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -111,7 +112,7 @@ class BelongsTo extends OneToOne
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -140,13 +141,17 @@ class BelongsTo extends OneToOne
|
||||
$relation = basename(str_replace('\\', '/', $this->model));
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) {
|
||||
$query->table([$table => $relation])
|
||||
->field($relation . '.' . $localKey)
|
||||
->whereExp($model . '.' . $foreignKey, '=' . $relation . '.' . $localKey);
|
||||
->whereExp($model . '.' . $foreignKey, '=' . $relation . '.' . $localKey)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -167,12 +172,16 @@ class BelongsTo extends OneToOne
|
||||
$this->getQueryWhere($where, $relation);
|
||||
}
|
||||
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->field($fields)
|
||||
->join([$table => $relation], $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->where($where);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\Collection;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
@ -166,7 +167,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -377,7 +378,7 @@ class BelongsToMany extends Relation
|
||||
|
||||
$pk = $result->$pk;
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -401,7 +402,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '')
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -428,7 +429,7 @@ class BelongsToMany extends Relation
|
||||
protected function eagerlyManyToMany($where, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -561,6 +562,7 @@ class BelongsToMany extends Relation
|
||||
$pivot[$this->foreignKey] = $id;
|
||||
$this->pivot->replace()
|
||||
->exists(false)
|
||||
->data([])
|
||||
->save($pivot);
|
||||
$result[] = $this->newPivot($pivot, true);
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
@ -48,7 +49,7 @@ class HasMany extends Relation
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -163,7 +164,7 @@ class HasMany extends Relation
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
if ($return && is_string($return)) {
|
||||
$name = $return;
|
||||
@ -186,7 +187,7 @@ class HasMany extends Relation
|
||||
*/
|
||||
public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '')
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -194,8 +195,8 @@ class HasMany extends Relation
|
||||
}
|
||||
}
|
||||
|
||||
return $this->query
|
||||
->whereExp($this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey)
|
||||
return $this->query->alias($aggregate . '_table')
|
||||
->whereExp($aggregate . '_table.' . $this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey)
|
||||
->fetchSql()
|
||||
->$aggregate($field);
|
||||
}
|
||||
@ -216,7 +217,7 @@ class HasMany extends Relation
|
||||
$this->query->removeWhereField($this->foreignKey);
|
||||
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -266,11 +267,11 @@ class HasMany extends Relation
|
||||
/**
|
||||
* 批量保存当前关联数据对象
|
||||
* @access public
|
||||
* @param array $dataSet 数据集
|
||||
* @param array|\think\Collection $dataSet 数据集
|
||||
* @param boolean $replace 是否自动识别更新和写入
|
||||
* @return array|false
|
||||
*/
|
||||
public function saveAll(array $dataSet, $replace = true)
|
||||
public function saveAll($dataSet, $replace = true)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
@ -292,14 +293,18 @@ class HasMany extends Relation
|
||||
*/
|
||||
public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
|
||||
{
|
||||
$table = $this->query->getTable();
|
||||
$model = basename(str_replace('\\', '/', get_class($this->parent)));
|
||||
$relation = basename(str_replace('\\', '/', $this->model));
|
||||
$table = $this->query->getTable();
|
||||
$model = basename(str_replace('\\', '/', get_class($this->parent)));
|
||||
$relation = basename(str_replace('\\', '/', $this->model));
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->field($model . '.*')
|
||||
->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->group($relation . '.' . $this->foreignKey)
|
||||
->having('count(' . $id . ')' . $operator . $count);
|
||||
}
|
||||
@ -321,13 +326,17 @@ class HasMany extends Relation
|
||||
$this->getQueryWhere($where, $relation);
|
||||
}
|
||||
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->group($model . '.' . $this->localKey)
|
||||
->field($fields)
|
||||
->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->where($where);
|
||||
}
|
||||
|
||||
|
||||
@ -11,8 +11,8 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\model\Relation;
|
||||
@ -24,6 +24,12 @@ class HasManyThrough extends Relation
|
||||
// 中间表模型
|
||||
protected $through;
|
||||
|
||||
/**
|
||||
* 中间主键
|
||||
* @var string
|
||||
*/
|
||||
protected $throughPk;
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
@ -38,9 +44,10 @@ class HasManyThrough extends Relation
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
$this->through = $through;
|
||||
$this->through = (new $through)->db();
|
||||
$this->foreignKey = $foreignKey;
|
||||
$this->throughKey = $throughKey;
|
||||
$this->throughPk = $this->through->getPk();
|
||||
$this->localKey = $localKey;
|
||||
$this->query = (new $model)->db();
|
||||
}
|
||||
@ -54,7 +61,7 @@ class HasManyThrough extends Relation
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -74,7 +81,28 @@ class HasManyThrough extends Relation
|
||||
*/
|
||||
public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
|
||||
{
|
||||
return $this->parent;
|
||||
$model = App::parseName(App::classBaseName($this->parent));
|
||||
$throughTable = $this->through->getTable();
|
||||
$pk = $this->throughPk;
|
||||
$throughKey = $this->throughKey;
|
||||
$relation = (new $this->model)->db();
|
||||
$relationTable = $relation->getTable();
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
if ('*' != $id) {
|
||||
$id = $relationTable . '.' . $relation->getPk();
|
||||
}
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->field($model . '.*')
|
||||
->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey)
|
||||
->join($relationTable, $relationTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relationTable) {
|
||||
$query->where($relationTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->group($relationTable . '.' . $this->throughKey)
|
||||
->having('count(' . $id . ')' . $operator . $count);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,45 +114,225 @@ class HasManyThrough extends Relation
|
||||
*/
|
||||
public function hasWhere($where = [], $fields = null)
|
||||
{
|
||||
throw new Exception('relation not support: hasWhere');
|
||||
$model = App::parseName(App::classBaseName($this->parent));
|
||||
$throughTable = $this->through->getTable();
|
||||
$pk = $this->throughPk;
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = (new $this->model)->db()->getTable();
|
||||
|
||||
if (is_array($where)) {
|
||||
$this->getQueryWhere($where, $modelTable);
|
||||
}
|
||||
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey)
|
||||
->join($modelTable, $modelTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk)
|
||||
->when($softDelete, function ($query) use ($softDelete, $modelTable) {
|
||||
$query->where($modelTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->group($modelTable . '.' . $this->throughKey)
|
||||
->where($where)
|
||||
->field($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* 预载入关联查询(数据集)
|
||||
* @access protected
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param mixed $subRelation 子关联名
|
||||
* @param Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
|
||||
{}
|
||||
public function eagerlyResultSet(array &$resultSet, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$localKey)) {
|
||||
$range[] = $result->$localKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$this->query->removeWhereField($foreignKey);
|
||||
|
||||
$data = $this->eagerlyWhere([
|
||||
[$this->foreignKey, 'in', $range],
|
||||
], $foreignKey, $relation, $subRelation, $closure);
|
||||
|
||||
// 关联属性名
|
||||
$attr = App::parseName($relation);
|
||||
|
||||
// 关联数据封装
|
||||
foreach ($resultSet as $result) {
|
||||
$pk = $result->$localKey;
|
||||
if (!isset($data[$pk])) {
|
||||
$data[$pk] = [];
|
||||
}
|
||||
|
||||
foreach ($data[$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
// 设置关联属性
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$pk]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询 返回模型对象
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* 预载入关联查询(数据)
|
||||
* @access protected
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param mixed $subRelation 子关联名
|
||||
* @param Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure)
|
||||
{}
|
||||
public function eagerlyResult($result, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$pk = $result->$localKey;
|
||||
|
||||
$this->query->removeWhereField($foreignKey);
|
||||
|
||||
$data = $this->eagerlyWhere([
|
||||
[$foreignKey, '=', $pk],
|
||||
], $foreignKey, $relation, $subRelation, $closure);
|
||||
|
||||
// 关联数据封装
|
||||
if (!isset($data[$pk])) {
|
||||
$data[$pk] = [];
|
||||
}
|
||||
|
||||
foreach ($data[$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
$result->setRelation(App::parseName($relation), $this->resultSetBuild($data[$pk]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联模型预查询
|
||||
* @access public
|
||||
* @param array $where 关联预查询条件
|
||||
* @param string $key 关联键名
|
||||
* @param string $relation 关联名
|
||||
* @param mixed $subRelation 子关联
|
||||
* @param Closure $closure
|
||||
* @return array
|
||||
*/
|
||||
protected function eagerlyWhere(array $where, $key, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
$throughList = $this->through->where($where)->select();
|
||||
$keys = $throughList->column($this->throughPk, $this->throughPk);
|
||||
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
$list = $this->query->where($this->throughKey, 'in', $keys)->select();
|
||||
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
$keys = $throughList->column($this->foreignKey, $this->throughPk);
|
||||
|
||||
foreach ($list as $set) {
|
||||
$data[$keys[$set->{$this->throughKey}]][] = $set;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param \Closure $closure 闭包
|
||||
* @param string $aggregate 聚合查询方法
|
||||
* @param string $field 字段
|
||||
* @param string $name 统计字段别名
|
||||
* @param Model $result 数据对象
|
||||
* @param Closure $closure 闭包
|
||||
* @param string $aggregate 聚合查询方法
|
||||
* @param string $field 字段
|
||||
* @param string $name 统计字段别名
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '')
|
||||
{}
|
||||
public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = null)
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
|
||||
if (!isset($result->$localKey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
if ($return && is_string($return)) {
|
||||
$name = $return;
|
||||
}
|
||||
}
|
||||
|
||||
$alias = App::parseName(App::classBaseName($this->model));
|
||||
$throughTable = $this->through->getTable();
|
||||
$pk = $this->throughPk;
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = $this->parent->getTable();
|
||||
|
||||
if (false === strpos($field, '.')) {
|
||||
$field = $alias . '.' . $field;
|
||||
}
|
||||
|
||||
return $this->query
|
||||
->alias($alias)
|
||||
->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)
|
||||
->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)
|
||||
->where($throughTable . '.' . $this->foreignKey, $result->$localKey)
|
||||
->$aggregate($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建关联统计子查询
|
||||
* @access public
|
||||
* @param Closure $closure 闭包
|
||||
* @param string $aggregate 聚合查询方法
|
||||
* @param string $field 字段
|
||||
* @param string $name 统计字段别名
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationCountQuery($closure = null, $aggregate = 'count', $field = '*', &$name = null)
|
||||
{
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
if ($return && is_string($return)) {
|
||||
$name = $return;
|
||||
}
|
||||
}
|
||||
|
||||
$alias = App::parseName(App::classBaseName($this->model));
|
||||
$throughTable = $this->through->getTable();
|
||||
$pk = $this->throughPk;
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = $this->parent->getTable();
|
||||
|
||||
if (false === strpos($field, '.')) {
|
||||
$field = $alias . '.' . $field;
|
||||
}
|
||||
|
||||
return $this->query
|
||||
->alias($alias)
|
||||
->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)
|
||||
->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)
|
||||
->whereExp($throughTable . '.' . $this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey)
|
||||
->fetchSql()
|
||||
->$aggregate($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行基础查询(仅执行一次)
|
||||
@ -134,10 +342,9 @@ class HasManyThrough extends Relation
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$through = $this->through;
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $this->model)));
|
||||
$throughTable = $through::getTable();
|
||||
$pk = (new $through)->getPk();
|
||||
$throughTable = $this->through->getTable();
|
||||
$pk = $this->throughPk;
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = $this->parent->getTable();
|
||||
$fields = $this->getQueryFields($alias);
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
@ -50,7 +51,7 @@ class HasOne extends OneToOne
|
||||
{
|
||||
$localKey = $this->localKey;
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -79,7 +80,7 @@ class HasOne extends OneToOne
|
||||
*/
|
||||
public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '')
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -111,7 +112,7 @@ class HasOne extends OneToOne
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
if ($return && is_string($return)) {
|
||||
$name = $return;
|
||||
@ -139,13 +140,17 @@ class HasOne extends OneToOne
|
||||
$relation = basename(str_replace('\\', '/', $this->model));
|
||||
$localKey = $this->localKey;
|
||||
$foreignKey = $this->foreignKey;
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) {
|
||||
$query->table([$table => $relation])
|
||||
->field($relation . '.' . $foreignKey)
|
||||
->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey);
|
||||
->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -166,12 +171,16 @@ class HasOne extends OneToOne
|
||||
$this->getQueryWhere($where, $relation);
|
||||
}
|
||||
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$fields = $this->getRelationQueryFields($fields, $model);
|
||||
$softDelete = $this->query->getOptions('soft_delete');
|
||||
|
||||
return $this->parent->db()
|
||||
->alias($model)
|
||||
->field($fields)
|
||||
->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType)
|
||||
->when($softDelete, function ($query) use ($softDelete, $relation) {
|
||||
$query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
|
||||
})
|
||||
->where($where);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@ -53,7 +54,7 @@ class MorphMany extends Relation
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -197,7 +198,7 @@ class MorphMany extends Relation
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -224,7 +225,7 @@ class MorphMany extends Relation
|
||||
*/
|
||||
public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '')
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$return = $closure($this->query);
|
||||
|
||||
if ($return && is_string($return)) {
|
||||
@ -253,7 +254,7 @@ class MorphMany extends Relation
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
$this->query->removeOption('where');
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@ -53,7 +54,7 @@ class MorphOne extends Relation
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
@ -186,7 +187,7 @@ class MorphOne extends Relation
|
||||
protected function eagerlyMorphToOne($where, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use Closure;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@ -87,7 +88,7 @@ abstract class OneToOne extends Relation
|
||||
$joinOn = $name . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey;
|
||||
}
|
||||
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
// 执行闭包查询
|
||||
$closure($query);
|
||||
// 使用withField指定获取关联的字段,如
|
||||
@ -311,7 +312,7 @@ abstract class OneToOne extends Relation
|
||||
protected function eagerlyWhere($where, $key, $relation, $subRelation = '', $closure = null)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
if ($closure instanceof Closure) {
|
||||
$closure($this->query);
|
||||
|
||||
if ($field = $this->query->getOptions('with_field')) {
|
||||
|
||||
@ -20,7 +20,7 @@ class Download extends Response
|
||||
protected $name;
|
||||
protected $mimeType;
|
||||
protected $isContent = false;
|
||||
protected $openinBrower = false;
|
||||
protected $openinBrowser = false;
|
||||
/**
|
||||
* 处理数据
|
||||
* @access protected
|
||||
@ -53,7 +53,7 @@ class Download extends Response
|
||||
$this->header['Pragma'] = 'public';
|
||||
$this->header['Content-Type'] = $mimeType ?: 'application/octet-stream';
|
||||
$this->header['Cache-control'] = 'max-age=' . $this->expire;
|
||||
$this->header['Content-Disposition'] = $this->openinBrower ? 'inline' : 'attachment; filename="' . $name . '"';
|
||||
$this->header['Content-Disposition'] = $this->openinBrowser ? 'inline' : 'attachment; filename="' . $name . '"';
|
||||
$this->header['Content-Length'] = $size;
|
||||
$this->header['Content-Transfer-Encoding'] = 'binary';
|
||||
$this->header['Expires'] = gmdate("D, d M Y H:i:s", time() + $this->expire) . ' GMT';
|
||||
@ -138,11 +138,11 @@ class Download extends Response
|
||||
/**
|
||||
* 设置是否在浏览器中显示文件
|
||||
* @access public
|
||||
* @param bool $openinBrower 是否在浏览器中显示文件
|
||||
* @param bool $openinBrowser 是否在浏览器中显示文件
|
||||
* @return $this
|
||||
*/
|
||||
public function openinBrower($openinBrower) {
|
||||
$this->openinBrower = $openinBrower;
|
||||
public function openinBrowser($openinBrowser) {
|
||||
$this->openinBrowser = $openinBrowser;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,11 +87,12 @@ class Redirect extends Response
|
||||
/**
|
||||
* 记住当前url后跳转
|
||||
* @access public
|
||||
* @param string $url 指定记住的url
|
||||
* @return $this
|
||||
*/
|
||||
public function remember()
|
||||
public function remember($url = null)
|
||||
{
|
||||
$this->app['session']->set('redirect_url', $this->app['request']->url());
|
||||
$this->app['session']->set('redirect_url', $url ?: $this->app['request']->url());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -18,9 +18,16 @@ class View extends Response
|
||||
// 输出参数
|
||||
protected $options = [];
|
||||
protected $vars = [];
|
||||
protected $config = [];
|
||||
protected $filter;
|
||||
protected $contentType = 'text/html';
|
||||
|
||||
/**
|
||||
* 是否内容渲染
|
||||
* @var bool
|
||||
*/
|
||||
protected $isContent = false;
|
||||
|
||||
/**
|
||||
* 处理数据
|
||||
* @access protected
|
||||
@ -32,7 +39,19 @@ class View extends Response
|
||||
// 渲染模板输出
|
||||
return $this->app['view']
|
||||
->filter($this->filter)
|
||||
->fetch($data, $this->vars);
|
||||
->fetch($data, $this->vars, $this->config, $this->isContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否为内容渲染
|
||||
* @access public
|
||||
* @param bool $content
|
||||
* @return $this
|
||||
*/
|
||||
public function isContent($content = true)
|
||||
{
|
||||
$this->isContent = $content;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,6 +87,12 @@ class View extends Response
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function config($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图内容过滤
|
||||
* @access public
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
|
||||
namespace think\route;
|
||||
|
||||
use think\App;
|
||||
use think\Container;
|
||||
use think\exception\ValidateException;
|
||||
use think\App;
|
||||
use think\Request;
|
||||
use think\Response;
|
||||
|
||||
@ -181,9 +181,10 @@ abstract class Dispatch
|
||||
|
||||
$response = Response::create($data, $type);
|
||||
} else {
|
||||
$data = ob_get_clean();
|
||||
$content = false === $data ? '' : $data;
|
||||
$status = '' === $content && $this->request->isAjax() ? 204 : 200;
|
||||
$data = ob_get_clean();
|
||||
$content = false === $data ? '' : $data;
|
||||
$status = '' === $content && $this->request->isJson() ? 204 : 200;
|
||||
|
||||
$response = Response::create($content, '', $status);
|
||||
}
|
||||
|
||||
|
||||
@ -642,17 +642,26 @@ abstract class Rule
|
||||
protected function checkCrossDomain($request)
|
||||
{
|
||||
if (!empty($this->option['cross_domain'])) {
|
||||
|
||||
$header = [
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE',
|
||||
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE',
|
||||
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With',
|
||||
];
|
||||
|
||||
if (!empty($this->option['header'])) {
|
||||
$header = array_merge($header, $this->option['header']);
|
||||
}
|
||||
|
||||
if (!isset($header['Access-Control-Allow-Origin'])) {
|
||||
$httpOrigin = $request->header('origin');
|
||||
|
||||
if ($httpOrigin && strpos(config('cookie.domain'), $httpOrigin)) {
|
||||
$header['Access-Control-Allow-Origin'] = $httpOrigin;
|
||||
} else {
|
||||
$header['Access-Control-Allow-Origin'] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
$this->option['header'] = $header;
|
||||
|
||||
if ($request->method(true) == 'OPTIONS') {
|
||||
@ -1001,7 +1010,7 @@ abstract class Rule
|
||||
}
|
||||
}
|
||||
|
||||
$regex = str_replace($match, $replace, $rule);
|
||||
$regex = str_replace(array_unique($match), array_unique($replace), $rule);
|
||||
$regex = str_replace([')?/', ')/', ')?-', ')-', '\\\\/'], [')\/', ')\/', ')\-', ')\-', '\/'], $regex);
|
||||
|
||||
if (isset($hasSlash)) {
|
||||
|
||||
@ -118,8 +118,8 @@ class RuleGroup extends Rule
|
||||
*/
|
||||
public function check($request, $url, $completeMatch = false)
|
||||
{
|
||||
// 跨域OPTIONS请求
|
||||
if ($dispatch = $this->checkCrossDomain($request)) {
|
||||
// 跨域OPTIONS请求
|
||||
return $dispatch;
|
||||
}
|
||||
|
||||
@ -151,10 +151,6 @@ class RuleGroup extends Rule
|
||||
$method = strtolower($request->method());
|
||||
$rules = $this->getMethodRules($method);
|
||||
|
||||
if (count($rules) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->parent) {
|
||||
// 合并分组参数
|
||||
$this->mergeGroupOptions();
|
||||
|
||||
@ -149,11 +149,6 @@ class RuleItem extends Rule
|
||||
*/
|
||||
public function checkRule($request, $url, $match = null, $completeMatch = false)
|
||||
{
|
||||
if ($dispatch = $this->checkCrossDomain($request)) {
|
||||
// 允许跨域
|
||||
return $dispatch;
|
||||
}
|
||||
|
||||
// 检查参数有效性
|
||||
if (!$this->checkOption($this->option, $request)) {
|
||||
return false;
|
||||
@ -169,6 +164,15 @@ class RuleItem extends Rule
|
||||
}
|
||||
|
||||
if (false !== $match) {
|
||||
if (!empty($option['cross_domain'])) {
|
||||
if ($dispatch = $this->checkCrossDomain($request)) {
|
||||
// 允许跨域
|
||||
return $dispatch;
|
||||
}
|
||||
|
||||
$option['header'] = $this->option['header'];
|
||||
}
|
||||
|
||||
// 检查前置行为
|
||||
if (isset($option['before']) && false === $this->checkBefore($option['before'])) {
|
||||
return false;
|
||||
|
||||
@ -12,7 +12,6 @@
|
||||
namespace think\route\dispatch;
|
||||
|
||||
use ReflectionMethod;
|
||||
use think\Controller;
|
||||
use think\exception\ClassNotFoundException;
|
||||
use think\exception\HttpException;
|
||||
use think\Loader;
|
||||
|
||||
@ -124,7 +124,7 @@ class Redis implements SessionHandlerInterface
|
||||
*/
|
||||
public function destroy($sessID)
|
||||
{
|
||||
return $this->handler->delete($this->config['session_name'] . $sessID) > 0;
|
||||
return $this->handler->del($this->config['session_name'] . $sessID) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -280,9 +280,6 @@
|
||||
pre.prettyprint .atv { color: #080 } /* a markup attribute value */
|
||||
pre.prettyprint .dec, pre.prettyprint .var { color: #606 } /* a declaration; a variable name */
|
||||
pre.prettyprint .fun { color: red } /* a function name */
|
||||
|
||||
/* bbs */
|
||||
.bbs-ask { margin-left: 15px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -413,10 +410,9 @@
|
||||
<?php } ?>
|
||||
|
||||
<div class="copyright">
|
||||
<a title="<?php echo implode('', ['S','h','o','p','X','O']); ?>官网" href="<?php echo implode('', ['h','t','t','p',':','/','/','w','w','w','.','s','h','o','p','x','o','.','n','e','t']); ?>"target="_blank"><?php echo implode('', ['S','h','o','p','X','O']); ?>官网</a>
|
||||
<span><?php echo APPLICATION_VERSION; ?></span>
|
||||
<a title="<?php echo implode('', ['S','h','o','p','X','O']); ?>社区" href="<?php echo implode('', ['h','t','t','p',':','/','/','a','s','k','.','s','h','o','p','x','o','.','n','e','t']); ?>" target="_blank" class="bbs-ask"><?php echo implode('', ['S','h','o','p','X','O']); ?>社区</a>
|
||||
<span>{ 国内领先企业级B2C免费开源电商系统! }</span>
|
||||
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
|
||||
<span>V<?php echo \think\facade\App::version(); ?></span>
|
||||
<span>{ 十年磨一剑-为API开发设计的高性能框架 }</span>
|
||||
</div>
|
||||
<?php if(\think\facade\App::isDebug()) { ?>
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user