diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
new file mode 100644
index 000000000..a3a6c1335
--- /dev/null
+++ b/.php-cs-fixer.php
@@ -0,0 +1,120 @@
+setRiskyAllowed(true)->setParallelConfig(new ParallelConfig(8, 24));
+$finder = Finder::create()->in(__DIR__)->exclude(['vendor', 'public', 'runtime']);
+return $config->setFinder($finder)->setUsingCache(false)->setRules([
+ '@PSR2' => true,
+ '@Symfony' => true,
+ '@DoctrineAnnotation' => true,
+ '@PhpCsFixer' => true,
+ 'header_comment' => [
+ 'comment_type' => 'PHPDoc',
+ 'header' => $header,
+ 'separate' => 'none',
+ 'location' => 'after_declare_strict',
+ ],
+ 'array_syntax' => [
+ 'syntax' => 'short',
+ ],
+ 'list_syntax' => [
+ 'syntax' => 'short',
+ ],
+ 'blank_line_before_statement' => [
+ 'statements' => [
+ 'declare',
+ ],
+ ],
+ 'general_phpdoc_annotation_remove' => [
+ 'annotations' => [
+ 'author',
+ ],
+ ],
+ 'ordered_imports' => [
+ 'imports_order' => [
+ 'class', 'function', 'const',
+ ],
+ 'sort_algorithm' => 'alpha',
+ ],
+ 'single_line_comment_style' => [
+ 'comment_types' => [
+ ],
+ ],
+ 'yoda_style' => [
+ 'always_move_variable' => false,
+ 'equal' => false,
+ 'identical' => false,
+ ],
+ 'phpdoc_align' => [
+ 'align' => 'left',
+ ],
+ 'multiline_whitespace_before_semicolons' => [
+ 'strategy' => 'no_multi_line',
+ ],
+ 'constant_case' => [
+ 'case' => 'lower',
+ ],
+ 'encoding' => true, // PHP代码必须只使用没有BOM的UTF-8
+ 'line_ending' => true, // 所有的PHP文件编码必须一致
+ 'single_quote' => true, // 简单字符串应该使用单引号代替双引号
+ 'no_empty_statement' => true, // 不应该存在空的结构体
+ 'standardize_not_equals' => true, // 使用 <> 代替 !=
+ 'blank_line_after_namespace' => true, // 命名空间之后空一行
+ 'no_empty_phpdoc' => true, // 不应该存在空的 phpdoc
+ 'no_empty_comment' => true, // 不应该存在空注释
+ 'no_singleline_whitespace_before_semicolons' => true, // 禁止在关闭分号前使用单行空格
+ 'concat_space' => ['spacing' => 'one'], // 连接字符是否需要空格,可选配置项 none:不需要 one:一个空格
+ 'no_leading_import_slash' => true, // use 语句中取消前置斜杠
+ 'cast_spaces' => ['space' => 'none'],
+ 'class_attributes_separation' => true,
+ 'combine_consecutive_unsets' => true,
+ 'declare_strict_types' => true,
+ 'lowercase_static_reference' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'multiline_comment_opening_closing' => true,
+ 'no_useless_else' => true,
+ 'no_unused_imports' => true,
+ 'not_operator_with_successor_space' => false,
+ 'not_operator_with_space' => false,
+ 'ordered_class_elements' => true,
+ 'php_unit_strict' => false,
+ 'phpdoc_separation' => false,
+]);
diff --git a/app/index/controller/Index.php b/app/index/controller/Index.php
index 2f5fbf79c..ab6fdaffd 100644
--- a/app/index/controller/Index.php
+++ b/app/index/controller/Index.php
@@ -1,18 +1,22 @@
env('CACHE_TYPE', 'file'),
// 缓存连接配置
- 'stores' => [
- 'file' => [
+ 'stores' => [
+ 'file' => [
// 驱动方式
- 'type' => 'File',
+ 'type' => 'File',
// 缓存保存目录
- 'path' => '',
+ 'path' => '',
// 缓存名称前缀
- 'prefix' => '',
+ 'prefix' => '',
// 缓存有效期 0 表示永久缓存
- 'expire' => 0,
+ 'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制
- 'serialize' => [],
+ 'serialize' => [],
],
- 'safe' => [
+ 'safe' => [
// 驱动方式
- 'type' => 'File',
+ 'type' => 'File',
// 缓存保存目录
- 'path' => syspath('safefile/cache/'),
+ 'path' => syspath('safefile/cache/'),
// 缓存名称前缀
- 'prefix' => '',
+ 'prefix' => '',
// 缓存有效期 0 表示永久缓存
- 'expire' => 0,
+ 'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制
- 'serialize' => [],
+ 'serialize' => [],
],
'redis' => [
// 驱动方式
- 'type' => 'redis',
- 'host' => env('CACHE_REDIS_HOST', '127.0.0.1'),
- 'port' => env('CACHE_REDIS_PORT', 6379),
- 'select' => env('CACHE_REDIS_SELECT', 0),
+ 'type' => 'redis',
+ 'host' => env('CACHE_REDIS_HOST', '127.0.0.1'),
+ 'port' => env('CACHE_REDIS_PORT', 6379),
+ 'select' => env('CACHE_REDIS_SELECT', 0),
'password' => env('CACHE_REDIS_PASSWORD', ''),
- ]
+ ],
],
-];
\ No newline at end of file
+];
diff --git a/config/database.php b/config/database.php
index ea58c067d..280a49dec 100644
--- a/config/database.php
+++ b/config/database.php
@@ -1,83 +1,86 @@
env('DB_TYPE', 'sqlite'),
+ 'default' => env('DB_TYPE', 'sqlite'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
- 'auto_timestamp' => true,
+ 'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 数据库连接配置信息
- 'connections' => [
- 'mysql' => [
+ 'connections' => [
+ 'mysql' => [
// 数据库类型
- 'type' => 'mysql',
+ 'type' => 'mysql',
// 服务器地址
- 'hostname' => env('DB_MYSQL_HOST', '127.0.0.1'),
+ 'hostname' => env('DB_MYSQL_HOST', '127.0.0.1'),
// 服务器端口
- 'hostport' => env('DB_MYSQL_PORT', '3306'),
+ 'hostport' => env('DB_MYSQL_PORT', '3306'),
// 数据库名
- 'database' => env('DB_MYSQL_DATABASE', 'thinkadmin'),
+ 'database' => env('DB_MYSQL_DATABASE', 'thinkadmin'),
// 用户名
- 'username' => env('DB_MYSQL_USERNAME', 'root'),
+ 'username' => env('DB_MYSQL_USERNAME', 'root'),
// 密码
- 'password' => env('DB_MYSQL_PASSWORD', ''),
+ 'password' => env('DB_MYSQL_PASSWORD', ''),
// 数据库连接参数
- 'params' => [],
+ 'params' => [],
// 数据库表前缀
- 'prefix' => env('DB_MYSQL_PREFIX', ''),
+ 'prefix' => env('DB_MYSQL_PREFIX', ''),
// 数据库编码默认采用 utf8mb4
- 'charset' => env('DB_MYSQL_CHARSET', 'utf8mb4'),
+ 'charset' => env('DB_MYSQL_CHARSET', 'utf8mb4'),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
- 'deploy' => 0,
+ 'deploy' => 0,
// 数据库读写是否分离 主从式有效
- 'rw_separate' => false,
+ 'rw_separate' => false,
// 读写分离后 主服务器数量
- 'master_num' => 1,
+ 'master_num' => 1,
// 指定从服务器序号
- 'slave_no' => '',
+ 'slave_no' => '',
// 检查字段是否存在
- 'fields_strict' => true,
+ 'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL执行日志
- 'trigger_sql' => true,
+ 'trigger_sql' => true,
// 开启字段类型缓存
- 'fields_cache' => isOnline(),
+ 'fields_cache' => isOnline(),
],
'sqlite' => [
// 数据库类型
- 'type' => 'sqlite',
+ 'type' => 'sqlite',
// 数据库文件
- 'database' => syspath('database/sqlite.db'),
+ 'database' => syspath('database/sqlite.db'),
// 数据库编码默认采用 utf8
- 'charset' => 'utf8',
+ 'charset' => 'utf8',
// 监听执行日志
'trigger_sql' => true,
// 其他参数字段
- 'deploy' => 0,
- 'suffix' => '',
- 'prefix' => '',
- 'hostname' => '',
- 'hostport' => '',
- 'username' => '',
- 'password' => '',
+ 'deploy' => 0,
+ 'suffix' => '',
+ 'prefix' => '',
+ 'hostname' => '',
+ 'hostport' => '',
+ 'username' => '',
+ 'password' => '',
],
],
];
diff --git a/config/phinx.php b/config/phinx.php
index a9ee86682..d6b34b457 100644
--- a/config/phinx.php
+++ b/config/phinx.php
@@ -1,19 +1,22 @@
[],
@@ -21,4 +24,4 @@ return [
'tables' => [],
// 备份数据表,填写表名
'backup' => [],
-];
\ No newline at end of file
+];
diff --git a/config/worker.php b/config/worker.php
index 974fe2415..a99b6457f 100644
--- a/config/worker.php
+++ b/config/worker.php
@@ -1,52 +1,52 @@
'127.0.0.1',
+ 'host' => '127.0.0.1',
// 服务监听端口
- 'port' => 2346,
+ 'port' => 2346,
// 套接字上下文选项
- 'context' => [],
+ 'context' => [],
// 高级自定义服务类
- 'classes' => '',
+ 'classes' => '',
// 消息请求回调处理
'callable' => null,
// 服务进程参数配置
- 'worker' => [
- 'name' => 'ThinkAdmin',
+ 'worker' => [
+ 'name' => 'ThinkAdmin',
'count' => 4,
],
// 监控文件变更重载,仅 Debug 模式有效
- 'files' => [
+ 'files' => [
// 监控检测间隔(单位秒,零不监控)
'time' => 3,
// 文件监控目录(默认监控 app+config 目录)
'path' => [],
// 文件监控后缀(默认监控 所有 文件)
- 'exts' => ['*']
+ 'exts' => ['*'],
],
// 监控内存超限重载,仅 Debug 模式有效
- 'memory' => [
+ 'memory' => [
// 监控检测间隔(单位秒,零不监控)
- 'time' => 60,
+ 'time' => 60,
// 限制内存大小(可选单位有 G M K )
- 'limit' => '1G'
+ 'limit' => '1G',
],
-];
\ No newline at end of file
+];
diff --git a/plugin/think-library/src/Builder.php b/plugin/think-library/src/Builder.php
index d9fa17023..3a9b28fe7 100644
--- a/plugin/think-library/src/Builder.php
+++ b/plugin/think-library/src/Builder.php
@@ -1,20 +1,22 @@
';
+ $html .= "\n\t\t\t" . sprintf('%s%s', empty($attrs['required']) ? '' : 'label-required-prev', $title, $substr);
+ $html .= "\n\t\t\t" . sprintf('', $name, $this->_attrs($attrs), $title, $this->variable, $name);
+ if ($remark) {
+ $html .= "\n\t\t\t" . sprintf('%s', $remark);
+ }
+ $this->fields[] = "{$html}\n\t\t";
+ return $this;
+ }
+
+ /**
+ * 创建 Text 输入.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param string $remark 字段备注
+ * @param bool $required 是否必填
+ * @param ?string $pattern 验证规则
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addTextInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
+ {
+ $attrs['vali-name'] = $title;
+ if ($required) {
+ $attrs['required'] = 'required';
+ }
+ if (is_string($pattern)) {
+ $attrs['pattern'] = $pattern;
+ }
+ return $this->addInput($name, $title, $substr, $remark, $attrs);
+ }
+
+ /**
+ * 创建密钥输入框.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param string $remark 字段备注
+ * @param bool $required 是否必填
+ * @param ?string $pattern 验证规则
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addPassInput(string $name, string $title, string $substr = '', bool $required = false, string $remark = '', ?string $pattern = null, array $attrs = []): Builder
+ {
+ $attrs['type'] = 'password';
+ return $this->addTextInput($name, $title, $substr, $required, $remark, $pattern, $attrs);
+ }
+
+ /**
+ * 添加取消按钮.
+ * @param string $name 按钮名称
+ * @param string $confirm 确认提示
+ * @return $this
+ */
+ public function addCancelButton(string $name = '取消编辑', string $confirm = '确定要取消编辑吗?'): Builder
+ {
+ return $this->addButton($name, $confirm, 'button', 'layui-btn-danger', ['data-close' => null]);
+ }
+
+ /**
+ * 添加提交按钮.
+ * @param string $name 按钮名称
+ * @param string $confirm 确认提示
+ * @return $this
+ */
+ public function addSubmitButton(string $name = '保存数据', string $confirm = ''): Builder
+ {
+ return $this->addButton($name, $confirm, 'submit');
+ }
+
+ /**
+ * 添加上传单图字段.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param bool $required 必填字段
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addUploadOneImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
+ {
+ if ($required) {
+ $attrs['required'] = 'required';
+ }
+ return $this->_addUploadOneView($name, $title, $substr, $attrs);
+ }
+
+ /**
+ * 添加上传视频字段.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param bool $required 必填字段
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addUploadOneVideo(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
+ {
+ if ($required) {
+ $attrs['required'] = 'required';
+ }
+ return $this->_addUploadOneView($name, $title, $substr, $attrs, 'video');
+ }
+
+ /**
+ * 创建上传多图字段.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param bool $required 必填字段
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addUploadMulImage(string $name, string $title, string $substr = '', bool $required = false, array $attrs = []): Builder
+ {
+ if ($required) {
+ $attrs['required'] = 'required';
+ }
+ $attrs = array_merge($attrs, ['type' => 'hidden', 'placeholder' => "请上传{$title} ( 多图 )"]);
+ $html = "\n\t\t" . '
';
+ $html .= "\n\t\t" . sprintf('', $name);
+ $this->fields[] = $html;
+ return $this;
+ }
+
+ /**
+ * 创建复选框字段.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param string $vname 变量名称
+ * @param bool $required 是否必选
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addCheckInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = [], string $type = 'checkbox'): Builder
+ {
+ if ($required) {
+ $attrs['required'] = 'required';
+ }
+ $attrs = array_merge($attrs, ['type' => $type, 'lay-ignore' => null, 'name' => $name . ($type === 'checkbox' ? '[]' : '')]);
+ $html = "\n\t\t" . '";
+ return $this;
+ }
+
+ /**
+ * 添加单选框架字段.
+ * @param string $name 字段名称
+ * @param string $title 字段标题
+ * @param string $substr 字段子标题
+ * @param string $vname 变量名称
+ * @param bool $required 是否必选
+ * @param array $attrs 附加属性
+ * @return $this
+ */
+ public function addRadioInput(string $name, string $title, string $substr, string $vname, bool $required = false, array $attrs = []): Builder
+ {
+ return $this->addCheckInput($name, $title, $substr, $vname, $required, $attrs, 'radio');
+ }
+
+ /**
+ * 显示模板内容.
+ * @return mixed
+ */
+ public function fetch(array $vars = [])
+ {
+ $html = '';
+ $type = "{$this->type}.{$this->mode}";
+ if ($type === 'form.page') {
+ $html = $this->_buildFormPage();
+ } elseif ($type === 'form.modal') {
+ $html = $this->_buildFormModal();
+ }
+ foreach ($this->class as $k => $v) {
+ $vars[$k] = $v;
+ }
+ throw new HttpResponseException(display($html, $vars));
+ }
+
+ /**
+ * 增加输入表单元素.
* @param string $name 字段名称
* @param string $title 字段标题
* @param string $subtitle 字段子标题
@@ -126,80 +335,26 @@ class Builder
$html = "\n\t\t" . '";
return $this;
}
/**
- * 创建文本输入框架
- * @param string $name 字段名称
- * @param string $title 字段标题
- * @param string $substr 字段子标题
- * @param array $attrs 附加属性
- * @return $this
- */
- public function addTextArea(string $name, string $title, string $substr = '', bool $required = false, $remark = '', array $attrs = []): Builder
- {
- if ($required) $attrs['required'] = 'required';
- $html = "\n\t\t" . '