phpMVC
来源:互联网 发布:员工管理系统数据库表 编辑:程序博客网 时间:2024/06/06 09:03
一、 Introduction
1. 项目开发常见流程
需求调研,人员,项目经理;成果,需求说明书。
软件设计书,人员,项目经理;成果,详细设计说明书,通常就是开发过程中的主要参考技术文档。
界面设计,人员,界面工程师;成果,设计效果图。
静态网页制作,人员,前端工程师;成果,静态网页。
动态网页开发,人员,程序员;成果,基本可用的软件初级产品。
测试,人员,测试工程师;成果,可用的符合需求的产品。
上线运营,人员,运维工程师;成果,发现问题,提出新需求,提出改进建议。
2. 关于显示和逻辑相分离的开发思想
就是显示页面和页面内的计算需求分别在不同的文件,通过调用的方式以实现显示需求的效果的思想。
<?php
//先计算数据
$t = date("Y-m-d H:i:s");
//然后载入一个静态网页,并在其中输出和显示计算的数据
include './time.html';
?>
<!DOCTYPE html>
<head>
<style type="text/css">
.div1{
color:red;
size:15px;
}
</style>
</head>
<body>
<div class=div1>
时间为:<?php echo $t; ?>
</div>
</body>
</html>
3. 模版技术
比如,显示当前时间,并可以由用户来选择使用不同的风格进行显示。
基本做法是获取数据的逻辑基本保持不变,但是表示数据的文件可以有多个。只需在php文件中,根据用户的选择,以决定使用哪个模版文件。
<?php
//先计算数据
$t = date("Y-m-d H:i:s");
//然后载入一个静态网页,并在其中输出和显示计算的数据
if(!empty($_GET['bg'])){
$bg = $_GET['bg'];
}else{
$bg = "red";
}
$file = "./time-" . $bg . ".html";
include $file;
?>
显示页面
<!DOCTYPE html>
<head>
<style type="text/css">
.div1{
color:red;
size:15px;
}
.b{
background-color:#bb0000;
}
p a{color:black}
</style>
</head>
<body class="b">
<p align="left">
<ahref="time1.php?bg=red">红景</a>
<ahref="time1.php?bg=green">绿景</a>
<ahref="time1.php?bg=blue">蓝景</a>
</p>
<div class=div1>
时间为:<?php echo $t; ?>
</div>
</body>
</html>
还有另外两个类似的模版页面。
二、 MVC思想
Mvc,是model、view、controller三个词的首字母,意思是模型、视图、控制,是一种应用于浏览器/服务器的开发思想,旨在清晰化程序设计、简化开发流程、优化后续维护。以服务流程解释就是用户浏览器发出请求,请求到达控制层,也就是一个php文件,然后,先调用模型,实际也是一个php文件,通过模型获取数据,然后,载入视图,一般是html文件,最终将数据显示给用户浏览器。
详细解释
控制器,controller,是php文件,由浏览器直接请求。它需要做两件核心工作,根据需求,决定需要什么数据,并去调用模型文件,去获取该数据;根据需求,决定需要将数据显示在哪个视图文件中。
模型,model,是php文件,不能直接请求,只能被载入而发挥作用。它的核心工作是根据控制器的要求去生产数据。
视图,view,是一个伪html文件,伪是因为里面有简单的php代码,也不应有浏览器直接请求。它的作用是结合html和css,显示相应的数据。
1. 一个渗透mvc思想的案例
创建一个用户注册网页
模型层
<?php
require "./MysqlUtil.class.php";
class UserModel{
function GetAllUser(){
$config = array(
'host' =>"localhost",
'port' =>3306,
'username'=> "root",
'password'=> "123456",
'names' =>"utf8",
'database'=> "php1",
);
$m =MysqlUtil::GetInstance($config);
$sql = "select* from stu1";
$rec = $m->GetRows($sql);
return $rec;
}
function GetUserCount(){
$config = array(
'host' =>"localhost",
'port' =>3306,
'username'=> "root",
'password'=> "123456",
'names' =>"utf8",
'database'=> "php1",
);
$m =MysqlUtil::GetInstance($config);
$sql = "selectcount(*) from stu1";
$rec = $m->GetOneData($sql);
return $rec;
}
}
?>
控制层,也可以叫控制器
<?php
require './UserModel.class.php';
$obj_user = new UserModel();
$data1 = $obj_user ->GetAllUser();
$data2 = $obj_user ->GetUserCount();
include './showAllUser_view.html';
?>
视图层
<!DOCTYPE html>
<head>
</head>
<body>
用户列表:
<?php
//一般不采用在php中嵌入html的形式
/*
echo "<table border='1'>";
echo"<tr>";
echo"<td>用户名</td>";
echo"<td>年龄</td>";
echo"<td>学历</td>";
echo"<td>爱号</td>";
echo"<td>来自</td>";
echo "<td>注册时间</td>";
echo"<td>操作</td>";
echo"</tr>";
foreach($data1 as $key=>$rec){
echo"<tr>";
echo"<td>" . $rec['username'] . "</td>";
echo"<td>" . $rec['age'] . "</td>";
echo"<td>{$rec['xueli']}</td>";
echo"<td>{$rec['fav']}</td>";
echo"<td>{$rec['home']}</td>";
echo"<td>{$rec['dt']}</td>";
echo "<td><ahref='mysql5.php?id={$rec['id']}' onclick = 'return queren()'>删除</a></td>";
echo"</tr>";
}
echo "</table>";
*/
//而是采用在html中嵌入php的方式,因为php是脚本语言,html是前端人员做的,他们使用的都是纯html开发的,而不是php,
//后端人员都在html基础上在需要显示数据的地方嵌入php语言以显示数据的。如果完全采用php中嵌入html,对于前端人员是不合适的,也不是高效的。
?>
<table border='1'>
<tr>
<td>用户名</td>
<td>年龄</td>
<td>学历</td>
<td>爱号</td>
<td>来自</td>
<td>注册时间</td>
<td>操作</td>
</tr>
<?php
foreach($data1 as$key =>$rec){
?>
<tr>
<td><?phpecho $rec['username']; ?></td>
<td><?phpecho $rec['age']; ?></td>
<td><?phpecho $rec['xueli']; ?></td>
<td><?phpecho $rec['fav']; ?></td>
<td><?phpecho $rec['home']; ?></td>
<td><?phpecho $rec['dt']; ?></td>
<td><ahref="?id=<?php echo $rec['id']; ?>" onclick = 'returnqueren()'>删除</a></td>
</tr>
<?php } ?>
</table>
<br />
当前用户总数:<?php echo $data2;?>
</body>
<script>
function queren(){
var s =window.confirm("确认删除?");
return s;
}
</script>
</html>
2. 模型层
用于处理数据的存取操作,比如表的增删改查。通常是根据控制器的要求,以返回合适的数据。有时控制器需要传递过来相应的数据,才能获取对应的结果数据,比如,获取id为4的用户的信息,此时控制器就需要传递4这个数据。
1) 模型层的典型代码模式
class 模型类名{
function 方法1(参数列表){……}
function 方法2(参数列表){……}
function 方法3(参数列表){……}
……
}
每个方法都是为了获取某种数据,有的方法可能需要一些参数,这些方法通常需要和数据库打交道,需要mysqlUtil工具类及相关的数据库连接数据。
2) 控制器中调用模型层获取数据的典型做法
require ‘模型层类文件’;
$obj = new 模型对象();
$data = $obj -> 某个方法();
3) 基础模型类
<?php
require './MysqlUtil.class.php';
class BaseModel{
//用于存储数据库工具类的实例
protected $db = null;
function __construct(){
$config = array(
'host' =>"localhost",
'port' =>3306,
'username'=> "root",
'password'=> "123456",
'names' =>"utf8",
'database'=> "php1",
);
$this ->db =MysqlUtil::GetInstance($config);
}
}
?>
在模型类中使用基础模型类
<?php
require "./BaseModel.php";
class UserModel extends BaseModel{
function GetAllUser(){
$sql = "select* from stu1";
$rec = $this ->db->GetRows($sql);
return $rec;
}
function GetUserCount(){
$sql = "selectcount(*) from stu1";
$rec = $this ->db->GetOneData($sql);
return $rec;
}
}
?>
4) 实现模型类的单例
模型类本身不变,不保证其本身是单例的,但是通过单例工厂,去获得模型类的实例,就是单例的。设计一个单例工厂类,通过这个单例工厂类,去获取模型类的对象。
<?php
class ModelFactory{
static $all_model =array();
static functionMF($model_name){
if(!isset(static::$all_model[$model_name]) ||
!(static::$all_model[$model_name]instanceof $model_name)){
static::$all_model[$model_name]= new $model_name();
}
returnstatic::$all_model[$model_name];
}
}
?>
5) 整个模型层的类库结构图
基础模型类(利用mysql工具类连接数据库,属性常用的名字为dao,data access object,数据访问对象)。
服务型模型类继承基础模型类。
单例工厂类,用于生产单例的模型类。
3. 控制器
获取请求数据,根据请求数据,以决定,调用哪个模型以获取什么数据,载入哪个视图文件以显示该数据。
//显示添加用户视图
if(!empty($_GET['act']) && $_GET['act'] == 'add'){
include './form_view.html';
return null;
}
//向数据库添加用户
if(!empty($_GET['act']) && $_GET['act'] == 'InsertUser'){
$username =$_POST['username'];
$password =$_POST['password'];
$age = $_POST['age'];
$xueli = $_POST['xueli'];
$fav = $_POST['fav'];
$home = $_POST['home'];
$aihao = array_sum($fav);
$rec = $obj_user->InsertUser($username, $password, $age, $xueli, $aihao, $home);
echo "添加用户成功";
echo "<ahref='?'>返回</a>";
return $rec;
}
将控制器的执行代码进行封装,根据控制的功能封装到功能对应的方法中:
<?php
require './UserModel.class.php';
require './ModelFactory.class.php';
//$obj_user = new UserModel();
class UserController{
function DetailAction(){
$obj_user = ModelFactory::MF('UserModel');
$rec = $obj_user->FindUserById($_GET['id']);
include'./userInfo.html';
}
function AddAction(){
$obj_user =ModelFactory::MF('UserModel');
include'./form_view.html';
}
functionInsertUserAction(){
$obj_user = ModelFactory::MF('UserModel');
$username =$_POST['username'];
$password =$_POST['password'];
$age =$_POST['age'];
$xueli =$_POST['xueli'];
$fav =$_POST['fav'];
$home =$_POST['home'];
$aihao =array_sum($fav);
$rec = $obj_user->InsertUser($username, $password, $age, $xueli, $aihao, $home);
echo "添加用户成功";
echo "<ahref='?'>返回</a>";
}
function DelAction(){
$obj_user =ModelFactory::MF('UserModel');
$obj_user->DeleteUserById($_GET['id']);
echo "删除成功";
echo "<ahref='?'>返回</a>";
}
function IndexAction(){
$obj_user =ModelFactory::MF('UserModel');
$data1 = $obj_user->GetAllUser();
$data2 = $obj_user->GetUserCount();
include'./showAllUser_view.html';
}
functionShowUpdateAction(){
$obj_user =ModelFactory::MF('UserModel');
$rec = $obj_user->FindUserById($_GET['id']);
include'./form_view.html';
}
functionUpdateUserAction(){
$obj_user =ModelFactory::MF('UserModel');
$id = $_POST['id'];
$username =$_POST['username'];
$password =$_POST['password'];
$age =$_POST['age'];
$xueli =$_POST['xueli'];
$fav =$_POST['fav'];
$home =$_POST['home'];
$aihao =array_sum($fav);
$rec = $obj_user->UpdateUserById($id, $username, $password, $age, $xueli, $aihao, $home);
echo "修改成功";
echo "<a href='?'>返回</a>";
}
}
$ctrl = new UserController();
$act = !empty($_GET['act']) ? $_GET['act'] : 'Index';
$action = $act . "Action";
$ctrl ->$action(); //使用可变方法代替以下逻辑判断
/*
//查看详情
if(!empty($_GET['act']) && $_GET['act'] == 'detail'){
DetailAction();
}
//显示添加用户视图
else if(!empty($_GET['act']) && $_GET['act'] == 'add'){
AddAction();
}
//向数据库添加用户
else if(!empty($_GET['act']) && $_GET['act'] == 'InsertUser'){
InsertAction();
}
//删除用户
else if(!empty($_GET['act']) && $_GET['act'] == 'del'){
DelAction();
}else{
IndexAction();
}
//*/
/*
$o2 = ModelFactory::MF('UserModel');
var_dump($obj_user);echo "<br />";
var_dump($o2);
//*/
?>
控制器的划分,通常,一个项目中,会有很多的功能,通常会将一些相关功能,合在一起,称为一个模块,并使用一个控制器去表达这个模块中的各个功能,其实就是方法。
一个控制器,就是一个类,一个控制器中,就只包含了一些方法。这些方法,被称为动作,因为每个方法,就对应了用户的某个操作。习惯上,所有的动作都以Action这个词为结尾。这些动作,将会对应网页上的连接或跳转或提交动作中的act参数的值。
实际应用中,在网页的连接或跳转或提交的时候,act=XXX会写成:a=XXX。一种习惯写法。
基础控制器类,一个项目中,有多个控制器,每个控制器是一个类文件,每个控制器中都有各自的一些功能,但是它们常常有些共同的工作或事情,如,设定编码,因为是由控制器来决定显示什么数据,也就应该由其来决定使用什么编码;页面的简短信息的显示,以及跳转功能。这些共同的工作可以一个基础控制器来完成,以便低耦合,高内聚。
<?php
class BaseController{
function __construct(){
header("content-type:text/html;charset=utf-8");
}
//显示一定的提示文件,然后,自动跳转(可以设定停留的时间描述)
function GotoUrl($msg,$url, $time){
echo"<p>$msg</p>";
echo "<ahref='$url'>返回</a>";
echo "<br/>页面将在{$time}秒之后自动跳转";
header("refresh:$time;url=$url");//自动定时跳转
}
}
?>
4. 视图层
视图层的功能是展示页面的静态内容,以及相关的变量数据。数据分为,普通标量数据,比如echo $v1;;数组数据,比如foreach($arr as $key =>$value){……}或单独输出,echo $arr[‘id’];对象数据,比如echo $o1->p1;echo $o2 ->p2;。
三、 关于MVC项目的其他常见做法
1. 请求分发器
又叫前端控制器,是根据请求类型,分别将请求发送到对应的控制器类的控制器。目的在于降低功能的耦合度,进一步提高内聚性。功能是根据传过来的c请求数据,决定作用使用哪个控制,可以设置默认值,根据传过来的a请求数据,决定使用哪个动作,可以设置默认值。
<?php
$c = !empty($_GET['c'])?$_GET['c']:'User';
require './' . $c . 'Model.class.php';
require './ModelFactory.class.php';
require './BaseController.class.php';
require './' . $c . 'Controller.class.php';
$controller = $c . 'Controller';
$ctrl = new $controller();
$act = !empty($_GET['act']) ? $_GET['act'] : 'Index';
$action = $act . "Action";
$ctrl ->$action(); //使用可变方法代替以下逻辑判断
?>
2. 目录结构的设定
为了管理的方便,通常将mvc项目的文件,根据功能分类存放在对应的文件夹,类似:
项目一级目录
下级目录
Index.php
Controllers
XXXController.php
Models
XXXModel.class.php
Framework
MysqlUtil.php、BaseModel.class.php……
Views
ShowAllUsers.html、Form_view.html……
3. 关于后台的初步创建
一般网站从客户界面和管理界面划分,包括前台和后台两部分。如果创建后台后,为了管理方便,项目的目录结构可以调整为:
项目一级目录
下级目录
下级目录
Index.php
Application
front
Controllers
XXXController.php
Models
XXXModel.class.php
Views
ShowAllUsers.html、Form_view.html……
back
Controllers
XXXController.php
Models
XXXModel.class.php
Views
AdminIndex.html、AdminForm_view.html……
Framework
MysqlUtil.php、BaseModel.class.php……
加入后台模块后,前端控制器类也做相应的调整,例子如:
<?php
require './Framework/MysqlUtil.class.php';
require "./Framework/BaseModel.class.php";
require './Framework/ModelFactory.class.php';
require './Framework/BaseController.class.php';
$p = !empty($_GET['p'])?$_GET['p']:'front';
$c = !empty($_GET['c'])?$_GET['c']:'User';
require "./Application/$p/Models/" . $c . 'Model.class.php';
require "./Application/$p/Controllers/" . $c . 'Controller.class.php';
$controller = $c . 'Controller';
$ctrl = new $controller();
$act = !empty($_GET['a']) ? $_GET['a'] : 'Index';
$action = $act . "Action";
$ctrl ->$action(); //使用可变方法代替以下逻辑判断
?>
为了开发的方便,在主页可以设计进入后台的连接,实际生产中不会这样做。
<a href="?p=back&c=Admin&a=login">进入后台</a>
4. 基础常量的设定
在mvc中,会使用到很多相对固定的目录路径,使用一个常量来表示这些固定的路径,可以起到简化代码的作用。
更重要的意义是保证在一个脚本周期内不会被有意或无意的更改。
常量一般定义在前端控制器类中。
比如定义和使用了常量后的前端控制器:
<?php
$p = !empty($_GET['p'])?$_GET['p']:'front';
$c = !empty($_GET['c'])?$_GET['c']:'User';
define("PLAT", $p);
define("DS", DIRECTORY_SEPARATOR ); //DIRECTORY_SEPARATOR表示目录分隔符,只有2个:‘\’(windows系统),‘/’(linux系统)
define("ROOT", __DIR__ . DS); //__DIR__表示当前mvc框架的根目录
define("APP", ROOT . 'Application' . DS); //application的完整路径
define("FRAMEWORK", ROOT . 'Framework' . DS); //框架基础类所在的路径
define("PLAT_PATH", APP . PLAT . DS); //平台所在目录
define("CTRL_PATH", PLAT_PATH . "Controllers" .DS); //当前控制器所在目录
define("MODEL_PATH", PLAT_PATH . "Models" .DS); //当前模型所在目录
define("VIEW_PATH", PLAT_PATH . "Views" . DS); //当前视图所在目录
require FRAMEWORK . 'MysqlUtil.class.php';
require FRAMEWORK . 'BaseModel.class.php';
require FRAMEWORK . 'ModelFactory.class.php';
require FRAMEWORK . 'BaseController.class.php';
require MODEL_PATH . $c . 'Model.class.php';
require CTRL_PATH . $c . 'Controller.class.php';
$controller = $c . 'Controller';
$ctrl = new $controller();
$act = !empty($_GET['a']) ? $_GET['a'] : 'Index';
$action = $act . "Action";
$ctrl ->$action(); //使用可变方法代替以下逻辑判断
?>
5. 自动加载的实现
在前端控制器中,加载文件时,对于类的文件,如果一次性全部加载,那么可能会造成资源的浪费。采用类的自动加载机制,可以使得在使用类的时候自动加载,以避免内存资源的浪费。比如:
//自动加载有利于有效利用资源
function __autoload($class){
$base_class =array("MysqlUtil", "BaseModel", "ModelFactory","BaseController");
if(in_array($class,$base_class)){
require FRAMEWORK .$class . '.class.php'; //加载基础模型类
}else if(substr($class, -5)=== "Model"){ //如果后5个字母是Model,则加载Model类
require MODEL_PATH .$class . '.class.php';
}else if(substr($class,-10) === "Controller"){ //如果后10个字母是Controller,则加载Controller类
require CTRL_PATH .$class . '.class.php';
}
}
6. 目录的访问权限控制
在项目的目录中,一般只需要对外开放主页的访问,其他目录的文件不应该对外开放访问。
配置方法:
在apache的conf/extra/httpd-vhosts.conf文件中,
将项目所在的文件夹的权限配置的一段:
<Directory"D:/php/test1>
Options Indexes FollowSymLinks
AllowOverride none
Require all granted
#DirectoryIndex hello.php
</Directory>
修改为:
<Directory"D:/php/test1>
Options Indexes FollowSymLinks
#AllowOverride设置是否分布式权限配置文件(.htaccess)
AllowOverride All
Require all granted
#DirectoryIndex hello.php
</Directory>
重启apache,然后在项目文件目录下,那些不允许外界通过浏览器访问的文件目录下,即application目录和Frameword目录下,都放置这个文件.htaccess。文件的内容为:Deny from All
四、 认识ECshop
安装ECShop
ECShop是一款B2C独立网站系统,适合快速构建个性化网上商店。下载一套ecshop,然后解压放在和apache、php等安装软件同级的目录下。在apache的httpd-vhost.conf文件中,创建一个站点作为esshop的站点,比如:
#ECShop电子商城
<VirtualHost *:80>
ServerName www.ecshop.com
DocumentRoot "D:\php\amp\ecshop\upload "
<Directory"D:\php\amp\ecshop\upload ">
Options Indexes FollowSymLinks
AllowOverride none
Require all granted
DirectoryIndex index.php
</Directory>
</VirtualHost>
然后将域名在hosts文件中做映射,然后,就可以访问这个站点了。
然后,按照网站提示的步骤,检查环境,对于不支持的项目,需要在php软件包的php.ini文件中打开相应的模块,比如不支持GD版本,那么就打开extension=php_gd2.dll。
然后,下一步,配置系统。填写配置信息。然后,点击安装。然后,打开www. Phpmyadmin.com网页会看到创建ecshop的数据库。
然后,就可以访问esshop的前台和后台页面。
五、 使用mvc框架实现登录界面和功能
首先,设计登录账户表。
create tableadmin_user(
id int auto_increment primary key,
admin_name varchar(20) unique key,
admin_pass varchar(48) not null,
login_times int comment '登录次数',
last_login_time datetime comment '最后登录时间'
) charset = utf8;
然后,插入几条管理员身份的数据,以便测试。
然后,设计一个登录界面。
注意表单提交的路径设计为:?p=back&c=Admin&a=CheckLogin
编写控制器类:
<?php
class AdminController extends BaseController{
function LoginAction(){
include VIEW_PATH .'adminlogin.html';
}
functionCheckLoginAction(){
$u =$_POST['username'];
$p =$_POST['password'];
$model =ModelFactory::MF('AdminModel');
$result = $model->CheckAdmin($u, $p);
if($result ===true){
echo "登录成功";
}else{
//失败后,提示并跳转到登录界面
$this->GotoUrl("登录失败","?p=back&c=Admin&a=Login", 2);
}
}
}
?>
编写模型类:
<?php
class AdminModel extends BaseModel{
function CheckAdmin($u,$p){
$sql = "selectcount(*) as c from admin_user where admin_name='$u' andadmin_pass=md5('$p');";
//echo $sql;
$result = $this->dao ->GetOneData($sql);
//echo $result;
if($result == 1){
//登录成功后,应该去修改登录次数和最后登录时间
$sql ="update admin_user set login_times = login_times+1, last_login_time =now() where admin_name = '$u'; ";
$this->dao ->exec($sql);
return true;
}else{
return false;
}
}
}
?>
- phpMVC
- 几个phpmvc框架
- PhpMVC框架整合smarty模板
- 让Nginx/tengine支持ThinkPHP/phpmvc框架/iwebshop的URL重写和PATHINFO
- 网易云课堂什么情况?
- 【工具使用】API表达工具----swagger
- OpenCV学习笔记(4)——平滑处理图像
- [Leetcode] 524. Longest Word in Dictionary through Deleting 解题报告
- 第三方jar包冲突怎么解决
- phpMVC
- 兄弟连学Python(1)— 函数
- 生成随机数,猜数得分
- mvp登陆
- 扩展欧几里德的收获,和遗憾
- python enumerate()函数
- Java代码建立TCP连接
- OpenCV学习笔记(3)——进度条视频播放控制
- Recycleview的点击事件