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;

              }

       }     

}     

?>

 

原创粉丝点击