diff --git a/application/common/model/Document.php b/application/common/model/Document.php index 6b6767bf..449ae7ee 100644 --- a/application/common/model/Document.php +++ b/application/common/model/Document.php @@ -15,7 +15,7 @@ namespace app\common\model; class Document extends \think\model\Merge{ protected $fk = 'doc_id'; - //protected static $relationModel = array('document_article'); + protected $relationModel = array('document_article'); // 定义需要自动写入时间戳格式的字段 protected $autoWriteTimestamp = array('create_time','update_time','deadline'); diff --git a/application/index/controller/Content.php b/application/index/controller/Content.php index fa777e01..196da0c0 100644 --- a/application/index/controller/Content.php +++ b/application/index/controller/Content.php @@ -125,7 +125,6 @@ class Content extends Fornt { //当为文章模型时 $info = $this->model->detail($id); - //文档模型数据统计,同一台电脑半小时更新一次 if ($this->modelInfo['extend'] = 1 && (time() - session('set_content_view')) > 1800) { db('Document')->where(array('id' => $id))->setInc('view'); session('set_content_view', time()); diff --git a/core/base.php b/core/base.php index 41afa489..1184dc51 100644 --- a/core/base.php +++ b/core/base.php @@ -19,7 +19,7 @@ define('LIB_PATH', THINK_PATH . 'library' . DS); define('CORE_PATH', LIB_PATH . 'think' . DS); define('TRAIT_PATH', LIB_PATH . 'traits' . DS); defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS); -defined('ROOT_PATH') or define('ROOT_PATH', dirname(APP_PATH) . DS); +defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS); defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS); defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS); defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS); diff --git a/core/library/think/Config.php b/core/library/think/Config.php index 5ab032fd..d7c3dc56 100644 --- a/core/library/think/Config.php +++ b/core/library/think/Config.php @@ -60,10 +60,12 @@ class Config } if (is_file($file)) { $type = pathinfo($file, PATHINFO_EXTENSION); - if ('php' != $type) { - return self::parse($file, $type, $name, $range); - } else { + if ('php' == $type) { return self::set(include $file, $name, $range); + } elseif ('yaml' == $type && function_exists('yaml_parse_file')) { + return self::set(yaml_parse_file($file), $name, $range); + } else { + return self::parse($file, $type, $name, $range); } } else { return self::$config[$range]; diff --git a/core/library/think/Route.php b/core/library/think/Route.php index c7c4a731..c18a2d67 100644 --- a/core/library/think/Route.php +++ b/core/library/think/Route.php @@ -1152,7 +1152,7 @@ class Route $module = Config::get('app_multi_module') ? array_shift($path) : null; if ($autoSearch) { // 自动搜索控制器 - $dir = APP_PATH . ($module ? $module . DS : '') . 'controller'; + $dir = APP_PATH . ($module ? $module . DS : '') . Config::get('url_controller_layer'); $suffix = App::$suffix || Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : ''; $item = []; foreach ($path as $val) { diff --git a/core/library/think/Validate.php b/core/library/think/Validate.php index 5fa15424..3c6e847a 100644 --- a/core/library/think/Validate.php +++ b/core/library/think/Validate.php @@ -12,6 +12,7 @@ namespace think; use think\File; +use think\Lang; use think\Request; use think\Session; @@ -376,6 +377,9 @@ class Validate // 验证失败 返回错误信息 if (isset($msg[$i])) { $message = $msg[$i]; + if (is_string($message) && strpos($message, '{%')) { + $message = Lang::get(substr($message, 2, -1)); + } } else { $message = $this->getRuleMsg($field, $title, $info, $rule); } @@ -1163,7 +1167,11 @@ class Validate } else { $msg = $title . '规则错误'; } - // TODO 多语言支持 + + if (is_string($msg) && strpos($msg, '{%')) { + $msg = Lang::get(substr($msg, 2, -1)); + } + if (is_string($msg) && false !== strpos($msg, ':')) { // 变量替换 if (strpos($rule, ',')) { diff --git a/core/library/think/db/Builder.php b/core/library/think/db/Builder.php index 15a240ad..f38e20bc 100644 --- a/core/library/think/db/Builder.php +++ b/core/library/think/db/Builder.php @@ -89,7 +89,7 @@ abstract class Builder $result = []; foreach ($data as $key => $val) { - $item = $this->parseKey($key); + $item = $this->parseKey($key, $options); if (!in_array($key, $fields, true)) { if ($options['strict']) { throw new Exception('fields not exists:[' . $key . ']'); @@ -115,9 +115,10 @@ abstract class Builder * 字段名分析 * @access protected * @param string $key + * @param array $options * @return string */ - protected function parseKey($key) + protected function parseKey($key, $options = []) { return $key; } @@ -146,10 +147,11 @@ abstract class Builder /** * field分析 * @access protected - * @param mixed $fields + * @param mixed $fields + * @param array $options * @return string */ - protected function parseField($fields) + protected function parseField($fields, $options = []) { if ('*' == $fields || empty($fields)) { $fieldsStr = '*'; @@ -158,9 +160,9 @@ abstract class Builder $array = []; foreach ($fields as $key => $field) { if (!is_numeric($key)) { - $array[] = $this->parseKey($key) . ' AS ' . $this->parseKey($field); + $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options); } else { - $array[] = $this->parseKey($field); + $array[] = $this->parseKey($field, $options); } } $fieldsStr = implode(',', $array); @@ -171,24 +173,22 @@ abstract class Builder /** * table分析 * @access protected - * @param mixed $table + * @param mixed $tables + * @param array $options * @return string */ - protected function parseTable($tables) + protected function parseTable($tables, $options = []) { - if (is_array($tables)) { - // 支持别名定义 - foreach ($tables as $table => $alias) { - $array[] = !is_numeric($table) ? - $this->parseKey($table) . ' ' . $this->parseKey($alias) : - $this->parseKey($alias); + $item = []; + foreach ((array) $tables as $table) { + $table = $this->parseSqlTable($table); + if (isset($options['alias'][$table])) { + $item[] = $this->parseKey($table) . ' ' . $this->parseKey($options['alias'][$table]); + } else { + $item[] = $this->parseKey($table); } - $tables = $array; - } elseif (is_string($tables)) { - $tables = $this->parseSqlTable($tables); - $tables = array_map([$this, 'parseKey'], explode(',', $tables)); } - return implode(',', $tables); + return implode(',', $item); } /** @@ -263,7 +263,7 @@ abstract class Builder protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null) { // 字段分析 - $key = $field ? $this->parseKey($field) : ''; + $key = $field ? $this->parseKey($field, $options) : ''; // 查询规则和条件 if (!is_array($val)) { @@ -425,14 +425,25 @@ abstract class Builder /** * join分析 * @access protected - * @param mixed $join + * @param array $join + * @param array $options 查询条件 * @return string */ - protected function parseJoin($join) + protected function parseJoin($join, $options = []) { $joinStr = ''; if (!empty($join)) { - $joinStr = ' ' . implode(' ', $join) . ' '; + foreach ($join as $item) { + list($table, $type, $on) = $item; + $condition = []; + foreach ((array) $on as $val) { + list($val1, $val2) = explode('=', $val, 2); + $condition[] = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options); + } + + $table = $this->parseTable($table, $options); + $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . implode(' AND ', $condition); + } } return $joinStr; } @@ -441,22 +452,23 @@ abstract class Builder * order分析 * @access protected * @param mixed $order + * @param array $options 查询条件 * @return string */ - protected function parseOrder($order) + protected function parseOrder($order, $options = []) { if (is_array($order)) { $array = []; foreach ($order as $key => $val) { if (is_numeric($key)) { if (false === strpos($val, '(')) { - $array[] = $this->parseKey($val); + $array[] = $this->parseKey($val, $options); } elseif ('[rand]' == $val) { $array[] = $this->parseRand(); } } else { $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; - $array[] = $this->parseKey($key) . ' ' . $sort; + $array[] = $this->parseKey($key, $options) . ' ' . $sort; } } $order = implode(',', $array); @@ -572,14 +584,14 @@ abstract class Builder $sql = str_replace( ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'], [ - $this->parseTable($options['table']), + $this->parseTable($options['table'], $options), $this->parseDistinct($options['distinct']), - $this->parseField($options['field']), - $this->parseJoin($options['join']), + $this->parseField($options['field'], $options), + $this->parseJoin($options['join'], $options), $this->parseWhere($options['where'], $options), $this->parseGroup($options['group']), $this->parseHaving($options['having']), - $this->parseOrder($options['order']), + $this->parseOrder($options['order'], $options), $this->parseLimit($options['limit']), $this->parseUnion($options['union']), $this->parseLock($options['lock']), @@ -611,7 +623,7 @@ abstract class Builder ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], [ $replace ? 'REPLACE' : 'INSERT', - $this->parseTable($options['table']), + $this->parseTable($options['table'], $options), implode(' , ', $fields), implode(' , ', $values), $this->parseComment($options['comment']), @@ -657,7 +669,7 @@ abstract class Builder $sql = str_replace( ['%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], [ - $this->parseTable($options['table']), + $this->parseTable($options['table'], $options), implode(' , ', $fields), implode(' UNION ALL ', $values), $this->parseComment($options['comment']), @@ -681,7 +693,7 @@ abstract class Builder } $fields = array_map([$this, 'parseKey'], $fields); - $sql = 'INSERT INTO ' . $this->parseTable($table) . ' (' . implode(',', $fields) . ') ' . $this->select($options); + $sql = 'INSERT INTO ' . $this->parseTable($table, $options) . ' (' . implode(',', $fields) . ') ' . $this->select($options); return $sql; } @@ -694,7 +706,7 @@ abstract class Builder */ public function update($data, $options) { - $table = $this->parseTable($options['table']); + $table = $this->parseTable($options['table'], $options); $data = $this->parseData($data, $options); if (empty($data)) { return ''; @@ -706,11 +718,11 @@ abstract class Builder $sql = str_replace( ['%TABLE%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], [ - $this->parseTable($options['table']), + $this->parseTable($options['table'], $options), implode(',', $set), - $this->parseJoin($options['join']), + $this->parseJoin($options['join'], $options), $this->parseWhere($options['where'], $options), - $this->parseOrder($options['order']), + $this->parseOrder($options['order'], $options), $this->parseLimit($options['limit']), $this->parseLock($options['lock']), $this->parseComment($options['comment']), @@ -730,11 +742,11 @@ abstract class Builder $sql = str_replace( ['%TABLE%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], [ - $this->parseTable($options['table']), - !empty($options['using']) ? ' USING ' . $this->parseTable($options['using']) . ' ' : '', - $this->parseJoin($options['join']), + $this->parseTable($options['table'], $options), + !empty($options['using']) ? ' USING ' . $this->parseTable($options['using'], $options) . ' ' : '', + $this->parseJoin($options['join'], $options), $this->parseWhere($options['where'], $options), - $this->parseOrder($options['order']), + $this->parseOrder($options['order'], $options), $this->parseLimit($options['limit']), $this->parseLock($options['lock']), $this->parseComment($options['comment']), diff --git a/core/library/think/db/Query.php b/core/library/think/db/Query.php index 2e9308cc..79933838 100644 --- a/core/library/think/db/Query.php +++ b/core/library/think/db/Query.php @@ -668,7 +668,9 @@ class Query if (is_array($join)) { if (0 !== $key = key($join)) { // 设置了键名则键名为表名,键值作为表的别名 - $table = $key . ' ' . array_shift($join); + $table = $key; + $alias = array_shift($join); + $this->alias([$table => $alias]); } else { $table = array_shift($join); } @@ -689,11 +691,12 @@ class Query } else { $table = $join; } + if (strpos($table, ' ')) { + list($table, $alias) = explode(' ', $table); + $this->alias([$table => $alias]); + } } - if (is_array($condition)) { - $condition = implode(' AND ', $condition); - } - $this->options['join'][] = strtoupper($type) . ' JOIN ' . $table . ' ON ' . $condition; + $this->options['join'][] = [$table, strtoupper($type), $condition]; } return $this; } @@ -1021,11 +1024,40 @@ class Query /** * 指定当前操作的数据表 * @access public - * @param string $table 表名 + * @param mixed $table 表名 * @return $this */ public function table($table) { + if (is_string($table)) { + if (strpos($table, ',')) { + $tables = explode(',', $table); + $table = []; + foreach ($tables as $item) { + list($item, $alias) = explode(' ', trim($item)); + if ($alias) { + $this->alias([$item => $alias]); + $table[$item] = $alias; + } else { + $table[] = $item; + } + } + } elseif (strpos($table, ' ')) { + list($table, $alias) = explode(' ', $table); + $this->alias([$table => $alias]); + } + } else { + $tables = $table; + $table = []; + foreach ($tables as $key => $val) { + if (is_numeric($key)) { + $table[] = $val; + } else { + $this->alias([$key => $val]); + $table[] = $key; + } + } + } $this->options['table'] = $table; return $this; } @@ -1145,12 +1177,20 @@ class Query /** * 指定数据表别名 * @access public - * @param string $alias 数据表别名 + * @param mixed $alias 数据表别名 * @return $this */ public function alias($alias) { - $this->options['alias'] = $alias; + if (is_array($alias)) { + foreach ($alias as $key => $val) { + $this->options['alias'][$key] = $val; + } + } else { + $table = isset($this->options['table']) ? $this->options['table'] : $this->getTable(); + + $this->options['alias'][$table] = $alias; + } return $this; } @@ -1630,8 +1670,8 @@ class Query { $pk = $this->getPk($options); // 获取当前数据表 - if (!empty($options['alias'])) { - $alias = $options['alias']; + if (!empty($options['alias'][$options['table']])) { + $alias = $options['alias'][$options['table']]; } if (is_string($pk)) { $key = isset($alias) ? $alias . '.' . $pk : $pk; @@ -2201,11 +2241,6 @@ class Query } } - // 表别名 - if (!empty($options['alias'])) { - $options['table'] .= ' ' . $options['alias']; - } - if (!isset($options['field'])) { $options['field'] = '*'; } diff --git a/core/library/think/db/builder/Mysql.php b/core/library/think/db/builder/Mysql.php index 04586906..a3e223ed 100644 --- a/core/library/think/db/builder/Mysql.php +++ b/core/library/think/db/builder/Mysql.php @@ -24,19 +24,28 @@ class Mysql extends Builder * 字段和表名处理 * @access protected * @param string $key + * @param array $options * @return string */ - protected function parseKey($key) + protected function parseKey($key, $options = []) { $key = trim($key); if (strpos($key, '$.') && false === strpos($key, '(')) { // JSON字段支持 list($field, $name) = explode('$.', $key); $key = 'json_extract(' . $field . ', \'$.' . $name . '\')'; + } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) { + list($table, $key) = explode('.', $key, 2); + if (isset($options['alias'][$table])) { + $table = $options['alias'][$table]; + } } if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) { $key = '`' . $key . '`'; } + if (isset($table)) { + $key = '`' . $table . '`.' . $key; + } return $key; } diff --git a/core/library/think/db/builder/Pgsql.php b/core/library/think/db/builder/Pgsql.php index 0a955a5b..e6e7dffa 100644 --- a/core/library/think/db/builder/Pgsql.php +++ b/core/library/think/db/builder/Pgsql.php @@ -43,15 +43,24 @@ class Pgsql extends Builder * 字段和表名处理 * @access protected * @param string $key + * @param array $options * @return string */ - protected function parseKey($key) + protected function parseKey($key, $options = []) { $key = trim($key); if (strpos($key, '$.') && false === strpos($key, '(')) { // JSON字段支持 list($field, $name) = explode('$.', $key); $key = $field . '->>\'' . $name . '\''; + } elseif (strpos($key, '.')) { + list($table, $key) = explode('.', $key, 2); + if (isset($options['alias'][$table])) { + $table = $options['alias'][$table]; + } + } + if (isset($table)) { + $key = $table . '.' . $key; } return $key; } diff --git a/core/library/think/db/builder/Sqlite.php b/core/library/think/db/builder/Sqlite.php index 17e59cb2..c9f55027 100644 --- a/core/library/think/db/builder/Sqlite.php +++ b/core/library/think/db/builder/Sqlite.php @@ -48,4 +48,25 @@ class Sqlite extends Builder return 'RANDOM()'; } + /** + * 字段和表名处理 + * @access protected + * @param string $key + * @param array $options + * @return string + */ + protected function parseKey($key, $options = []) + { + $key = trim($key); + if (strpos($key, '.')) { + list($table, $key) = explode('.', $key, 2); + if (isset($options['alias'][$table])) { + $table = $options['alias'][$table]; + } + } + if (isset($table)) { + $key = $table . '.' . $key; + } + return $key; + } } diff --git a/core/library/think/db/builder/Sqlsrv.php b/core/library/think/db/builder/Sqlsrv.php index bf630d90..c53f3848 100644 --- a/core/library/think/db/builder/Sqlsrv.php +++ b/core/library/think/db/builder/Sqlsrv.php @@ -61,17 +61,27 @@ class Sqlsrv extends Builder } /** - * 字段名分析 + * 字段和表名处理 * @access protected * @param string $key + * @param array $options * @return string */ - protected function parseKey($key) + protected function parseKey($key, $options = []) { $key = trim($key); + if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) { + list($table, $key) = explode('.', $key, 2); + if (isset($options['alias'][$table])) { + $table = $options['alias'][$table]; + } + } if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) { $key = '[' . $key . ']'; } + if (isset($table)) { + $key = '[' . $table . '].' . $key; + } return $key; } diff --git a/core/library/traits/model/SoftDelete.php b/core/library/traits/model/SoftDelete.php index e08d96aa..4bb072dc 100644 --- a/core/library/traits/model/SoftDelete.php +++ b/core/library/traits/model/SoftDelete.php @@ -133,10 +133,9 @@ trait SoftDelete */ protected function getDeleteTimeField($read = false) { - if (isset($this->deleteTime)) { - $field = $this->deleteTime; - } else { - $field = 'delete_time'; + $field = isset($this->deleteTime) ? $this->deleteTime : 'delete_time'; + if (!strpos($field, '.')) { + $field = $this->db(false)->getTable() . '.' . $field; } if (!$read && strpos($field, '.')) { list($alias, $field) = explode('.', $field);