diff --git a/README.md b/README.md
index 6aaed99..c32b66d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,844 @@
-### TOP-Framework
\ No newline at end of file
+# TOP-Framework
+*这是一个部分代码源自三年前毕业设计中的代码集合,后经过一系列重构,形成的一套框架。在此准备写一个文档。*
+
+## 模块
+### 创建模块
+1. 手动创建
+在application(可更改)目录下创建home目录,再创建config、controller(必须)、model、view目录
+2. 命令行自动创建
+命令格式([]为可选参数):
+```
+php create.php 目录 模块名 [入口文件]
+```
+
+进入framework/create/目录,执行以下命令:
+```
+php create.php application home index
+```
+
+至此,已经通过简单的命令创建了home模块,浏览器输入127.0.0.1即可访问home模块(系统默认模块为home模块,可在入口文件中指定),亦可命令行访问home模块。
+
+## 控制器
+### 创建控制器
+一个典型的控制器(Index.php)
+```
+view();
+}
+```
+调用基础控制器中的view方法、并return出去,完成模板的展示。
+### 模板传值
+1. view方法
+```
+public function index()
+{
+ return $this->view(null, [
+ 'param' => 'Hello world!'
+ ]);
+}
+```
+2. 直接return数组
+```
+public function index()
+{
+ return [
+ 'param' => 'Hello world!'
+ ];
+}
+```
+以上两种方式等效。
+### 控制器方法的前置、后置操作
+```
+public function before_index()
+{
+}
+
+public function after_index()
+{
+}
+
+public function index()
+{
+ return [
+ 'param' => 'Hello world!'
+ ];
+}
+```
+命名规范:before_方法名(前置)、after_方法名(后置),执行index方法之前会先执行before_index方法(如果存在),执行完index方法后会执行after_index方法(如果存在)。当前置方法return的值为空字符串、null、true时才会继续执行,否则前置方法的return等效于index方法的return。
+
+## 模型
+### 创建模型
+一个典型的模型(Users.php)
+```
+update([
+ 'username' => 'TOP糯米'
+], 1);
+```
+除此之外,提供另一种方式,传递更多条件或更复杂的条件
+```
+$this->update([
+ 'username' => 'TOP糯米'
+], function ($model) {
+ $model->where('id', 1);
+});
+```
+当然,也可以使用连贯操作
+```
+$this->where('id', 1)->update([
+ 'username' => 'TOP糯米'
+]);
+```
+
+成功返回受影响的记录数,失败抛出DatabaseException异常。
+
+5. find($param = false, $notRaw = true)
+查找一条记录
+
+可传入第一个参数为主键,第二个参数为是否按指定的规则(outReplace属性)进行处理。
+
+一般调用
+```
+$this->find(1);
+```
+匿名函数
+```
+$this->find(function ($model) {
+ $model->where('id', 1);
+});
+```
+连贯操作
+```
+$this->where('id', 1)->find();
+```
+
+成功返回一个一维数组,失败抛出DatabaseException异常。
+
+6. select($param = false, $notRaw = true)
+查找多条记录
+
+使用方法同find
+
+成功返回一个二维数组,失败抛出DatabaseException异常。
+
+7. delete
+删除记录
+
+直接传入主键
+```
+$this->delete(1);
+```
+匿名函数
+```
+$this->delete(function () {
+ $model->where('id', 1);
+});
+```
+连贯操作
+```
+$this->where('id', 1)->delete();
+```
+
+成功返回受影响的记录数,失败抛出DatabaseException异常。
+
+8. count
+返回记录数
+
+一般调用
+```
+$this->count();
+```
+第一个参数同样可以为匿名函数、并且同样支持连贯操作
+
+成功返回记录数,失败抛出DatabaseException异常。
+
+9. avg
+计算平均值
+
+接收一个参数,当没有使用field方法指定字段时,可直接传入字段名,以计算平均值。
+```
+$this->avg('score');
+```
+使用field方法指定字段
+```
+$this->field('score')->avg();
+```
+匿名函数中指定字段或条件
+```
+$this->avg(function ($model) {
+ $model->where('score', '>=', 60);
+ $model->field('score');
+});
+```
+成功返回平均值,失败抛出DatabaseException异常。
+
+10. max
+计算最大值
+
+同avg方法
+
+11. min
+计算最小值
+
+同avg方法
+
+12. sum
+求和
+
+同avg方法
+
+13. _sql
+返回最后执行的SQL语句
+
+14. tableDesc
+返回表结构
+
+接收参数为一个完整表名。
+
+成功返回表结构,失败抛出DatabaseException异常。
+
+15. distinct
+过滤记录中的重复值
+
+接收一个为字段名称的参数
+
+调用
+```
+$this->distinct('sex')->select();
+```
+
+失败抛出DatabaseException异常。
+
+16. effect
+删除时指定表(别)名
+
+接收一个参数,可以为字符串或数组,参数为表名或表别名
+
+调用
+```
+$this->delete(function ($model) {
+ $model->effect('s,this');
+ $model->join('left', 'score', 's')->on('s.uid = this.id');
+ $model->where(['this.id' => 3]);
+});
+```
+
+17. field
+指定字段
+
+可传入字符串或数组
+
+18. where
+指定条件
+
+最多可接收三个参数
+
+仅传入一个参数时,可传入字符串或数组
+```
+$where = ['id' => ['>', 10], 'sex' => 1];
+$where = 'id > 10 and sex = 1';
+$this->where($where)->select();
+```
+两个参数,解析为“字段=值”
+```
+$this->where('sex', 1)->select();
+```
+三个参数,指定字段与字段值的连接符
+```
+$this->where('sex', '>', 1)->select();
+```
+
+19. order
+对结果进行排序
+
+```
+$this->order('id desc')->select();
+```
+也可以使用匿名函数调用order方法
+
+20. limit
+查询范围
+
+接收一个参数,可以是字符串或数组
+
+一般调用
+```
+$this->limit('0, 5')->select();
+$this->limit([0, 5])->select();
+```
+两种方式等效
+
+21. join
+加入多表进行查询,通常情况下与on方法同时使用
+
+接收三个参数,第一个参数为连接方式(空、left、right、full),第二个参数为表名(不包含前缀),第三个参数为别名(当前表会自动将”this“作为别名)。
+
+一般调用
+```
+$this->select(function ($model) {
+ $model->join('left', 'score', 's')->on('s.uid = this.id');
+});
+```
+同样也可以使用连贯操作
+
+22. on
+表字段连接关系
+
+见join方法
+
+#### 属性:
+1. $table
+指定当前模型的表名(优先于模型名称)
+
+```
+protected $table = 'users';
+```
+
+2. $pk
+指定当前模型的主键(如果不指定,程序将自动查询以当前模型命名的表的主键)
+
+```
+protected $pk = 'id';
+```
+
+3. $map
+指定传入数据的键与数据库字段名称的映射关系
+
+```
+protected $map = [
+ 'name' => 'username'
+];
+```
+
+4. $inReplace
+入库时替换值
+
+数据入库时自动格式化时间为unix时间戳
+```
+protected $inReplace = [
+ 'create_time' => ['formatTime', true]
+];
+
+protected function formatTime($time)
+{
+ return strtotime($time);
+}
+```
+至此,在数据在被写入数据库之前会先调用inReplace中设定的函数、方法,并将return的值作为新的值写入数据库。
+
+注意:当以字段为键名的数组的值为一个字符串时,则该字符串为即将调用的函数,如果值为一个数组,且无第二个值或第二个值为false、空,则该数组第一个值为即将调用的函数,如第二个值为true,则表示当前调用的方法存在于本类或父类中。
+
+5. $outReplace
+出库时替换值
+
+```
+protected $outReplace = [
+ 'sex' => ['outFormatSex', true]
+];
+
+protected function outFormatSex($sex)
+{
+ switch ($sex) {
+ case 1:
+ return '男';
+ break;
+ case 2:
+ return '女';
+ break;
+ default:
+ return '未知';
+ }
+}
+```
+
+注意:当以字段为键名的数组的值为一个字符串时,则该字符串为即将调用的函数,如果值为一个数组,且无第二个值或第二个值为false、空,则该数组第一个值为即将调用的函数,如第二个值为true,则表示当前调用的方法存在于本类或父类中。
+
+6. $updateReplace
+数据更新时替换值
+
+基本类似于inReplace,但仅当执行更新操作时执行。
+
+7. $validate
+自动验证
+
+验证不为空
+```
+protected $validate = [
+ 'username' => ['notNull', '用户名不能为空'],
+];
+```
+验证不等于
+```
+protected $validate = [
+ 'username' => ['notEqual', '0', '用户名不能为0'],
+];
+```
+多条件(用户名不为空且不为0)
+```
+protected $validate = [
+ 'username' => [
+ ['notNull', '用户名不能为空'],
+ ['notEqual', '0', '用户名不能为0'],
+ ],
+];
+```
+自定义函数验证,新建函数demo到函数库
+```
+function demo($name, $n1, $n2)
+{
+ if ($name == $n1 || $name == $n2) {
+ return false;
+ }
+ return true;
+}
+```
+添加到自动验证
+```
+protected $validate = [
+ 'username' => [
+ ['notNull', '用户名不能为空'],
+ ['notEqual', '0', '用户名不能为0'],
+ ['demo', 'TOP糯米', '张三', '用户名不能为TOP糯米或张三'],
+ ],
+];
+```
+
+### 调用模型
+调用模型有两种方式:
+1. model函数(推荐)
+model函数会返回一个模型的单例,使用方式与直接new无差别。
+```
+$object = model(模型);
+```
+2. new 模型
+```
+$object = new 模型();
+```
+
+## 模板
+### 模板继承
+模板继承通过extend标签与block标签配合使用实现。
+一个最简单的继承
+```
+// Base/layout.html(父级模板)
+
+
+
+
+
+ Title
+
+
+
+
+
+
+// Index/index.html
+
+
+
+ 内容主体
+
+```
+### 模板标签
+内置一些常用标签
+1. php
+
+php标签。此标签为闭合标签,标签内的内容将被解析为原生php代码执行。
+
+```
+
+ echo '你好';
+
+```
+
+2. if
+
+if标签。此标签为闭合标签,condition属性为if的条件,属性列表:condition。
+
+```
+
+ // do something...
+
+```
+
+3. else
+
+else标签。此标签为自闭合标签,可选属性condition,存在condition属性则被解析为elseif,属性列表:condition(可选)。
+
+```
+
+ // do something...
+
+ // do something...
+
+
+
+ // do something...
+
+ // do something...
+
+```
+
+4. volist
+
+循环标签。此标签为闭合标签,属性列表:name、id、key(可选)。
+
+```
+
+ {$item['id']}
+
+
+
+ {$i}、{$item['id']}
+
+```
+
+5. assign
+
+赋值标签,在模板中创建新的php变量。此标签为自闭合标签,属性列表:name、value。
+
+```
+
+```
+
+6. raw
+
+该标签为闭合标签。raw标签中的内容不会被编译。
+
+```
+
+
+ {$item['id']}
+
+
+```
+上例,volist标签会被原样输出。
+
+7. 变量、函数输出
+```
+// 变量输出
+{$username}
+
+// 调用函数,左定界符后加上:表示调用函数
+{:mb_substr($username, 0, 3, 'utf8')}
+```
+
+### 自定义标签
+新建自定义标签库类文件/application/home/taglib/Extend.php,目录及文件名称没有要求。
+#### 闭合标签
+```
+namespace app\home\taglib;
+
+class Extend
+{
+ public $tags = [
+ 'test' => ['attr' => 'start,length,id', 'close' => 1]
+ ];
+
+ public function _test($tag, $content)
+ {
+ $parse = '';
+ $parse .= $content;
+ $parse .= '';
+ return $parse;
+ }
+}
+```
+类创建完成后,到配置文件config.php的view下的tagLib中添加Extend类
+```
+'view' => [
+ 'tagLib' => [
+ \app\home\taglib\Extend::class
+ ]
+ ],
+```
+添加完成后即可在模板中使用
+```
+
+ {$test}
+
+```
+#### 自闭合标签
+添加一个描述
+```
+'say' => ['attr' => 'what', 'close' => 0]
+```
+新建_say方法
+```
+public function _say($tag)
+{
+ return "";
+}
+```
+模板调用
+```
+
+```
+
+## 自定义路由
+路由配置文件位于 application 下,文件名:route.php
+现有News控制器中的detail方法
+```
+public function detail($id)
+{
+ return [
+ 'id' => (int) $id
+ ];
+}
+```
+假设访问地址为: http://127.0.0.3/home/news/detail/id/1.html 。
+### 必须参数
+添加如下规则
+```
+'detail' => [
+ '[id]',
+ 'home/news/detail'
+]
+```
+完成后,可使用 http://127.0.0.3/detail/1.html 访问到对应位置。
+### 可选参数
+修改detail方法
+```
+public function detail($id = 0)
+{
+ return [
+ 'id' => (int) $id
+ ];
+}
+```
+添加路由规则
+```
+'detail' => [
+ '[:id]',
+ 'home/news/detail'
+]
+```
+完成后,可使用 http://127.0.0.3/detail.html 访问到对应位置,如果没传递id,则使用默认值。
+### 多个参数
+```
+'detail' => [
+ '[id][:type]',
+ 'home/news/detail'
+]
+```
+
+## 其他
+### Request类
+获取实例
+1. instance方法获取单例
+```
+Request::instance();
+```
+2. request函数获取单例
+```
+request();
+```
+
+#### 供调用的方法
+1. isPost
+
+判断是否是POST请求
+
+2. isGet
+
+判断是否是GET请求
+
+3. isPut
+
+判断是否是PUT请求
+
+4. isDelete
+
+判断是否是DELETE请求
+
+5. isHead
+
+判断是否是HEAD请求
+
+6. isPatch
+
+判断是否是PATCH请求
+
+7. isOptions
+
+判断是否是OPTIONS请求
+
+8. isAjax
+
+判断是否是AJAX请求
+
+9. create
+
+创建一个HTTP请求
+
+原型:create($url, $data = [], $header = [])
+
+第一个参数为请求的链接,第二个参数为将要POST的数据,第三个参数为指定Header参数
+
+10. ip
+
+返回客户端IP地址
+
+11. module
+
+当前请求的模型名称
+
+12. classname
+
+当前请求的完整控制器名称
+
+13. controller
+
+当前请求的不包含命名空间的控制器名称
+
+14. method
+
+当前请求的方法名称
+
+15. params
+
+当前请求所带的参数
+
+16. get
+
+获取get数据
+
+原型:get($name = '*', $except = [], $filter = 'filter')
+
+第一个参数为将要获取的变量名称(' * ' 为全部),第二个参数为过滤的变量,第三个参数为指定的过滤函数(可以为自定义函数名称或匿名函数)。
+
+函数名称:
+```
+request()->get('id', ['type'], 'filter');
+```
+匿名函数:
+```
+request()->get('id', ['type'], function ($value) {
+ return (int) $value;
+});
+```
+
+17. post
+
+获取post数据
+
+使用同get方法
+
+18. except
+
+指定过滤的变量
+
+取出全部get数据,但不包括type
+```
+request()->except('type')->get();
+```
+
+### 面向控制器的前置、后置方法(请求拦截)
+创建application/home/filter/Auth.php测试文件
+```
+namespace app\home\filter;
+
+use top\middleware\ifs\MiddlewareIfs;
+
+class Auth implements MiddlewareIfs
+{
+ public function before()
+ {
+ return '拒绝请求';
+ }
+
+ public function after($data)
+ {
+ // TODO: Implement after() method.
+ }
+}
+```
+创建完成后,加入配置
+```
+'middleware' => [
+ \app\home\filter\Auth::class
+],
+```
+现在,访问项目则会得到 ' 拒绝请求 ' 结果。仅当before方法return的值为true时,程序才会继续执行,否则return等效于控制器方法的return。
\ No newline at end of file
diff --git a/application/home/config/config.php b/application/home/config/config.php
deleted file mode 100644
index 15d1c08..0000000
--- a/application/home/config/config.php
+++ /dev/null
@@ -1,9 +0,0 @@
- [
- 'port' => 3306
- ],
- 'middleware' => [
- \app\home\middleware\Test::class
- ],
-];
\ No newline at end of file
diff --git a/application/home/config/index.html b/application/home/config/index.html
deleted file mode 100644
index e69de29..0000000
diff --git a/application/home/controller/Common.php b/application/home/controller/Common.php
deleted file mode 100644
index 352bad6..0000000
--- a/application/home/controller/Common.php
+++ /dev/null
@@ -1,10 +0,0 @@
-view();
- return [];
- }
-}
diff --git a/application/home/controller/index.html b/application/home/controller/index.html
deleted file mode 100644
index e69de29..0000000
diff --git a/application/home/functions.php b/application/home/functions.php
deleted file mode 100644
index b3d9bbc..0000000
--- a/application/home/functions.php
+++ /dev/null
@@ -1 +0,0 @@
- 'user_type'
- ];
-
- protected $insertHandle = [
- '' => 'time',
- '' => ['getIntTime', true]
- ];
-
- protected $updateHandle = [
- '' => ['getIntTime', true]
- ];
-
- // 出库
- protected $outHandle = [
- '' => [
- 1 => '一',
- ]
- ];
-
- // 数据验证
- protected $validate = [
- '' => [
- ['notEqual', 0, 'tips'],
- ['notNull', 'tips']
- ],
- '' => ['notNull', 'tips']
- ];
-
- /**
- * 将字符串时间格式化为unix时间戳
- * @param $param
- * @return false|int
- */
- public function getIntTime($param)
- {
- return strtotime($param);
- }
-
-}
\ No newline at end of file
diff --git a/application/home/model/Users.php b/application/home/model/Users.php
deleted file mode 100644
index ce15f51..0000000
--- a/application/home/model/Users.php
+++ /dev/null
@@ -1,10 +0,0 @@
- ['attr' => 'what', 'close' => 0],
- 'lists' => ['attr' => 'name', 'close' => 1]
- ];
-
- public function _say($tag)
- {
- return '';
- }
-
- public function _lists($tag, $content)
- {
- $parse = "";
- $parse .= $content;
- $parse .= "";
- return $parse;
- }
-
-}
diff --git a/application/home/taglib/index.html b/application/home/taglib/index.html
deleted file mode 100644
index e69de29..0000000
diff --git a/application/home/view/Base/a.html b/application/home/view/Base/a.html
deleted file mode 100644
index ba073a4..0000000
--- a/application/home/view/Base/a.html
+++ /dev/null
@@ -1,2 +0,0 @@
-a.html
-
\ No newline at end of file
diff --git a/application/home/view/Base/b.html b/application/home/view/Base/b.html
deleted file mode 100644
index a34cd0f..0000000
--- a/application/home/view/Base/b.html
+++ /dev/null
@@ -1 +0,0 @@
-b.html
\ No newline at end of file
diff --git a/application/home/view/Base/common.html b/application/home/view/Base/common.html
deleted file mode 100644
index 2ef3515..0000000
--- a/application/home/view/Base/common.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- Title
-
-
-父级模板
-
-
-
\ No newline at end of file
diff --git a/application/home/view/Index/index.html b/application/home/view/Index/index.html
deleted file mode 100644
index 0905015..0000000
--- a/application/home/view/Index/index.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- BODY
-
-
-
- {$a}
-
- {$b}
-
-
-
- {:date('Y-m-d H:i:s', time())}
-
-
- cut
-
- content
-
- content
-
- content
-
-
-
-
\ No newline at end of file
diff --git a/application/home/view/index.html b/application/home/view/index.html
deleted file mode 100644
index e69de29..0000000
diff --git a/application/route.php b/application/route.php
deleted file mode 100644
index bd83500..0000000
--- a/application/route.php
+++ /dev/null
@@ -1,17 +0,0 @@
- [
- null,
- 'home/example/login'
- ],
- 'example-detail' => [
- '[id]',
- 'home/example/detail'
- ],
- 'example' => [
- '[:type]',
- 'home/example/index'
- ],
-];
\ No newline at end of file
diff --git a/framework/config/config.php b/framework/config/config.php
index c859d5e..033d71b 100644
--- a/framework/config/config.php
+++ b/framework/config/config.php
@@ -26,9 +26,7 @@ return [
],
'view' => [
'engine' => 'Top',
- 'tagLib' => [
- \app\home\taglib\Extend::class
- ],
+ 'tagLib' => [],
'ext' => 'html',
'dir' => '',
'cacheDir' => '',
diff --git a/framework/create/create.php b/framework/create/create.php
index e53d79f..9251eef 100644
--- a/framework/create/create.php
+++ b/framework/create/create.php
@@ -123,7 +123,7 @@ class Create
{
$file = $this->projectPath . '../route.php';
if (!file_exists($file)) {
- if (!file_put_contents($file, file_get_contents($this->dir . 'route.tpl'))) {
+ if (!file_put_contents($file, file_get_contents($this->dir . 'tpl/route.tpl'))) {
exit('-8');
}
}
diff --git a/framework/create/tpl/model/demo.tpl b/framework/create/tpl/model/demo.tpl
index 2bc1361..780b72b 100644
--- a/framework/create/tpl/model/demo.tpl
+++ b/framework/create/tpl/model/demo.tpl
@@ -12,6 +12,6 @@ class Demo extends Model
public function get()
{
- return 'Hello';
+ return '模块{name}正在运行...';
}
}
diff --git a/framework/create/tpl/view/index.tpl b/framework/create/tpl/view/index.tpl
index e0050d0..f1d584d 100644
--- a/framework/create/tpl/view/index.tpl
+++ b/framework/create/tpl/view/index.tpl
@@ -8,6 +8,8 @@
Document
-{$hello}
+{$hello}
+
+TOP-Framework