1.MVC是什么
MVC的全名是Model View Controller,是一种使用“模型-视图-控制器”设计创建Web应用程序的模式,同时提供了对HTML、CSS和JavaScript的完全控制,它是一种软件设计典范
- m: model,业务模型, 数据库操作
- v: view, 用户界面(视图), html 页面
- c: controller,控制器, model与view数据交互的中间层
2.分层后的MVC
2.1 控制器
- 接受请求: 路由
- 选择模型: CURD
- 加载视图: 模板
2.2 模型
- 查询构造器
- 模型操作
2.3 视图
- 模板赋值
- 渲染视图
2.4 目录结构
3.MVC实现与路由
3.1 核心原理
3.1.1 业务模型Model.php
<?php
// 模型类
namespace core;
use PDO;
abstract class Model
{
protected $db = null;
//1.连接数据库 在实例化时自动连接
public function __construct($dsn, $username, $password)
{
$this->db = new PDO($dsn, $username, $password);
}
// 2.内置一些底层操作
// 2.1 获取全部数据 $table 查询的表名
public function getAll($table)
{
$sql = "SELECT * FROM `$table` ;";
$stmt = $this->db->prepare($sql);
// $stmt->execute();
if ($stmt->execute()) {
return $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
print_r($stmt->errorInfo());
}
}
// 2.2 指定获取多条数据 此案例只调用了此方法
public function getData($table, $num)
{
$sql = "SELECT * FROM `$table` LIMIT ?;";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(1, $num, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 2.3 根据id查询一条数据
public function getOne($table, $id)
{
$sql = "SELECT * FROM `$table` WHERE `id`= ? ;";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(1, $id, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
3.1.2 视图 View.php
<?php
// 视图类
namespace core;
class View
{
// 1. 模板变量容器
protected array $data = [];
// 2. 模板赋值
public function assign(string $key, $value)
{
$this->data[$key] = $value;
}
// 3. 渲染视图同时传参 $path 视图路径 $data存放参数的容器
public function render(string $path, array $data = [])
{
if ($data) {
foreach ($data as $key => $value) {
$this->assign($key, $value);
}
}
// 解构数组容器 以数组的键作为变量名 方便在模板中使用
extract($this->data);
// 渲染/加载模板文件
file_exists($path) ? include $path : die('模板不存在');
}
}
3.1.3 控制器 Controller.php
<?php
// 控制器类
namespace core;
abstract class Controller
{
// 1.模型对象
protected Model $model;
// 2.视图对象
protected View $view;
// 3.在实例化时初始化模型对象与视图对象
public function __construct(Model $model, View $view)
{
$this->model = $model;
$this->view = $view;
}
}
3.1.4 路由 Router.php
<?php
namespace core;
// 路由类
class Router
{
public static function parse(): array
{
// 默认控制器,实际项目,应该来自配置文件,而不是在写死
$controller = 'Index';
$action = 'index';
// 参数列表
$params = [];
// 判断是否存在pathinfo
if (array_key_exists('PATH_INFO', $_SERVER) && $_SERVER['PATH_INFO'] !== '/') {
// 为什么要判断 $_SERVER['PATH_INFO'] !== '/' ?
// 因为: admin.php/ 时,$_SERVER['PATH_INFO'] = '/', 导致解析控制器失败
$pathinfo = array_filter(explode('/', $_SERVER['PATH_INFO']));
// dump($pathinfo);
// 考虑到index.php/ 情况, 这时pathinfo为空数组
if (count($pathinfo) >= 2) {
$controller = array_shift($pathinfo);
$action = array_shift($pathinfo);
$params = $pathinfo;
} else {
$controller = array_shift($pathinfo);
}
}
// 查看控制器,方法,参数
// dump($controller, $action, $params);
// 将这些数据返回出去
return [$controller, $action, $params];
}
}
3.2 自定义User的实现
3.2.1 自定义模型 UserModel.php
<?php
// 自定义User模型
namespace model;
use core\Model;
class UserModel extends Model
{
public function __construct($dsn, $username, $password)
{
parent::__construct($dsn, $username, $password);
}
// 根据条件获取数据
public function getLimitData($table,$num=10)
{
return $this->getData($table,$num);
}
}
3.2.2 自定义控制器 UserController.php
<?php
namespace controller;
use core\Controller;
use core\Model;
use core\View;
class UserController extends Controller
{
public function __construct(Model $model, View $view)
{
parent::__construct($model, $view);
}
// 获取user表中所有数据
public function getLimitData($table,$num)
{
// 1. 选择模型: 获取数据
$users = $this->model->getLimitData($table,$num);
// 2. 加载视图
// 路径约定: view/控制器/方法名.php
$this->view->render('view/user/getLimitData.php', ['users' => $users]);
}
}
3.2.3 视图模板 getLimitData.php
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分页展示数据</title>
<style>
table {
margin: auto;
width: 600px;
border-collapse: collapse;
text-align: center;
}
table th,
table td {
border: 1px solid;
padding: 5px;
}
table thead {
background-color: lightcyan;
}
table caption {
font-size: larger;
margin-bottom: 8px;
}
body>p {
display: flex;
}
p>a {
text-decoration: none;
color: #555;
border: 1px solid;
padding: 5px 10px;
margin: 10px 2px;
}
.active {
background-color: seagreen;
color: white;
border: 1px solid seagreen;
}
</style>
</head>
<body>
<table>
<caption><h3>用户信息表</h3></caption>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>邮箱</th>
<th>注册时间</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $user) :extract($user) ?>
<tr>
<td><?=$id?>
</td>
<td><?=$name?>
</td>
<td><?=$sex?'女':'男' ?>
</td>
<td><?=$email?>
</td>
<td><?=date('Y-m-d H:i:s',$register_data)?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</body>
</html>
3.2.4 入口文件 index.php
<?php
namespace myMVC;
use controller\UserController;
use model\UserModel;
use core\View;
// 入口文件: 测试
// 1.类的自动 composer的自动加载器
require 'vendor/autoload.php';
// 2. 实例化控制器
$model = new UserModel('mysql:dbname=phpedu', 'root', 'root');
$view = new View();
$users = new UserController($model, $view);
// 3. 调用控制器中的方法
$users->getLimitData('user',15);
3.2.5 composer.json配置文件,实现自动加载
{
"autoload": {
"psr-4": {
"core\\": "core",
"model\\": "model",
"controller\\": "controller"
}
},
"require": {}
}
配置完成后需执行
composer dumpautoload
使之生效
3.3 预览
3.4 路由
路由的本质: 是从url中解析出控制器,控制器方法,以及方法的参数
- controller: 控制器类名
- method: 控制器中的某个方法名
- params: 参数列表,以数组形式
以路由的方式获取数据
http://phpedu.io/0824/myMVC/indexRouter.php/UserController/getLimitData/user&10
indexRouter.php
<?php
namespace myMVC;
use controller\UserController;
use model\UserModel;
use core\View;
use core\Router;
// 入口文件: 测试
// 1.类的自动 composer的自动加载器
require 'vendor/autoload.php';
$request = Router::parse();
// 路由解析
$controller = array_shift($request);
$action = array_shift($request);
// 将参数分割转为数组
$params = explode('&', array_shift($request)[0]);
// print_r($params);
//生成新的控制器名称
$controller = 'controller\\' . ucfirst($controller) . 'Controller';
// 2. 实例化控制器
$model = new UserModel('mysql:dbname=phpedu', 'root', 'root');
$view = new View();
$users = new UserController($model, $view);
// 3. 调用控制器中的方法
call_user_func_array([$users, 'getLimitData'], $params);