Thunder,是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架。
project 应用部署目录
├─app 应用目录
│ │
│ ├─模块1 项目模块1(例 Home)
│ │ ├─common 配置目录
│ │ ├─controller 控制器目录
│ │ └─views 视图
│ │
│ ├─模块2 项目模块2(例 Admin)
│ │ ├─common 配置目录
│ │ ├─controller 控制器目录
│ │ └─views 视图
│ │
│ ├─模型1 (例Student.php)
│ │
│ ├─模型2 (例Teacher.php)
│ │
│ └─ ...
├─core 框架系统目录
│
├─log 日志及缓存目录
│
├─public WEB 部署目录(对外访问目录)
│
├─routes 路由配置文件目录
│ └─www.php
│
├─vendor 第三方类库目录(Composer)
│
├─.env env全局配置文件
│
├─.htaccess 用于 apache 的重写
│
├─composer.json composer 定义文件
│
├─index.php 入口文件
│
└─README.md README 文件
http://serverName/index.php(或不写)/模块/控制器/操作/[参数名/参数值...]
出于优化的URL访问原则,还通过URL重写隐藏入口文件,下面以Apache为例说明隐藏应用入口文件index.php的.htaccess设置。
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
如果不清楚命名空间的基本概念,可以参考PHP手册:命名空间
模型:namespace app ;
控制器:namespace 模块名 \ controller ;
简单来讲,PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法,php的Traits和Go语言的组合功能类似(可以理解为横向扩展),通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。Thunder中的视图层则是利用Trait引入。具体用法请看下面的代码:
namespace thunder;
trait View{
public function display(){
//
}
}
namespace Home\controller;
use \thunder\View;
class IndexController{
use View;
public function index(){
$this->display();
}
}
API数据的输出
namespace Home\controller;
class IndexController{
public function index(){
$data = ['name'=>'thunder','url'=>'guolifu.pw'];
return ['data'=>$data,'code'=>1,'message'=>'ok'];
//返回纯数组
return ['data'=>$data,'code'=>1,'message'=>'ok','TO_ARRAY'=>true];
//返回jsonp
return ['data'=>$data,'code'=>1,'message'=>'ok','TO_JSONP'=>true];
}
}
{"data": {"name":"thunder","url":"guolifu.pw"},"code":1,"message":"ok"}
配置文件位于
core\config
中,包括数据库,日志存储,模板后缀,默认路由等配置,还可在分组下的common(如Home\common\config\创建覆盖配置文件
).env作为全局环境变量配置,目前只定义了数据库配置,具体可根据需求使用
getenv()
全局获取
Thunder中的路由十分简介强大,请看介绍:
http://serverName/index.php(或不写)/module/controller/action/param1/value1/param2/value2/...
// routes\web.php
use \thunder\Route;
/*注册路由*/
Route::init('goRoute','Home/index/index');
http://serverName/index.php(或不写)/goRoute
<==>
http://serverName/index.php(或不写)/goRoute/Home/index/index
注意!如此注册之后并不代表你可以传递参数
需传参写法
Route::init('goRoute/{param}','Home/index/index');
http://serverName/index.php(或不写)/goRoute/param1/value1/param2/value2/.../...
<==>
http://serverName/index.php(或不写)/goRoute/Home/index/index/param1/value1/param2/value2/.../...
Thunder中获取类型是简介明了的
http_method()
函数获取请求类型
IS_GET(判断是否为GET请求)
IS_POST(判断是否为POST请求)
class IndexController{
public function mvc(){
$m = route()->module;
$c = route()->ctrl;
$v = route()->action;
dump('模块:'.$m,'控制器:'.$c,'方法:'.$v);
}
}
在浏览器中访问http://serverName/home/index/mvc
"模块:Home"
"控制器:Index"
"方法:mvc"
一个灵活的框架必然会有一个灵活强大的数据库操作,Thunder为了满足开发者的各种开发习惯,封装了传统操作和ORM操作两种模式。
为了避免开发者重复new来new去,系统提供了一个强大的函数table('表名'),你可以把他想象成为一个你即将操作的数据库对象。下面简单了解一下
class IndexController{
public function sql(){
table('student')->find(); //默认查找 student 表第一条数据
table('student')->find(2); //返回ID为2的行的
table('student')->find(2,'name'); //返回ID为2的学生的name值(返回字符串)
table('student')->find(2,'id,name'); //返回ID为2的学生的id和name(返回的是数组)
<==>
table('student')->find(2,['id','name']);//为了清晰,可以使用数组形式(推荐)
}
}
class IndexController{
public function sql(){
table('student')->all();//返回student表中全部数据
}
}
class IndexController{
public function sql(){
table('student')->where(['name'=>'thunder'])->find();
table('student')->where(['id'=>1])->all(); //WHERE id = 1
table('student')->where(['id[>]'=>1])->all(); //WHERE id > 1
table('student')->where(['id[!]'=>1])->all(); //WHERE id != 1
table('student')->where(['id[>=]'=>1])->all();//WHERE id >= 1
table('student')->where(['id[<=]'=>1])->all();//WHERE id <= 1
table('student')->where(['id[<>]'=>[1,10]])->all();//WHERE id BETWEEN 1 AND 10
table('student')->where(['id[><]'=>[1,10]])->all();//WHERE id NOT BETWEEN 1 AND 10
table('student')->where('city[~]'=>'lon')->all();//WHERE "city" LIKE '%lon%'
table('student')->where('city[!~]'=>'lon')->all();//WHERE "city" NOT LIKE '%lon%'
table('student')->where('city[~]'=>['lon','foo','bar'])->all();//WHERE "city" LIKE '%lon%' OR "city" LIKE '%foo%' OR "city" LIKE '%bar%'
table('student')->where(["OR" => [
"student_id" => [2, 123, 234, 54],
"email" => ["[email protected]", "[email protected]", "[email protected]"]
]])->all();
// WHERE
// student_id IN (2,123,234,54) OR
// email IN ('[email protected]','[email protected]','[email protected]')
// 多条件查询
table('student')->where(["OR" => [
"AND" => [
"user_name[!]" => "foo",
"student_id[!]" => 1024,
"email[!]" => ["[email protected]", "[email protected]", "[email protected]"],
"city[!]" => null,
"promoted[!]" => true
]
]])->all();
// WHERE
// `user_name` != 'foo' AND
// `student_id` != 1024 AND
// `email` NOT IN ('[email protected]','[email protected]','[email protected]') AND
// `city` IS NOT NULL
// `promoted` != 1
}
}
class IndexController{
public function sql(){
table('student')->where(["OR" => [
"AND" => [ //实际应用时这儿可以使用AND或者OR
"OR" => [ //第一个条件
"user_name" => "foo",
"email" => "[email protected]"
],
"OR" => [ //第二个条件
"user_name" => "bar",
"email" => "[email protected]"
]
]
]])->all();
// WHERE (
// (
// "user_name" = 'foo' OR "email" = '[email protected]'
// )
// AND
// (
// "user_name" = 'bar' OR "email" = '[email protected]'
// )
// )
}
}
[>] == LEFT JOIN [<] == RIGH JOIN [<>] == FULL JOIN [><] == INNER JOIN
class IndexController{
public function sql(){
table('student')->join(["[>]class"=>['s_id'=>'class_id']])->all();
// LEFT JOIN `class` ON `student`.`class_id` =`s_id`
}
}
//之前的条件查询where()就是连贯操作的一种,剩下的请看例子,非常容易理解。
class IndexController{
public function sql(){
//field()筛选字段 参数可以如下写,也可以写做数组形式
table('student')->field('name(别名),num')->all();
table('student')->field(['name','num(别名)'])->all();
//order()排序 参数可写多个,靠前权重高
table('student')->order(['字段名'=>'排序(如ASC,DESC需大写)'])->all();
//limit()条数限制
table('student')->limit(l)->all();//表示从返回结果集中取l条数据;
table('student')->limit([n,m])->all();//表示从返回结果集中的第n+1条开始,取m条数据;
//以上方法均可连贯操作
table('student')->join(["[>]class"=>['s_id'=>'class_id']])->where(['class[>]'=>1])->limit([5,10])->order(['id'=>'DESC'])->field('name')->all();
}
}
public function sql(){
$data = ['name'=>'xiaoming','age'=>18];
table('student')->add($data);
//也可以批量新增
$data = [
['name'=>'xiaoming','age'=>18],
['name'=>'zhangsan','age'=>17],
['name'=>'liergou','age'=>16]
];
table('student')->add($data);
}
public function sql(){
$data = ['name'=>'xiaoming','email'=>'[email protected]'];
//使用update()时可以连贯使用where()作为条件。
table('student')->where(['student_id'=>3])->update($data);
//根据id修改数据时系统提供简介方法
table('student')->setOne(1,$data);
}
public function sql(){
table('student')->destroy(1); //根据id删除数据
table('student')->flushall(); //清空数据表(慎重使用)
}
public function sql(){
table('student')->count(); //统计条数
table('student')->max(); //统计字段最大
table('student')->min(); //统计字段最小
table('student')->avg(); //统计字段平均值
table('student')->sum(); //统计字段求和
}
public function sql(){
table()->query("SELECT * FROM student")->fetchAll();
}
//不是每个数据库引擎都支持事务。你必须在使用前检查。如果返回false,则回滚事务。
public function sql(){
$database = table('student');
$database->action(function ($database){
$database->add(['name'=>'事物']);
$res = $database->setOne(1,['name'=>'action']);
return $res->rowCount()==0? false:true;
return false;
});
}
//如果修改没有成功,返回false,则回滚事务。不会修改成功也不会添加成功。
这里的ORM模型就不详细说明了,系统提供了model('表名')函数以供调用ORM模型。具体请移步到https://docs.golaravel.com/docs/4.1/eloquent/
Thunder封装了强大的模板引擎供开发者使用。在控制器中use \thunder\View;并且在类中use View;你就可以尽情的使用强大的引擎来协助你的工作
class IndexController{
public function index(){
// 模板变量赋值
$this->assign('name','Thunder');
$this->assign('email','[email protected]');
// 或者批量赋值
$this->assign([
'name' => 'Thunder',
'email' => '[email protected]'
]);
// 模板输出
$this->display();
$this->display('index1'); //同级目录下
$this->display('index/url'); //跨控制器输出
$this->display('api/index/views');//跨模块输出
}
}
在tpl配置文件中自定义规则
return array(
'TMPL_PARSE_STRING' =>array( //自定义模板变量
'__PUBLIC__' => __PUBLIC__,
'__ADMIN__' => __PUBLIC__.'/'.'Admin',
)
);
//在html中使用{{__PUBLIC__}}调用
{{asset.css('路径')}} //规则:server/public/模块/css/路径;
{{asset.js('路径')}} //规则:server/public/模块/js/路径;
{{asset.asset('路径')}} //规则:server/public/模块/路径;
该方法支持第二个参数
{{asset.css('路径',true)}} //规则:server/public/Public/css/路径;代表模块公共目录路径
html中使用{{变量名}}
{{name}}
在页面中显示
Thunder
更多模板操作请参考twig手册
Thunder的一些其他操作
class IndexController{
public function index(){
session()->set('name','val');
session()->get('name');
session()->del('name');
session()->clear();
}
}
use \thunder\Cookie;
class IndexController{
public function index(){
cookie::set('name','val');
cookie::get('name');
cookie::del('name');
}
}
public function create_verify(){
$v = verify();
$v->length = 4; //设置长度
$v->useNoise = false;//是否添加杂点
$v->useCurve = false;//是否画混淆曲线
$v->create();//生成验证码
}
public function verify(){
$code = input('post.code');
$v = verify();
if($v->check($code))
header('Location:./index?login=1');
$this->display();
}
public function upload(){
if(IS_POST){
$up = new \thunder\Upload();
//设置属性(上传的位置, 大小, 类型, 名是是否要随机生成)
$up -> set("path",__UPLOAD__.'/images');
$up -> set("maxsize", 2000000);
$up -> set("allowtype", array("gif", "png", "jpg","jpeg",'xls'));
$up -> set("israndname", false);
if($up -> upload("photo")) {
//获取上传后文件名子
var_dump($up->getFileName());
}else {
//获取上传失败以后的错误提示
var_dump($up->getErrorMsg());
}
}
$this->display();
}
Created by leileida.
v2.0.0
1.修正了路由规则
2.增加了多模块机制
3.控制器方法重构
4.api开发模式,控制器return数组自动转换为json格式等。
5.模型层重构,模型层分离为独立层:
demo:
namespace app;
use \thunder\Model;
class Student extends Model{
public function test(){
return 'test!';
}
6.视图机制优化,支持跨控制器,跨模块输出页面
demo:
namespace home\controller;
use \thunder\View;
class StudentController{
use View;
public function index(){
$this->display();
$this->display('index1');
$this->display('index/url');
$this->display('api/index/views');
}
}
- fixed the routing rule
- increased the multi module mechanism
- controller method refactoring
- join the API development model, the controller return array automatically converted to JSON format.
5. model layer is reconstructed, and model layer is separated into independent layer:
demo:
namespace app;
use \thunder\Model;
class Student extends Model{
public function test(){
return 'test!';
}
}
6. view mechanism optimization, support cross controller, cross module output page
namespace home\controller;
use \thunder\View;
class StudentController{
use View;
public function index(){
$this->display();
$this->display('index1');
$this->display('index/url');
$this->display('api/index/views');
}
}