基于PHP的mvc框架
基于PHP的mvc框架:https://gitee.com/fyiyy/yogurt
yogurt
介绍
yogurt是基于php的mvc框架
软件架构
软件架构说明
安装教程
使用说明
基础
1.安装yogurt
yogurt的环境要求如下:
PHP >= 7.3
PDO PHP Extension
MBstring PHP Extension
CURL PHP Extension
2.开发规范
3.目录结构
project 应用部署目录
├─application 应用目录(可设置)
├─config 公共配置
├─framework 框架系统目录
├─public WEB 部署目录(对外访问目录)
│ ├─static 静态资源存放目录(css,js,image)
│ ├─index.php 应用入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于 apache 的重写
├─runtime 应用的运行时目录(可写,可设置)
├─vendor 第三方类库目录(Composer)
架构
1.架构总览
2.入口文件
默认的应用入口文件位于public/index.php,内容如下:
namespace yogurt;
require_once __DIR__ . '/../framework/start.php';
3.URL访问
没有启用路由的情况下典型的URL访问规则是:
http://serverName/模块/控制器/操作?[参数名=参数值...] http://serverName/index.php(或者其它应用入口文件)?m=模块&c=控制器&a=操作&[参数名=参数值...]
配置
1.配置目录
系统默认的配置文件目录就是项目目录(ROOT_PATH),也就是默认的project下面,并分为应用配置(整个应用有效)和模块配置(仅针对该模块有效)。
2.配置格式
返回PHP数组的方式是默认的配置定义格式,例如:
return [
// 调试模式
'debug' => true,
// 访问日志写入
'log_write' => true,
// 默认模板后缀
'default_template_exit' => 'html',
// URL模式, 可选值:0=>兼容模式,1=>pathinfo,2=>rewrite
'url_model' => 0,
// 默认模块
'default_model' => 'index',
// 默认控制器
'default_controller' => 'index',
// 默认方法
'default_action' => 'index',
// 控制器文件夹,自定义修改必须保证有对应的目录
'controller_directory' => 'controller',
// 视图文件夹,自定义修改必须保证有对应的目录
'view_directory' => 'view',
// 程序app文件名
'app_name' => 'application',
// 是否强制开启路由模式
'url_route_must' => false,
];
3.读取配置
设置完配置参数后,就可以使用get方法读取配置了,例如:
echo Config::get('配置参数1');
如果需要读取二级配置,可以使用:
echo Config::get('配置参数.二级参数');
4.环境变量配置
在开发过程中,可以在应用根目录下面的.env来模拟环境变量配置,.env文件中的配置参数定义格式采用ini方式,例如:
app_debug = true
app_trace = true
[DATABASE]
HOSTNAME = 127.0.0.1,127.0.0.1
DATABASE = yogurt
USERNAME = root
PASSWORD = root,root
路由
1.路由模式
2.路由定义
在route目录下面定义任意php文件,目前路由只支持精确匹配,暂不支持正则匹配
use yogurt\Route;
Route::get('/hello', function () {
return 'hello';
});
Route::get('/route', function () {
return 'route';
});
Route::get('/index/hello', '/index/index/yogurt');
控制器
1.控制器定义
yogurt的控制器定义比较灵活,可以无需继承任何的基础类,也可以继承官方封装的\yogurt\Controller类或者其他的控制器类。
控制器定义
一个典型的控制器类定义如下:
namespace app\index\controller;
class Index
{
public function index()
{
return 'index';
}
}
控制器类文件的实际位置是:
application\index\controller\Index.php
如果继承了yogurt\Controller类的话,可以直接调用yogurt\View及yogurt\Request类的方法,例如:
namespace app\index\controller;
use yogurt\Controller;
class Index extends Controller
{
public function index()
{
// 获取包含域名的完整URL地址
$this->assign('domain',$this->request->url(true));
return $this->fetch('index');
}
}
2.控制器重定向
\yogurt\Controller类的redirect方法可以实现页面的重定向功能。
//重定向到News模块的Category操作
Response::redirect('News/Category');
请求
1.请求信息
如果要获取当前的请求信息,可以使用\yogurt\Request类, 除了下文中的
Request::get('id');
2.请求类型
Request::isPost();
3.参数绑定
按名称绑定 参数绑定方式默认是按照变量名进行绑定,例如,我们给Blog控制器定义了两个操作方法read和archive方法,由于read操作需要指定一个id参数,archive方法需要指定年份(year)和月份(month)两个参数,那么我们可以如下定义:
namespace app\index\Controller;
class Blog
{
public function read($id)
{
return 'id='.$id;
}
public function archive($year='2016',$month='01')
{
return 'year='.$year.'&month='.$month;
}
}
URL的访问地址分别是:
http://serverName/index.php/index/blog/read/?id=1
http://serverName/index.php/index/blog/archive?year=2016&month=06
4.依赖注入
Yogurt的依赖注入(也称之为控制反转)是一种较为轻量的实现,无需任何的配置,并且主要针对访问控制器进行依赖注入。可以在控制器的构造函数或者操作方法(指访问请求的方法)中类型声明任何(对象类型)依赖,这些依赖会被自动解析并注入到控制器实例或方法中。
在控制器的架构方法中会自动注入当前请求对象,例如:
namespace app\index\controller;
use yogurt\Request;
class Index
{
public function hello(Request $request)
{
return 'Hello,' . $request->param('name') . '!';
}
}
数据库
1.连接数据库
常用的配置在config目录下面的database.php中添加下面的配置参数:
use yogurt\Env;
return [
// 数据库类型:mysql,sqlsrv
'type' => 'mysql',
// 服务器地址
'hostname' => Env::get('database.hostname', '127.0.0.1'),
// 数据库名
'database' => Env::get('database.database', 'yogurt'),
// 用户名
'username' => Env::get('database.username', 'root'),
// 密码
'password' => Env::get('database.password', 'root'),
// 端口
'hostport' => '3306',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'y_',
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 1,
// 数据库读写是否分离 主从式有效
'rw_separate' => true,
// 读写分离后 主服务器数量
'master_number' => 1,
];
2.基本使用
配置了数据库连接信息后,我们就可以直接使用数据库运行原生SQL操作了,支持query(查询操作)和execute(写入操作)方法,并且支持参数绑定。
Db::query("select * from y_user where id=1");
Db::execute("insert into y_user (id, name) values (1, 'yogurt')");
3.查询构造器
查询一个数据使用:
// table方法必须指定完整的数据表名
Db::table('y_user')->where('id',1)->find();
查询数据集使用:
Db::table('y_user')->where('status',1)->select();
添加数据
使用 Db 类的 insert 方法向数据库提交数据
$data = ['name' => 'yogurt'];
Db::table('y_user')->insert($data);
添加多条数据
$data = [
['name' => 'yogurt'],
['name' => 'yogurt1'],
['name' => 'yogurt2']
];
Db::name('user')->insertAll($data);
更新数据
Db::table('y_user')->where('id', 1)->update(['name' => 'yogurt']);
删除数据表中的数据
Db::table('y_user')->where('id',1)->delete();
链式操作
表达式查询
Db::table('y_user')
->where('id','>',1)
->where('name','yogurt')
->select();
数组条件
$map['name'] = 'yogurt';
$map['status'] = 1;
// 把查询条件传入查询方法
Db::table('y_user')->where($map)->select();
4.分布式数据库
Yogurt内置了分布式数据库的支持,包括主从式数据库的读写分离,但是分布式数据库必须是相同的数据库类型。
配置database.deploy 为1 可以采用分布式数据库支持。如果采用分布式数据库,定义数据库配置信息的方式如下
//分布式数据库配置定义
return [
// 启用分布式数据库
'deploy' => 1,
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '192.168.1.1,192.168.1.2',
// 数据库名
'database' => 'demo',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
];
模型
1.定义
视图
1.视图实例化
2.模版引擎
3.模版赋值
除了系统变量和配置参数输出无需赋值外,其他变量如果需要在模板中输出必须首先进行模板赋值操作,绑定数据到模板输出有下面几种方式:
namespace index\app\controller;
class Index extends \yogurt\Controller
{
public function index()
{
// 模板变量赋值
$this->assign('name','Yogurt');
$this->assign('email','1719847255@qq.com');
// 或者批量赋值
$this->assign([
'name' => 'Yogurt',
'email' => '1719847255@qq.com'
]);
// 模板输出
return $this->fetch('index');
}
}
4.模版渲染
模版
1.模版定位
2.模版标签
普通标签用于变量输出和模板注释,普通模板标签默认以{ 和 } 作为开始和结束标识,并且在开始标记紧跟标签的定义,如果之间有空格或者换行则被视为非模板标签直接输出。 例如:{<span id="MathJax-Span-2" class="noError">name} 、{<span class="MJX_Assistive_MathML">name} 、{vo['name']} 都属于正确的标签,而{ <span id="MathJax-Element-2-Frame" class="MathJax" data-mathml="<math xmlns="http://www.w3.org/1998/Math/MathML"><merror><mtext>name} 、{</mtext></merror></math>"><span id="MathJax-Span-3" class="math"><span id="MathJax-Span-4" class="noError">name} 、{<span class="MJX_Assistive_MathML">name} 、{vo.name}则不属于。
要更改普通标签的起始标签和结束标签,可以更改下面的配置参数:
return [
// 模板后缀
'view_suffix' => 'html',
// 标签左界定符
'taglib_begin' => '{',
// 标签右界定符
'taglib_end' => '}',
// 是否支持原生PHP标签
'php_turn' => true,
];
3.变量输出
4.模版注释
{#...# 或者 *...#,注释}
5.模版继承
模板继承是一项更加灵活的模板布局方式,模板继承不同于模板布局,甚至来说,应该在模板布局的上层。模板继承其实并不难理解,就好比类的继承一样,模板也可以定义一个基础模板(或者是布局),并且其中定义相关的区块(block),然后继承(extend)该基础模板的子模板中就可以对基础模板中定义的区块进行重载。
因此,模板继承的优势其实是设计基础模板中的区块(block)和子模板中替换这些区块。
每个区块由{block} {/block}标签组成。 下面就是基础模板中的一个典型的区块设计(用于设计网站标题):
{block name="title"}<title>网站标题</title>{/block}
block标签必须指定name属性来标识当前区块的名称,这个标识在当前模板中应该是唯一的,block标签中可以包含任何模板内容,包括其他标签和变量,例如:
{block name="title"}<title>{$web_title}</title>{/block}
你甚至还可以在区块中加载外部文件:
{block name="include"}{include file="public/header" /}{/block}
一个模板中可以定义任意多个名称标识不重复的区块,例如下面定义了一个base.html基础模板:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{block name="title"}标题{/block}</title>
</head>
<body>
{block name="menu"}菜单{/block}
{block name="left"}左边分栏{/block}
{block name="main"}主内容{/block}
{block name="right"}右边分栏{/block}
{block name="footer"}底部{/block}
</body>
</html>
然后我们在子模板(其实是当前操作的入口模板)中使用继承:
{extend name="base" /}
{block name="title"}{$title}{/block}
{block name="menu"}
<a href="/">首页</a>
<a href="/info/">资讯</a>
<a href="/bbs/">论坛</a>
{/block}
{block name="left"}{/block}
{block name="main"}
{volist name="$list" id="vo"}
<a href="/new/{$vo['id']}">{$vo['title']}</a><br/>
{$vo['content']}
{/volist}
{/block}
{block name="right"}
最新资讯:
{volist name="$news" id="new"}
<a href="/new/{$new['id']}">{$new['title']}</a><br/>
{/volist}
{/block}
{block name="footer"}
@Yogurt 版权所有
{/block}
6.包含文件
{include file="public/header" /} // 包含头部模版header
7.内置标签
volist标签通常用于查询数据集(select方法)的结果输出,通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出。 在控制器中首先对模版赋值:
$list = User::select();
$this->assign('list',$list);
在模版定义如下,循环输出用户的编号和姓名:
{volist name="$list" id="vo"}
{$vo['id']}:{$vo['name']}<br/>
{/volist}
循环标签
{foreach $data item="$item"}
<p>{$item['id']} {$item['name']}</p>
{/foreach}
{foreach $data as $key=>$vo}
<p>{$vo['id']} {$vo['name']}</p>
{/foreach}
IF标签
{loop name="$data" id='vo'}
{if ($vo['id'] == 15)}
<p style="color: red;">{$vo['id']} {$vo['name']}</p>
{else}
<p>{$vo['id']} {$vo['name']}</p>
{/if}
{/loop}
日志
1.日志写入
2.日志读取
杂项
1.缓存
Yogurt采用yogurt\Cache类提供缓存功能支持。
缓存支持采用驱动方式,所以缓存在使用之前,需要进行连接操作,也就是缓存初始化操作。
设置
return [
// 缓存类型为File,支持file,redis
'type' => 'file',
// 全局缓存有效期(0为永久有效)
'expire'=> 0,
// 缓存前缀
'prefix'=> 'yogurt',
// 缓存目录
'path' => '../runtime/cache/',
// redis缓存配置
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'password' => ''
]
];
使用
设置缓存(有效期一个小时)
Cache::set('name',$value,3600);
获取缓存
Cache::get('name');
删除缓存
Cache::rm('name');
清空缓存
Cache::clear();
2.Session
设置(有效期一个小时)
Session::set('name',$value,3600);
获取
Session::get('name');
删除
Session::delete('name');
清空
Session::clear();
3.Cookie
4.上传
前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="upload.html" method="post" enctype="multipart/form-data">
<input type="file" name="image" id="">
<input type="submit" value="上传">
</form>
</body>
</html>
public function upload()
{
$file = Request::file('image')->validate(['size' => 1024, 'ext' => 'jpg,jpeg,png,gif,xls'])->rule('md5')->move('upload/');
echo '<pre>';
print_r($file->getError());
echo '</pre>';
echo '<pre>';
print_r($file->getSaveName());
echo '</pre>';
exit();
}
中间件
1.定义
在应用目录下面middleware目录中定义控制器中间件
namespace app\middleware;
use Closure;
class CheckLogin
{
/**
* 响应处理请求
* @param $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// 请求响应前
$response = $next($request);
// 请求响应后
return $response;
}
}
2.使用
在控制器中定义中间件属性$middleware
namespace app\index\controller;
use yogurt\Controller;
class Base extends Controller
{
/**
* 中间件属性
* @var string[] $middleware
*/
protected $middleware = [
'app\middleware\CheckLogin',
];
}
容器
1.使用
if (!app()->make('yogurt\Cache')->get('login')) {
app()->make('yogurt\Cache')->set('login', 'yogurt', 10);
}
halt(app()->make('yogurt\Cache')->get('login'));

浙公网安备 33010602011771号