php.MVC系列教程

xxjfhh 贡献于2013-02-19

作者 a  创建于2004-11-03 05:40:00   修改者a  修改于2004-11-03 06:50:00字数28338

文档摘要:  php.MVC是PHP Web应用程序的一个开源框架,它实现了模型-视图-控制器(MVC)设计模式——Web应用程序的工业标准,鼓励基于Model2架构的应用程序设计。这种开发模式允许网页或其他显示内容从内部应用程序代码中分离出来,让设计者和程序员更容易地集中于他们各自的专业领域。这个框架提供了一个单独入口点的控制器。这个控制器接受HTTP请求,并根据配置文件分配给相应的动作处理。
关键词:

php.MVC系列教程之前言       ASP,JSP,PHP是WEB开发的三大技术,三种技术优缺点也早就有人分析过了。无非也就是ASP简单易用且有microsoft做靠山,JSP功能强大是因为有java支持,PHP则开源跨平台。在国内,ASP应用范围最广,JSP发展势头最猛,PHP则处于劣势。这可能与公司的支持以及技术的培训有关。       由于公司项目的需要,我这才接触PHP,用过一段时间后两点体会最深刻,一是学习容易,上手极快,内置函数很多,适合快速开发;二是学习资料匮乏,普及不广,很多时候都要去看英文文档。       对于中小型WEB应用来说,PHP有很强的竞争力,LINUX+APACHE+MYSQL+PHP(LAMP)的组合几乎可以胜任绝大多数网站的解决方案,对于大型应用来讲,对于系统架构要求更高,需要有成熟的框架支持,JSP的struts是个不错的框架,国内介绍它的资料也非常多,应用逐渐广泛起来,对应的PHP也有php.MVC,但是我搜遍了网络也没有发现一篇中文文档,这才让我动了翻译用户指南念头,也算是抛砖引玉,希望PHP能够在国内蓬勃发展起来。       php.MVC是PHP Web应用程序的一个开源框架,它实现了模型-视图-控制器(MVC)设计模式——Web应用程序的工业标准,鼓励基于Model2架构的应用程序设计。这种开发模式允许网页或其他显示内容从内部应用程序代码中分离出来,让设计者和程序员更容易地集中于他们各自的专业领域。这个框架提供了一个单独入口点的控制器。这个控制器接受HTTP请求,并根据配置文件分配给相应的动作处理。       模型包含了应用程序的业务逻辑,控制器负责处理请求,并转向到相应的显示组件——将HTML和PHP标签的结合起来的模板文件。处理结果返回给客户端浏览器,或者通过另外的协议比如SMTP。       php.MVC是用PHP来实现Jakarta Struts框架,目前它支持Struts的许多特性,包括申明应用程序的配置参数通过XML解析器。比如在XML配置文件中指定各种业务逻辑组件与对应的显示组件之间的映射。 php.MVC的网站地址http://www.phpmvc.net 用PHP开始你的MVC (一)整合你的站点入口 这是一篇介绍如何用php来实现MVC模式开发的文件。关于MVC模式的技术文章网上随处可以,所以这篇文件将不再讲述这种模式的优缺点(实际 上是我说不清楚),子讲他的php技术实现。并且在以后的系列文章中也是以讲技术为主。 一、实现统一的网站入口(在MVC中调用Controler层的方法,也就是控制层) 大家也许经常在网上看到这样的路径(http://www.aaa.com/aaa/bbb/aaa?id=5),让人不解,这样的网站的实现方式有几种可能性:     1、隐藏文件的扩展名,对这种做法的好处,众说纷纭,不过个人觉得没有必要;     2、用了网站的重定向规则,实现虚拟路径;     3、强制文件解析的方式,实现虚拟路径。 用第2\3种方法可以实现网站的统一接口,合理的整合网站,更好的体现网站的安全性和架构,用这两种方式的网站大多是使用“MVC”模式构 建和实现的。 下面是一个例子 访问路径如下:       ....../test/*******/Bad       ....../test/*******/Good     (其中的"******"可以用任何字符串替换,"......."是你的web路径) 文件的目录结构如下  |-- .htaccess  |-- test  |-- Application.php  |-- Controler/GoodControler.php  |-- Controler/BadControler.php 注意 文件".htaccess",在windows下不能直接建立的,可以在命令行模式下建立. 文件0:(.htaccess)(这个文件是更改apache的配置方式用的) forcetype application/x-httpd-php 文件1:(test.php) parse(); $aa->go(); ?> 文件2:(GoodControler.php) 文件3:(BadControler.php) 文件4:(Application.php) _parsePath();         $this->_getControlerFile();         $this->_getControlerClassname();     }     /*      * 解析当前的访问路径,得到要进行动作      */     function _parsePath(){      list($path, $param) = explode("?", $_SERVER["REQUEST_URI"]);         $pos = strrpos($path, "/");         $this->action = substr($path, $pos+1);     }     /*      * 通过动作$action,解析得到该$action要用到的controler文件的路径      */     function _getControlerFile(){      $this->controlerFile = "./Controler/".$this->action."Controler.php";         if(!file_exists($this->controlerFile))          die("Controler文件名(".$this->controlerFile.")解析错误");         require_once $this->controlerFile;     }     /*      * 通过动作$action,解析得到该$action要用到的controler类名      */     function _getControlerClassname(){         $this->controlerClass = $this->action."Controler";         if(!class_exists($this->controlerClass))          die("Controler类名(".$this->controlerClass.")解析错误");     }     /*      * 调用controler,执行controler的动作      */     function go(){         $c = new $this->controlerClass();         $c->control();     } } ?> 用PHP开始你的MVC (二)抽象数据库接口 二、抽象数据库接口(利用数据操作管理类) 在用mvc模式开发的时候,model层负责数据库的所有操作,为了对数据库的操作进行统一的管理,我们需要定义一个数据库操作管理类,由他来接替所有的数据库操作,也就是整个系统中只有这个数据库操作管理类,可以直接对数据库进行操作,如果其他的类需要对数据库进行操作,那它就必须调用和通过这个类来实现。 下面的Db类就是一个这样的类。 getSeq('art_id', 2, 1);  *    ?>  */ /*  * example 2:  分页查询  *    1, "name"=>"this is name");     var $data;     //这个实体类的数据约束信息,用来判断加入的$data数据的准确性     //see: ClassModel     var $match;     //与该实体对应的数据库中表的名称     var $table;     //初始化     function Model(&$data){         $this->data = &$data;     }     //设置该实体的某个数据是值     function set($key, $value){         $this->data[$key] = $value;     }     //获取该实体的某个数据     function get($key){         return $this->data[$key];     }     //获取该实体的全部数据     function getData(){      return $this->data;     }     //获取该实体的约束信息     function getMatch(){      return $this->match;     }     //验证实体数据的准确性和完整性     function isValid(){         foreach($this->match as $key=>$value){             if(!isset($value["null"]) && !isset($this->data[$key])) die("$key 的数值不能为空");             //.....可以在加其他的判断,例如是否超过如许的最大数值,或长度过长.....         }     } } ?> 文件1:(Manager.php)Model层进行实体管理的基础类 db = new Db();     }     //用来向数据库中插入实体信息     function insert(&$model){      $model->isvalid();         $table = $model->table;         $match = $model->getMatch();         $data = $model->getData();         $str1 = $str2 = array();         foreach($match as $key=>$value){          if(isset($data[$key])){              $str1[] = $key;                 $str2[] = ($value["type"]=="C")? "\"".$data[$key]."\"": $data[$key];             }         }         $sql = "INSERT INTO $table (".implode(",", $str1).") VALUES(".implode(",", $str2).")";         return $this->db->execute($sql);     } } ?> 文件2:(ClassModel.php)班级信息的实体类 true表示是准许为空,否则不能为空)     var $match = array("cls_id" => array("name"=>"cls_id", "type"=>"I"),                        "cls_name" => array("name"=>"cls_name", "type"=>"C"),                        "cls_address" => array("name"=>"cls_address", "type"=>"C", "null"=>true)            );     var $table = "class";     //初始化     function ClassModel(&$data){      parent::Model($data);     }     //用来获取这个班级的学生的信息     function getStudent(){      require_once "./Model/StudentManager.php";         $manager = new StudentManager();         $classId = $this->get("cls_id");         return $manager->getList($classId);     } } ?> 文件3:(StudentModel.php)学生信息的实体类 true表示是准许为空,否则不能为空)     var $match = array("stu_id" => array("name"=>"stu_id", "type"=>"I"),             "stu_clsid" => array("name"=>"stu_clsid", "type"=>"I"),                        "stu_name" => array("name"=>"stu_name", "type"=>"C", "null"=>true)             );     var $table = "student";     //初始化 function StudentModel(&$data){      parent::Model($data);     } } ?> 文件4:(ClassManager.php)班级实体的管理类 db->query($sql);     }     //查找并返回一个班级的实体类     function &findOneModel($id){      $sql = "SELECT * FORM class WHERE cls_id=$id";         $data = $this->db->getOne($sql);         if($data==null) die("该班级不存在!");         require_once "./Model/ClassModel.php";         $model = new ClassModel($data);         return $model;     } } ?> 文件5:(StudentManager.php)学生实体的管理类 db->query($sql);     } } ?> 文件6:(Db.php)数据库联接管理类,用于共享并管理数据的访问。由于这个类涉及的内容不是本章要讨论的内容,所以这个类模拟了“真实的数据库管理类的方法”,借口是和正常的类是一样的,但是接口函数里面的内容是不对的,只是模拟的数据。网上有很多这种类的做法,可以自己到晚上找找,(**另外本系列文章的第二章里也有详细的介绍**)。 con=mysql_connect(********************);...........    }    //执行数据查询语句    function &query($sql){        //$result = mysql_query($sql); ..................        //return $result;        if($sql=="SELECT * FROM student WHERE stu_clsid=2")         return array("0"=>array("stu_id"=>1, "stu_clsid"=>2, "stu_name"=>"student1"),                       "1"=>array("stu_id"=>2, "stu_clsid"=>2, "stu_name"=>"student2")                          );        die("空班级");    }    //获取一条数查询结果    function getOne($sql){        //$result = mysql_query($sql); .............        //return $result[0];        if($sql=="SELECT * FORM class WHERE cls_id=1")         return null;        if($sql=="SELECT * FORM class WHERE cls_id=2")         return array("cls_id"=>2, "cls_name"=>"classname", "cls_address"=>"classaddress");    }    //执行数据库更新/添加/删除语句    function execute($sql){       //mysql_query($sql);       echo "
正在进行插入操作
...
插入操作完成
";       return true;    } } ?> 测试文件一、(ModelTest1.php)(查询班级标号(cls_id)为2的班级的学生的名单) findOneModel($classId); $data = &$model->getStudent(); foreach($data as $value) echo "编号:".$value["stu_id"]." ------ 姓名: ".$value["stu_name"]."
"; ?> 返回的结果是: 编号:1 ------ 姓名: student1 编号:2 ------ 姓名: student2 测试文件二、(ModelTest2.php)(查询班级标号(cls_id)为1的班级的学生的名单) findOneModel($classId); $data = &$model->getStudent(); foreach($data as $value) echo "编号:".$value["stu_id"]." ------ 姓名: ".$value["stu_name"]."
"; ?> 返回的结果是: 该班级不存在! 测试文件三、(ModelTest3.php)(执行数据库的插入工作,向student表添加数据) 3, "stu_clsid"=>2, "stu_name"=>"student3"); require_once "./Model/StudentModel.php"; $model = new StudentModel($data); require_once "./Model/StudentManager.php"; $manager = new StudentManager($data); $result = $manager->insert($model); echo $result? "

插入操作成功

": "

插入操作失败

"; ?> 返回的结果是: 正在进行插入操作 ... 插入操作完成 插入操作成功 测试文件四、(ModelTest4.php)(执行数据库的插入工作,向student表添加数据) 3, "stu_name"=>"student3"); require_once "./Model/StudentModel.php"; $model = new StudentModel($data); require_once "./Model/StudentManager.php"; $manager = new StudentManager($data); $result = $manager->insert($model); echo $result? "

插入操作成功

": "

插入操作失败

"; ?> 返回的结果是: stu_clsid 的数值不能为空 结果分析: StudentModel中"match"的规定stu_clsid的值是不能为空的, 而代码中代码中$data = array("stu_id"=>3, "stu_name"=>"student3"); 缺少stu_clsid的值,因此不能通过数据的完整性校验,抱错. 用PHP开始你的MVC (四)实现View层 MVC模式的view层的主要任务是进行页面的和结果的显示工作,在php的实现过程中,主要是体现为一个模板(使用模板,可以达到php代码和html代码分离的目的,这样代码和页面的维护就方便多了,便于管理和页面的更换,可以真正的划分程序员、美工的分工)的解析过程: 首先,controler层从model层得到数据 其次,controler层将数据交给view层 再次,view层的接口将数据按一定的方式传给模板解析类, 最后,模板解析类将数据解析到模板中,然后显示。 下面是一个具体的实现例子 目录结构 |- ClassRenderTest.php          //测试解析classlist.html |- StudentRenderTest.php        //测试解析studentlist.html |- render / TemplateParser.php  //模板解析类 |- render / Render.php          //解析模板的所有类的基础类 |- render / StudentRender.php   //解析模板studentlist.html的类 |- render / ClassRender.php     //解析模板classlist.html的类 |- template / studentlist.html  //模板文件 |- template / classlist.html    //模板文件 注意: 1、这里模板解析类选用了简单的“TemplateParser.php”,根据个人的需要你可以选用任何一种模板解析类; 2、如果每个模板解析都直接调用“TemplateParser.php”,可能会有大量的重复代码出现,这是oo思想所不准许出现的。因此采用“Render.php”对它进行包装,然后再对“Render.php”里面的Render类进行扩展,来对不同文件模板进行解析; 3、不同的模板解析类的,使用的方法是不同的,他们的包装方式也可能不同。 4、“StudentRender.php”“ClassRender.php”就是包装过的Render类,分别用来满足解析“studentlist.html”“classlist.html”的需要。 文件1:classlist.html current time is : _now_ 

current school class list :                                        BEGIN_classlist_                                         END_classlist_
IDNAMEGRADECLASS
_cid__cname__grade__class_
文件2:studentlist.html current time is : _now_ 

current class is :  BEGIN_classinfo_                                         END_classinfo_
class id: _cid_class name: _cname_class grade: _grade_class num: _class_

current class's student :                                BEGIN_studentlist_                                 END_studentlist_
IDNAMESCORE
_sid__sname__score_
文件3:TemplateParser.php 下面的模板解析类是笔者临时写的一个简单的模板解析类,功能很少,没有真正什么使用价值。但是在这里可以满足这篇文章讲解的需要。 同时,如果以前没有接触过模板解析,对模板解析的实现方法有一定疑问的同僚,可以研究一下这个简单类实现解析的方式,代码挺简单的应该能看懂的。 这个解析类有自己的模板结构,“块”(要进行循环显示的地方)的定义如下:   BEGIN_你的块名_    ......html代码.......  _你的块里面的变量的名称_    ......html代码.......   END_你的块名_ 变量的定义方式如下:    ......html代码.......  _你的块里面的变量的名称_    ......html代码.......  具体的“块”和“变量”的使用参考上面的两个模板 root = $root;     }     /*      * set template file name      */     function loadTemplateFile($tplFile){         $this->tpl = $tplFile;     }     /*      * set global var value;      *      * @param $varName  global var name      * @param $data     var's value      */     function setData($varName, $data){         $this->data['__ALL__'][$varName] = $data;     }     /*      * set global var value;      *      * @param $blockName  template block name      * @param $data       var value      * @param $rec        var value      */     function setBlockData($blockName, &$data, $rec=false){  $this->data[$blockName] = &$data;         $this->rec[$blockName] = $rec;     }     /*      * parse template action      */     function parse(){         $tplstr = file_get_contents("{$this->root}/{$this->tpl}");         foreach($this->data as $block=>$value){             $tag = "|BEGIN_{$block}_(.*)END_{$block}_|sm";             preg_match($tag, $tplstr, $tmpdata);             if($tmpdata[1]!=null){              $tmpstr = '';              if($this->rec[$block]){                      foreach($value as $subValue)                       $tmpstr .= $this->_parseBlock($tmpdata[1], $subValue);                 }else{                     $tmpstr .= $this->_parseBlock($tmpdata[1], $value);                 }             }             $tplstr = preg_replace("|BEGIN_{$block}_(.*)END_{$block}_|sm", $tmpstr, $tplstr);         }         $tplstr = $this->_parseBlock($tplstr, $this->data['__ALL__']);         $this->result = $tplstr;     }     /*      * parse block      *      * @param $str     string   one block string      * @param $data    array    data for parse      */     function _parseBlock($str, $data){         foreach($data as $key=>$value){          $keys[] = "_{$key}_";             $values[] = "$value";         }         return str_replace($keys, $values, $str);     }     /*      * return parse result      */     function get(){  return $this->result;     }     /*      * show parse result      */     function show(){  echo $this->result;     } } ?> 文件4:Render.php parser = new TemplateParser($root);         $this->parser->loadTemplateFile($tplFile);     }     /*   * add data to template parser      *      * @param $data array() data for parse   */     function initData(&$data){         return ;     }     /*   * show template parse result   */     function show(){      $this->parser->parse();         $this->parser->show();     } } ?> 文件5:StudentRender.php parser->setData('now', date('Y-m-d H:i:s'));         $this->parser->setBlockData('classinfo', $data['class'], false);         $this->parser->setBlockData('studentlist', $data['student'], true);     } } ?> 文件6:ClassRender.php parser->setData('now', date('Y-m-d H:i:s'));         $this->parser->setBlockData('classlist', &$data['class'], true);     } } ?>   -------------------------------------------------- 下面两个是测试文件,第一个比较简单一些 -------------------------------------------------- 测试文件1:ClassRenderTest.php array('1'=>array('cid'=>1, 'cname'=>'class one',   'grade'=>3, 'class'=>1),         '2'=>array('cid'=>2, 'cname'=>'class two',   'grade'=>3, 'class'=>2),                              '3'=>array('cid'=>3, 'cname'=>'class three', 'grade'=>4, 'class'=>1),                              '4'=>array('cid'=>4, 'cname'=>'class four',  'grade'=>4, 'class'=>2),                              '5'=>array('cid'=>5, 'cname'=>'class five',  'grade'=>5, 'class'=>1))); /*  * do template parse  */ doRender($data); /*  * may see as controler's action, use to parse template  */ function doRender(&$data){  $render = new ClassRender();  $render->initData($data);  $render->show(); } ?> 运行结果: current time is : 2004-05-10 23:51:26 

current school class list :                                                                                                                                                                                                                          
IDNAMEGRADECLASS
1class one31
2class two32
3class three41
4class four42
5class five51
测试文件2:StudentRenderTest.php array('cid'=>1, 'cname'=>'class one', 'grade'=>3, 'class'=>1),        'student'=>array('1'=>array('sid'=>1, 'sname'=>'stu one',   'score'=>100),           '2'=>array('sid'=>2, 'sname'=>'stu two',   'score'=>90),                                '3'=>array('sid'=>3, 'sname'=>'stu three', 'score'=>80),                                '4'=>array('sid'=>4, 'sname'=>'stu four',  'score'=>95),                                '5'=>array('sid'=>5, 'sname'=>'stu five',  'score'=>55))); /*  * do template parse  */ doRender($data); /*  * may see as controler's action, use to parse template  */ function doRender(&$data){  $render = new StudentRender();  $render->initData($data);  $render->show(); } ?> 运行结果: current time is : 2004-05-10 23:52:22 

current class is :                                    
class id: 1class name: class oneclass grade: 3class num: 1

current class's student :                                                                                                                                                                          
IDNAMESCORE
1stu one100
2stu two90
3stu three80
4stu four95
5stu five55
php.MVC系列教程之安装配置 php.MVC必须安装在PHP v 4.1.0及以上版本的Web服务器上 Windows(Apache 2.0.51+php-4.3.9-Win32) 1.从http://www.apache.org下载相应的Apache版本。 2.从http://www.php.net下载相应的PHP版本。 3.从http://www.phpmvc.net下载相应的php.MVC版本。 4.建立目录c:\www作为Web服务器目录,c:\webapp作为Web根目录, 你也可以定义自己的目录,以下作相应的修改即可。 5.将Apache安装到c:\www,打开浏览器,在地址栏输入http://localhost测试是否安装成功 注意:如果你的系统上已经安装有其他Web服务器(如IIS 5),且占用了80端口,请先停止该服务器。 6.把PHP压缩包解压到c:\www。 7.将c:\www\php-4.3.9-Win32目录下php.ini-dist拷贝到系统目录如c:\winnt中并更名为php.ini, 将php4ts.dll拷贝到系统目录如c:\winnt\system32中,打开c:\www\Apache Group\Apache2\conf目录下http.conf文件, 在ScriptAlias /cgi-bin/ "c:/www/Apache Group/Apache2/cgi-bin/"下加入 ScriptAlias /php/ "c:/www/php-4.3.9-Win32/" AddType application/x-httpd-php .php Action application/x-httpd-php "/php/php.exe" 并将DocumentRoot "c:\www\Apache Group\Apache2\htdocs"改为DocumentRoot "c:/webapp" 8.把php.MVC压缩包解压到c:\webapp 9.打开c:\webapp\phpmvc目录下Main.php文件,修改如下内容 // Set php.MVC library root directory $appServerRootDir = 'c:\webapp\phpmvc'; // no trailing slash // Set the application path $moduleRootDir    = 'c:\webapp\phpmvc'; // no trailing slash // Set the OS Type [Optional] [UNIX|WINDOWS|MAC] if we have // trouble detecting the server OS type. Eg: path errors. $osType = 'WINDOWS'; 确认c:\webapp\phpmvc\WEB-INF目录下phpmvc-config.data有可写权限。 打开浏览器,在地址栏输入http://localhost/phpmvc/Main.php?do=stdLogon测试是否安装成功。 10.要查阅更为详细的安装文档,请看http://www.phpmvc.net/docs/installIdx.php?doc=all。 php.MVC系列教程之框架介绍 一、介绍         php.MVC是一个开放源代码的Web应用框架,实现了模型-视图-控制器(MVC)设计模式,鼓励基于Model2架构的应用程序设计。这种开发模式允许网页或其他显示内容从内部应用程序代码中分离出来,让网页设计者和程序员更容易地集中于他们各自的专业领域。         这个框架提供了一个单独入口点的控制器。这个控制器接受HTTP请求,并根据配置文件分配给相应的动作处理。模型则包含了应用程序的业务逻辑。当请求处理完成,控制器调用相应的显示组件——通常用模板文件来实现。处理结果返回给客户端浏览器,或者通过另外的协议比如SMTP。         php.MVC是用PHP来实现Jakarta Struts框架,目前它支持Struts的许多特性,包括通过XML解析器实现XML与对象的映射,从而设置应用程序的配置参数。比如在XML配置文件中指定各种业务逻辑组件与对应的显示组件之间的映射。                                                                       图1 图1所示的逻辑图描述了框架的高层结构。 可以看出框架包括三个主要的组件:前端控制器、主控制器和动作分配器。 二、优/缺点 优点: 1. php.MVC是一个开源项目能让你完全接触源代码,使开发者能更深入的了解其内部实现机制。 2. 使用php.MVC可以促进模块化开发,促使开发者和设计者的角色分离,提高代码的重用性和可维护性。 3. php.MVC框架的学习可以借鉴Jakarta Struts的一些知识和经验,如果你有开发Struts的经验,那么就可以快速地用php.MVC来进行开发。 4. MVC模式是Java开发Web应用程序的一个设计标准,使用php.MVC框架还有助于Web开发者理解MVC设计模式。 缺点: 1. php.MVC功能仍在不段变化和完善中,你需要随时关注最新版本。 2. 使用php.MVC需要进行额外的学习过程。 3. 应用php.MVC可以得到清晰的程序结构,但也会增加系统复杂度。 4. 应用php.MVC可以让程序更加有条理,但也会降低程序执行速度。 因此你需要根据项目大小、周期、成本,开发人员素质等众多条件来决定是否应用php.MVC框架。 php.MVC系列教程之处理流程         php.MVC框架由许多类组装而成,但是我们不必了解所有类的详细工作过程也可以使用这个框架,图2显示了我们使用该框架需要了解的一些核心组件。                                                                图2         从图2我们可以看到一个典型的Web浏览器的HTTP请求如何与我们应用程序框架的核心类进行交互,然后如何得到HTTP响应返回到Web浏览器。         现在,让我们以一个实例来了解框架的处理流程。比如要查看公司销售报表,先在浏览器地址栏输入 http://www.myhost.com/mycompany/Main.php?do=salesReport 客户端便发送给php.MVC应用程序一个请求。应用程序框架的控制器处理这个请求,分析查询字符串,取出请求路径关键字。在这个实例中,路径为salesReport。后面我们将看到如何通过XML配置文件来配置必需的应用行为,绑定表单验证,业务逻辑处理和显示组件。         如果我们想严格控制只有通过验证的人才能访问这个报表,则用户必须先输入基本的验证信息,通常是用户名和密码。为了限制只有通过了验证的用户才能访问该报表,这里用了一个被称作ActionForm的类,我们需要继承框架的ActionForm来定义自己的表单验证类,比如SalesActionForm,如下所示: class SalesActionForm extends ActionForm { ... }.         在SalesActionForm类里我们要检查用户是否可信任的以决定下一步动作。如果用户没有通过验证,我们将重定向到初始页面要求重新输入;如果他通过了验证,控制器会通过Action类来调用业务处理类。 我们通过继承框架Action类来进行自定义,比如SalesAction,如下所示: class SalesAction extends Action { ... }.         在XML配置文件中我们要定义请求与Action类的对应关系,这样控制器找到相应的Action类,这里调用SalesAction。在SalesAction类里我们能访问业务处理类和数据源。本例中我们从数据库中取得销售数据,制成报表格式。例如:我们创建一些对象,后面在销售报表模板中可以使用这些对象,如下所示:  // Sales report items - per zone (individual object instances):  $item1 = new Item('Northern Zone Sales' , $salesNorth);  $item2 = new Item('Southern Zone Sales' , $salesSouth);  ...           当我们完成了销售报表,就要通过控制器指定显示组件显示出来。这是通过一个在XML配置文件中已经配置好的被称作Forward的对象的来完成,如下所示: return $mapping->findForwardConfig('salesReportSuccess');         Forward对象包含了销售报表模板的路径,比如salesReport.tpl,这也是在配置文件中定义。         然后控制器将请求转向到ActionDispatcher,由它定向到指定的显示组件,在本例中是salesReport.tpl,在模板中通过访问先前定义对象和变量从而得到在SalesAction里准备好的数据。         下面显示我们如何用phpTAL模板系统访问报表数据并生成显示视图,对象$item1我们用类变量$item1->value    ...             ...         最后将处理结果通过HTTP发送到客户端浏览器,从而也就完成了整个处理过程。 php.MVC系列教程之目录文件         现在让我们来分析一个典型的php.MVC Web应用程序的结构。         图3显示了如何布置一个php.MVC应用程序和其核心类库                                                      图3 php.MVC类库         从上图我们可以看到php.MVC类库被安装在服务器的DEV目录下,这个目录用来放置一些通用类库。为了安全起见,该目录不允许Web用户访问,因此最好不要将该目录建立在Web根目录。如果由于某种原因需要将php.MVC类库安装在Web 根目录,那你必须用.htaccess文件来控制其访问对象。         下面显示的是Apache的.htaccess文件 # options the .htaccess files in directories can override.    # Edit apache/conf/httpd.conf to AllowOverride in .htaccess    # AllowOverride AuthConfig # Stop the directory list from being shown   Options -Indexes # Controls who can get stuff from this server.   Order Deny,Allow   Deny from all   Allow from localhost         这将指示Apache服务器                 拒绝所有人访问包含有该.htaccess的目录及其子目录,在本例中是php.MVC类库的/WEB-INF目录下包含的文件及子目录。                 允许从服务器主机可以访问,这允许使用Web 服务器的开发者能够浏览该类库下的测试目录以及执行单元测试。         php.MVC文件不必做任何修改即可正常使用,为了能够访问到类库文件,我们需要在Web应用程序的Main.php文件中设置php.MVC类库根目录,如下所示: $appServerRootDir = 'D:/Dev/PHP/phpmvc-base'; // no trailing slash php.MVC Web应用程序         从图3我们可以看出一个Web应用程序目录SalesReport被放置在Web根目录WWW下。         在SalesReports下的一级目录下我们可以看到几个目录和Main.php文件,art目录用来存放应用图像,style目录用来存放样式表,这两个目录可以通过Web访问,并且可以根据实际需要重新命名,我们能够在模板文件中访问这些资源,如下所示:         接下来是WEB-INF目录,该目录存放应用类和资源。它不能通过Web访问,这是通过.htaccess文件来实现的。开发者可以在该目录下自由创建目录及子目录,但需要在WEB-INF目录下的ModulePaths.php中声明。在WEB-INF目录下,class目录用来存放应用类和资源文件,tpl目录用来存放显示资源,比如网页模板。         在WEB-INF目录下还有.htaccess,ModulePaths.php, phpmvc-config.xml, phpmvc-config_1_1.dtd, phpmvc-config.data and prepend.php files。其中.htaccess文件已经在前面讨论过了。         ModulePaths.php文件用来定义指定应用类及资源的路径,我们可以象下面一样定义:  $appDirs   = array();  $appDirs[] = ''; // starting with the sub-application home directory  $appDirs[] = 'WEB-INF';  $appDirs[] = 'WEB-INF/classes';  $appDirs[] = 'WEB-INF/tpl';         phpmvc-config.xml文件是php.MVC应用程序的中心组件,可以通过XML来定义应用程序的行为和属性,在后面将有更为详细的介绍。         phpmvc-config_1_1.dtd文件是phpmvc-config.xml的文档类型定义文件,DTD文件指定了在phpmvc-config.xml文件中可以包含的节点,它是应用程序行为和属性的最终参照。大部分XML编辑器都可以用DTD文件来验证phpmvc-config.xml文件的有效性。         phpmvc-config.data文件包含了应用程序的一些配置数据,这些配置数据是根据phpmvc-config.xml文件的最新信息动态生成的。假如你的应用程序得不到期望结果时,可以在phpmvc-config.xml中增加空格键以修改它,重新运行应用程序时配置数据就会被重新生成。         prepend.php文件常用来包含应用文件,前面,我们已经包含了应用类和模板文件,我们可以用它来包含其他类和资源文件,如下: include_once 'Locale.php'; include_once 'PropertyMessageResources.php';         Main.php就是php.MVC应用程序的那个单一入口点,它被放置在应用程序根目录。所有的请求都需要通过它来完成。         从上面我们可以看出,Main.php文件中必须定义php.MVC类库的路径 $appServerRootDir = 'D:/Dev/PHP/phpmvc-base'; // no trailing slash         接下来我们将指定应用程序路径 $moduleRootDir = 'C:/WWW/SalesReports'; // no trailing slash         我们也可以设置应用程序的ActionDispatcher路径。每个php.MVC应用程序通常都要自定义一个 ActionDispatcher来处理指定的请求,我们需要定义ActionDispatcher变量,如下所示: $actionDispatcher = 'ReportActionDispatcher';         $osType变量用于指定php.MVC所在主机的操作系统类型,通常框架能够自动检测出来并以此来设置应用路径,但是如果你的应用程序运行出现路径错误,请手工设置该变量。如下所示: $osType = 'UNIX';         正常情况下,包含在Main.php中的其它参数可以不做修改。 php.MVC系列教程之对象关系 图4显示了从开发者的角度来看php.MVC示例程序中主要类和资源,以及它们之间的关系。                                                                图4 在上图左上角是ActionForm类,我们通过继承它来处理HTML表单验证和与之相关的功能。示例中通过继承ActionForm定义了一个基类AbstractBaseForm,它包含一些通用的逻辑,可以为更多的应用程序ActionForm类所引用,比如SalesReportForm类就具体实现了AbstractBaseForm类。 在上图上方是Action类,通常用来处理通过ActionForm类完成了初始化验证的请求。我们再次看到了继承Action定义的基类AbstractBaseAction,SalesReportAction类继承AbstractBaseAction用来处理请求,在SalesReportAction类中我们能调用业务逻辑类ReportBusinessClass,访问数据库和其他资源。 在上图下方是ActionDispatcher类,负责为Action请求准备显示资源如网页模板。通常,我们需要继承框架ActionDispatcher类来定义自己的Dispatcher,比如示例中的ReportActionDispatcher。 在后面我们将有更为详细的介绍 php.MVC系列教程之控制器         控制器(Controller)由一些类组成,根据预先定义的配置选项处理用户请求。一个典型的用户请求如下: http://www.myhost.com/mycompany/Main.php?do=salesReport.         php.MVC 控制器由两部分组成:前端控制器和控制器。当请求到来时,前端控制器负责安装应用程序,控制器则根据phpmvc-config.xml的配置属性处理请求。         图6显示了前端控制器的主要任务。                                                                            图6         用户请求被Main.php文件接收,这里,将设置一些初始化参数。前端控制器将执行以下任务: · 定义应用程序路径:这将指定php.MVC类库以及Web应用程序的路径,如下: $appServerRootDir = 'C:/WWW/phpmvc-base'; $moduleRootDir    = 'C:/WWW/mycompany'; · 定义应用程序的ActionDispatcher:我们通常需要扩展框架ActionDispatcher来定义自己的Dispatcher类: $actionDispatcher = 'MyActionDispatcher'; · 初始化应用程序类路径:为了将类和资源装入,前端控制器将导入预先定义的全局路径以及应用程序路径。我们可以在/WEB-INF/ModulePaths.php中设置路径,如下: $appDirs = array(); ... $appDirs = 'WEB-INF/report_tpl'; $appDirs = 'WEB-INF/report_classes'; · 包含应用程序类:前端控制器将导入它所需要的类文件,我们也可以用/WEB-INF/prepend.php文件来有选择性地导入一些特殊的应用程序类文件。如下: include_once './WEB-INF/mytools/MyTools.php'; · 配置应用程序:前端控制器将为应用程序设置配置信息,比如我们先前定义的ActionDispatcher。 · 初始化控制器:前端控制器现在将创建一个应用服务器实例(ActionServer)。 · 导入配置信息:前端控制器现在将导入应用程序配置信息,假如phpmvc-config.xml从最后一次请求后被修改了,phpmvc-config.xml文件将被重新处理并将数据缓存到/WEB-INF/phpmvc-config.data中。 · 初始化HTTP请求:前端控制器现在将设置HTTP请求并添加请求属性。 · 调用应用程序控制器:前端控制器现在已经完成了准备工作,将会把处理权交给控制器。         控制器接收从前端控制器传来的请求,根据配置属性执行一系列操作。         图7描述了php.MVC控制器的任务。                                                                   图7 · 处理action路径:控制器将根据请求路径识别出关键字,选择一个action映射。比如请求路径为: http://www.myhost.com/mycompany/Main.php?do=salesReport, action路径就为salesReport。 · 处理现场:根据需要为当前用户选择一个Locale · 处理内容格式:根据需要设置内容格式,默认为text/html。 · 处理不缓存:根据需要设置不缓存头信息,默认为: "Pragma", "No-cache" "Cache-Control", "no-cache" "Expires", 1 · 处理预处理任务:可以在自定义的ActionServer子类中覆盖这个方法,执行一些指定的预处理任务。 · 处理Action映射:控制器将根据请求识别action映射,根据phpmvc-config.xml的相应节点生成action映射对象(ActionConfig),比如:。 · 处理角色:检查能执行这个action的所有必须的认证。 · 处理ActionForm:控制器将根据action映射找到相关联的ActionForm,form-bean就是由action的name属性指定,比如: 。 · 处理Populate:根据请求参数设置ActionForm实例的属性。 · 验证ActionForm:根据action的validate属性值如:,决定是否调用ActionForm的validate()方法。如果validate()返回False(验证失败),控制器将用action中input属性所指定的显示资源(模板)显示错误,比如:            假如validate()返回True(验证通过),则将继续处理。处理Forward:控制器检查forward映射的URI是否正常,如果是,继续处理。 · 处理Include:控制器检查include映射的URI是否正常,如果是,继续处理。 · 处理Action创建:控制器将创建或获取Action实例来处理这个请求,这是用action的type属性来定义的,比如:            execute(...)。在该方法内,我们将调用业务处理逻辑类。 · 处理Action链:控制器将检查是否还有另外一个Action需要处理,在应用程序配置文件中,我们通过ActionChain能定义一系列Action,为了定义ActionChain,需要为action节点的forward元素添加一个nextActionPath属性,比如:                 ... · forward元素的path属性是必须项,假如这个特殊的Action没有输出,我们可以设置path = ""。 · 处理Action Forward:控制器将转发或重定向到指定的资源,一个forward请求在当前处理器中被处理。RequestProcessor只是把控制权交给ActionDispatcher,那里包含了指定的URI模板。比如:     · 重定向请求实际是发送给客户端浏览器一个标头响应,然后重定向到一个新的URL。在发送重定向标头信息时当前的处理将立即终止。         假如没有其他的Action需要处理,控制器处理结束。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档

            Sales report->value will appear here