原文:使用 CodeIgniter 框架快速开发 PHP 应用(三)
分析网站结构
既然我们已经安装 CI ,我们开始了解它如何工作。
读者已经知道 CI 实现了MVC式样。 通过对目录和文件的内容进行分类, 而不是让代码大块大块地纠集在一起。
这一章,我们将会对 MVC 理论做个简短的介绍, 然后再介绍 CI 的MVC实现方式。特别地,要了解那些目录和文件如何互相交换信息?网站结构是怎样的?以及CI是如何自如地动作于其中的?
这一章将会介绍:
。MVC 如何架构一个动态网站
。CI如何接收和分析request以及如何调配指定的代码来reponse
。这些指定的代码如何编制
。CodeIgniter 语法
。CI提供的各种类和函数,你自己编写的类和函数
。如控向controllers传递URL参数
。如何编写运行良好的视图并把动态内容传递给它们。
。如何返回信息给上网者
。文件和类如何传递信息和互相调用
。助手类文件有什么用?
。有助于网站设计的一些特别提示
MVC-到底有什么用?
MVC,在本文领域内,指的是一个动态网站的组织方法。 设计模式是1979年由挪威人,Trygve Reenskaug首次提出来的,这里是一些概要:
。模型是包含数据的对象,他们与数据库交互,对这些数据进行存取,使其在不同的阶段包含不同的值,不同的值代表了不同的状态,具有特定的含意。
。视图显示模型的状态,他们负责向使用者显示数据。(虽然他们通常是 HMTL 视图, 但是,他们可能是任何形式的接口。 比如PDA屏幕或WAP手机屏幕)
。控制器用来改变模型的状态,他们操作模型,提供动态的数据给视图。
CI框架包含模型、视图和控制器的子目录。 他们里面的每个文件都有.php文件后缀, 包含有特定命名约定的类。
CI 帮助你遵循MVC的约定, 使你更有效地组织代码。 CI允许你有最大的灵活性,你可以获得 MVC 结构的所有好处。
当你编程的時候,试着始终用 MVC 来思考问题。尽可能确保你的 '视图' 聚焦于显示, '控制器'纯粹地用来控制数据流。 把应用逻辑保留在数据模型和数据库中。
这样,如果你决定开发新的视图,你不必在任何一个控制器或模型中修改代码。 如果你需要更新 '商业规则' ,你只需要在模型中修改代码。
另一方面,你必须认识到,MVC只是用来帮助你的一种设计方式,而不是用来约束你的。MVC可以有不同的实现方式。CI 论坛包含许多如何 '正确合理'地实现 MVC 的方式。 ( 我应该在控制器部分实现数据库查询功能吗?我能直接从视图发送数据到模型层吗?或者我必须通过控制器来访问?)
与其寻找理论上的正确方式,不如遵循二项有用的原则。 这些在 CI 用户手册上有相关描述:
。松藕合: 类之间尽可能不要彼此依赖。
。组件智能化: 智能化是组件独立实现特定目标的能力。在 CI框架中,每个类和它内部的函数高度地自治。
这些是Rick开发CI要实现的目标, 他们也会成为你开发你自己的网站时的目标。实现这些目标之后,你代码中使用这些类时就不需要担心有什么副作用了。
CI做到了这一点,我的经验是那助手类和类库中的其它类使用用起来十分容易,工作起来效果也不错。
因此, 如果你的控制器直接操作数据库, 或你的在模型层调用视图, CI 代码将会以适当的方式工作-通常没有技术上的问题-但是从MVC理论来看这样似乎是 '不正确的'. 不要烦恼,如果非要这样做,做吧!
CI 的网站结构: 控制器和视图
你的整个 CI 网站是动态的。 就是, 可能找不到制作 '静态' 网页的简单的 HTML 代码。 (如果需要你可以添加,但是他们将会在 CI 结构之外.) 那么, 你的网站文件到底在哪里?
当我们安装 CI 的时候,我们注意到应用目录包括名为models、views和controllers的子目录。 每个 CI 框架应用都包含这三大类型。
让我们看看内部细节。
再次强调我们并不处理静态网页和对应的URL,我们将会给你看CI如何分析URL请求和如何响应它。 首先,考虑一个正常的英特网请求。用户建立一个连接到你的网站: www.example.com,
然后经过端口发出一个如下的HTTP request:
GET /folder/file.html HTTP/1.0
GET是请求的类型, HTTP/1.0 指定 HTTP 协议的版本, 中间是相对路径和文件名。但是在你的网站上,找不到简单的静态 HTML 文件。取代它的,所有的收入请求被 index.php 文件拦截并进行处理。
如果使用者正在以正确的URL在你的网站上位置上请求页面-一般是通过点击你网页上的超级链接-request一般看起来象这样:
GET /index.php/tests/showall HTTP/1.0
如果使用者不知道精确的URL, CI 会设定一个默认页面(我们一会儿就告诉你怎么做.)
CI的处理步骤是:
+--------------------------------+
| internet request comes in: |
| "GET http://127.0.0.1" |
+--------------------------------+
|
v
+--------------------------------+
| Router:decides which controller|
| should handle this request |
+--------------------------------+
|
v
+--------------------------------+ +-------------------+
| Controller: analyzes the | -----> | |
| request and responds:maybe | |Model:provides data|
| by getting data from the model | >----- | |
+--------------------------------+ +-------------------+
|
v
+--------------------------------+
| View:formats the response |
| (in this case as an HTML page) |
+--------------------------------+
|
v
+--------------------------------+
| Page is served up to enquirer |
+--------------------------------+
一个从英特网到你的网站根目录的请求被 index.php 文件拦截,作用就象一个“站由器”。 换句话说, 它调用一个 '控制器', 然后返回一个'视图'.
“路由器”怎么知道调用哪一个控制器? 就象我们已经见到的,有时候request本身包含的信息会告诉它调用哪个控制器。 举例来说,如果请求说:
GET http://127.0.0.1/index.php/welcome/index
并且如果你有一个控制器叫做welcome,这就是被调用的控制器。
welcome控制器
所以, 让我们看welcome控制器。 它被存放在如下路径:
system/application/controllers/welcome.php
它的内容是这样的:
class Welcome extends Controller {
function Welcome() {
parent::Controller();
}
function index() {
$this->load->view('welcome_message');
}
}
?>
复制代码
文件的第二行开始是一个类。 每个控制器从一个Controller类继承。 在类中包含二个函数或称为方法-welcome() 和incex().
注:
CI 要求控制器名字从一个大写字母(class Welcome) 开始, 但文件名是小写字母:
/system/application/controllers/welcome.php。
parent::Controller();
}
复制代码
这三行组成构造函数。 注意到 CI 使用PHP 4 构造函数命名规则,兼容于 PHP 5.-CI在PHP 4 和PHP 5 两个版本中都能工作得很好。构造函数在类实例化时被调用,你可以做一些初始化的工作,比如调用函数库和模型层,或者对类的成员变量进行寝化。
这个例子中构造函数中仅一行,调用父类的构造函数。parent::Controller() 。这只是显式地使用父类功能的一种方法。如果你想要详细地了解CI框架中controller类,你可以研读文件 /system/libraries/controller.php 。
(可以放心的是你可以随时查看CI的源代码,它们已经保存在你机器上的某个目录内。)
让视图开始工作
让我们回到发出request那个部分。 “路由器”需要知道, 除了哪一个控制器应该处理请求, 而且要知道是哪一个控制器里面的哪一个函数。 那是为什么request中还包含了特定的action信息http://127.0.0.1/welcome/index. “index”指示路由器寻找“welcome"控制器里的一个函数"index"。你要确保存在index函数!
来看看index()函数。这个函数只是用CI的装载函数(this->load->view)装入一个视图('welcome_view')。在现阶段,它不对视图任何操作,只是传递给你动态内容。稍后才会执行。
'welcome_view' 在CI中有特定的含义,实际上它指向了如下文件:
system/application/views/welcome_view.php
这个视图文件中只是一些简单的HTML代码,但是因为在稍后运行时CI会向文件里存入PHP编码,因此使用了PHP文件后缀。(如果只是使用简单的静态的HTML不需要修改后缀.)
下面是视图文件中HTML代码示例(作了精简处理):
<head>
<title>Welcome to Code Igniter</title>
<style type=" text/css">
body
{
background-color: #ffffff;
margin: 40 px;
font-family: Lucida Grande, Verdana, Sans-serif;
font-size:14 px;
color: #4F5155;
}
.....more style information here
</style>
</head>
<body>
<h1> Welcome to Code Igniter!</h1>
<p>The page you are looking at is being generated dynamically by Code Igniter.</p>
<p>If you would like to edit this page you'll find it located at:</p>
<code>system/application/views/welcome_message.php</code>
<p>If you are exploring Code Igniter for the very first time, you should start by reading the :<a href="user_guide/">User Guide</a>.</p>
</body>
</html>
复制代码
正如你见到的,它完全由 HTML 组成,内置CSS定义。在这个简单的例子中,控制器还没有传送任何的变量到视图中。
默认的控制器
前面提到,如果在request中没有指明具体的控制器和action, CI 将会把页面重定向到一个系统默认的页面。这个默认页面可以自己设定,它存放在如下地址:
/system/application/config/routes
该文件中包含下列设置:
$route['default_controller']="welcome";
如果你不在此设定默认值, 没有明确URL的request会转到 '404not found'页面。
上述config文件,默认值是重定向到welcome controller。
如果没有指定函数,/index会被默认选中。因此确定你包括一个index()函数, 如果只是要避免显示 '404' 页面,请确保包括index()函数。
你可以根据需要修改此设置,你还可以修改一个函数叫做_remap($function),其中$function是你要重定向的控制器。_remap总是先被调用,不管URL是什么内容。
CodeIgniter 语法规则
在我们开始学习之前,让我们简单地规纳一下 CI 的语法规则。 框架希望文件和目录按一定的规则设置,否则它可能无法准确地定位和使用它们。
控制器
这是一个类(也就是OO代码) 它由URL直接调用,例如:
'www.example.com/index.php/start/hello'
控制器使用函数名称来调用函数,如:
mainpage();
不过,你不能够在一个控制器内调用其它控制器内的函数。
定义:
控制器开始用如下格式定义:
class Start extends controller
控制器的名称的首字母必须大写, 而且被保存为.php文件,位于如下路径:
/system/application/controllers
文件名称的首字母不需要大写,应该是start.php而不是Start.php. 还有,在构造函数中至少要有如下构造方式:
function display()
{parent::Controller();}
所有的其他代码一定要写在不同的函数当中(这不是CI的规定,而是PHP的规定)。
视图
视图是包含 HTML 代码的,带有.php后缀的文件。 使用如下命令装载:
$this->load->view('testview',$data);
这条命令载入视图。使用时还要使用别外的方法。
语法: 视图用HTML编写,PHP 代码包含在 <?ph p?>标记中,在view目录中保存为后缀为.php的文件。
在 CI 框架开发的网站上的文件或类的类型介绍
application目录中有一些不同的子目录。 我们已经看过controller、 config 和views目录。
但是什么是libraries, models和scripts? 这是 CI 目录中似乎让人相当困惑的一个区域。 (如果你已经用过 1.5 版前的 CI 的版本, 你将会了解为什么。 Rick Ellis对较早的版本感到不满意, 并且已经大幅度修改了结构。因此,为了向前兼容,一些目录结构必须保留。)
从技术角度看,这些文件夹被平等地对待。你为什么要把代码放在这个目录而不是那个目录是没有什么理由好讲,这就是一种约定。
这样讲吧,假定你已经写了一段代码并命名为display, 里面包含一个函数叫做mainpage。有四种方法你可以实现: 一个model, 一个library,一个助手类或一个插件。下列的表格列举了你如何装载和使用每一种方法:
文件类型 如何使用
model 是一个类(面向对象代码)
装载方法:$this->load->model('display');
使用方法:$this->display->mainpage();
如何定义:
必须以如下格式开始:class Display extends Model
必须包含构造函数和构造语句:
function display() {
parent::Model();
}
必须包含一个mainpage()函数
概念性总结:用户手册这样描述:“Models是设计用来表示数据库中信息的PHP类。”
library 存放在application和system目录中。
也是一个类(注意:你自己的类库不会自动地包含在CI超类中,因此你必须用不同的方法来词用,详见第七章)
装载方法:$this->load->library('display');
使用方法:$this->display->mainpage();
如何中定义:
不需要从父类继承,不一定需要构造函数。
这样足够了:
chass Display() {
function mainpage() {
// code here
}
}
概念性总结:如果你想扩充CI的功能,或者创建特别的功能可以使用library
helper 可以保存在system/helpers或application/helpers目录中 。是一段脚本(过程式代码,不是类)
装载方法:$this->load->helper('display');
使用方法:直接调用,如:mainpage();
如何定义:
文件必须被保存为,如:display_helper.php
(文件名必须加上_helper)
mainpage()必须作为一个函数包含在这个文件中,整个文件就是一过程式函数的集合。因此你不可以在这个文件的函数中调用CI的其它资源。
概念性总结:helper是用来适度帮助你实现特定目的的低级函数。
plug-in 保存在system/plugins目录中,也可以保存在
application/plugins目录中
是一段脚本(不是类)
装载方法:$this->plugin('display');
使用方法:直接调用,如:mainpage();
如何定义:
保存在如下格式的文件中:display_pi.php
文件名中必须加上_pi
mainpage()必须作为一个函数包含在这个文件中,整个文件就是一过程式函数的集合。因此你不可以在这个文件的函数中调用CI的其它资源。
概念性总结:用户手册如此写道:“...plug-in和helper的最大不同就是plug-in通常用来提供一个单一的函数,helper是一个函数的集合...plug-in一般用于社区内互相分享代码。”。(详见第十五章:一个插件的例子)
你可以*地选择使用这四种方式中的任一种或几种,当然,如果你选择model和library的话必须使用OO编程方式。helper和plug-in必须使用过程编程方式。后者不能够直接引用其他的 CI 类。 另外,不同目录的区别主要是由CI框架设定的。
你应该注意到 CI 有二组helpers,plug-in和libraries,而models只有一组,前三种一组放在application目录中,另一组放在system目录中,这两组的区别主要也是CI框架设定的。
。 那些在system目录中代码是CI的核心代码,所有的项目都会使用。如果你升级到一个新的CI版本,这些文件会被修改。
。 当你装载一个helper, plug-in或library, CI会在两个目录中查找,比如你要装载一个类叫做display, CI会先杳找system/application/libraries目录。如果这个目录中不存在,CI会寻找system/libraries目录。
。这意味着可以通过把同名的文件放入applications目录来取代CI核心库的libries, helpers, 和plug-ins。不要轻易尝试这样做。因为这种高度的灵活性需要你使用CI的经验足够多。如果你想扩充CI基本类和脚本的功能,请参考第十三章。
文件夹的含义?
在对系统各目录进行了一番介绍后,我们通过下表来总结一下各目录的作用。
application config 存放配置文件:包含网站的基本配置信息
controllers 控制器
errors 包含出错信息页,你不必修改这个目录
hooks 首次安装时为空,用来存放你创建的钩子。钩子是
用来装载其它文件的控制方法
libraries 代码库,针对本项目的专用代码
models 代码库,本项目的模型层文件
views 存放视图的模板目录
cache 第一次安装时为空,如果你打开缓存设置(详见第十章),这个目录存放 缓存数据
codeigniter 组成CI框架的文件
database CI框架的数据库类的类库文件
fonts 没有在用户手册中介绍,存放水印图像使用的字体
helpers "系统级"助手类
language 你可以存放你本国语言的键名列表-详见11章
libraries “系统级”类库
logs 如果你打开系统错误日志,日志文件默认保存在这个目录
plugins 更多的系统级代码文件
scaffolding "系统级"类库,实现简单的“脚手架”功能
设计良好的视图
在现阶段,你可能问我们为什么要这么努力去为一个简单的HTML页面服务?为什么不把所有的东西放在一个文件里?对一个简单的网站来说,这个观点是对的,但是现在谁还听得到简单的网站?CI框架中最酷的一点就是它能够始终保持内部结构一致,展开良好,易于维护。
一开始,我们需要三个相同的步骤:
。 写一个视图view
。 写一个stylesheet
。 更新我们的 config 文件指定 stylesheet 在哪里
在这三点做完之后,我们需要更新我们的控制器接受从URL传来的叁数,把变量传给视图。
首先,让我们重新设计我们的视野并把它保存至如下路径:
system/application/views/testview.php
<head>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0
Strict//EN'http:// [url]www.w3.org/TR/xhtml[/url] 1/DTD/xhtml-strict.dtd'>
<html xmlns='http:// www.w 3.org/1999/xhtml'>
<title>Web test Site</title>
<base href=<?php echo "$base"; ?>>
<link rel="stylesheet" type=" text/css" href="<?php echo
"$base/$css";?>">
</head>
<body>
<h1><?php echo $mytitle; ?></h1>
<p class='test'><?php echo $mytext; ?></p>
</body>
</html>
复制代码
它基本上仍然是 HTML, 但是注意<?php ?>标记中间的PHP代码。
你将会注意到有一个PHP代码片断存放在stylesheet中,它指定一个系统的CSS文件存放在网站的根文件夹中,让我们保存一个简单的 stylesheet 文件,名为 mystyles.css 。 它很简单:
margin: 5 px;
padding-left: 10 px;
padding-right: 10 px;
background: #ffffff;
color: blue;
width: 100%;
font-size: 36 px;
}
.test{
margin: 5 px;
padding-left: 10 px;
padding-right: 10 px;
background: #ffffff;
color: red;
width: 100%;
font-size: 36 px;
}
复制代码
这给了我们二种风格可以选择, 而且你将会在视图中会用到它们。
首先,让我们在config 文件加入:
$config['css']=" mystyles.css";
这只是将告诉网站我们刚才编写的 CSS 文件的文件名称和位置
但是注意 stylesheet 的实际位置是 $base/$css-从哪里获取变量 $base和 $css的内容呢?你还可以联想到,变量 $mytitle 和 $mytext 的内容呢? 答案是我们需要一个新的控制器!
设计一个工作良好的控制器
现在,我们需要一个新的控制器。 我们将其命名为Start并且保存在
/system/application/controllers/start.php
这一个控制器必须做几件事情:
。调用视图
。将基本URL信息和刚编写的css文件的名称传递给视图
。把另一些数据传递给视图: 它正在期待名称 ($mytitle) 和一些本文 ($mytext)
。最后, 我们想要控制器接受来自使用者的一个叁数 (经由URL request)
换句话说,我们必须在先对视图中的变量赋值。 因此让我们从我们的Start控制器开始。 这是一个 OO 类:
<?php
class Start extends Controller {
var $base;
var $css;
在这里请注意,我们已经声明了变量(或叫做类属性) $base (网站的根地址), 和 $css(css 文件名)。 如果我们在每个类中要编写超过一个函数,这样做会很方便。你也可以把它们定义为一个函数内的变量,如果你硬要这么做也可以。
构造函数现在可以通过查找config文件来定义我们刚声明的变量了。要实现这个功能,我们可以做如下定义:
$this->config->item('name_of_config_variable');
当做在:
parent::Controller();
$this->base = $this->config->item('base_url');
$this->css = $this->config->item('css');
}
复制代码
CI 会 config 文件中读取相关的设置内容。
使用这一机制、不管我们编写多少个控制器和函数,如果我们的网站访问量很大,我们需要搬迁服务器的话,也只要一次就可以改变这些参数。
把叁数传给一个函数
现在,在Start控制器类里面,让我们定义将会实际上做工作的函数。
$data['css']=$this->css;
$data['base']=$this->base;
$data['mytitle']='Welcome to this site';
$data['mytext']="Hello, $name, now we're getting dynamic!";
$this->load->view('testview',$data);
}
复制代码
这函数期待一个叁数, $name,(但是你能设定一个默认值-myfunction($myvariable=0)), 通常会把一个字符串赋给$mytext变量。好吧, 我们现在要问一个问题,$name变量来自哪里?
在这个例子中,它需要来自URL request的第三个参数。因此, 它由 HTTP request提供:
GET /index.php/start/hello/fred HTTP/1.0
或换句话说, 当你在地址栏输入:
http://www.mysite.com/index.php/start/hello/fred
注意这一个例子中代码不 '干净地' 传递了变量fred, 没有用任何方式检查它。 你需要在编程时对它进行检查。 我们将会在第 7 章学习到如何检查输入。 通常,参数必须在检查后确保没有问题再传递给控制器。 如果不检查的话,一个不怀好意的用户可以容易地侵入系统, 他可以发送这样一个URL如: http://www.mysite.com/index.php/ ... malicious_variable. 所以, 你应该检查接收的变量,确保它们符合要求再进行处理。
网址的最后一个片段作为一个参数被传给函数。事实上,你能增加更多的参数,但不能超过你所使用的浏览器的设置。
让我们总结下CI处理URL具体细节:
URL片段 用途
http://www.mysite.com 定位你网站的基本URL
/index.php 定位CI路由器并读取URL的其它部分,分析后定们到相关网 页
/Start CI将调用的控制器的名称(如果没有设置控制器名称,CI将 调用你在config文件中设置的默认控制器)
/hello CI将调用的函数的名称,位于所调用的控制器内。(如果不 存在该函数,默认调用的是index函数,除非你使用
_remap)
/fred CI把这个作为传递给函数的变量
如果还有/... CI把更多的参数作为变量传递给函数
传递数据到视图
让我们回去再看一下hello函数:
$data['css']=$this->css;
$data['base']=$this->base;
$data['mytitle']='Welcome to this site';
$data['mytext']="Hello, $name, now we're getting dynamic!";
$this->load->view('testview',$data);
}
复制代码
注意hello() 函数如何首先设置一个名为 $data的数组, 并把一些对象的属性及文本读入数组。
然后它通过名称装载视图, 并把刚生成的$data数组作为第二个参数。
在幕后, CI 很好地利用了另外一个 PHP 函数: extract(),这个函数的作用是把数组中元素取出放入变量表,其中每个键值对中的键名即为变量名,对应该键名的值为变量的值。因此我们刚才定义的 $data 数组在视图中转换成一个一个单一的变量:$text (包含 " Hello, $name, now we're getting dynamic ") , $css(包含来自 config 文件的设置值), 等等。
换句话说,当它被建立时的时候, $data数组看起来像这样:
Array (
[css]=> mystyles.css
[base]=> http://127.0.0.1/packt
[mytitle]=> Welcome to this site
[mytext]=> Hello, fred, we're getting dynamic!
)
但是当它被传递给视图的途中,它被解开,而且下列的变量在视图对象中被生成,与$data的每个键/值相对应:
$css = 'mystyles.css';
$base = 'http://127.0.0.1/packt';
$mytitle = 'Welcome to this Site';
$mytext = 'Hello, fred, we're getting dynamic!';
)
虽然你只传送一个变量到视图中, 但是,你能把许多数据装进那一个变量。$data数组的每个值还可是数组,这被称为多维数组,因此,用一个数组变量可以把大量的变量传递给视图,这是一个很好的编程技巧。
现在对
http://127.0.0.1/packt/index.php/index/start/fred
(注意:这个网址跟以前的不同-它要求在index控制器中寻找start函数,并把参数“fred”传递给该函数),你可以看到如何使用 MVC 框架构建动态网站。 (当然, 到目前至少是 VC,因为我们还没有介绍 M 。)
键入上述网址,你可以在济览器中出来了对应的页面。
你可以看到参数fred是URL的最后一个部分,并被传递给函数,再经由函数传给了视图。
请记住你的视图一定要与你的控制器相对应。 如果视图中并未为一个变量安排显示的位置,它将不被显示。如果视图正在期待一个变量,而这个变量并没有在控制器中被声明并赋值,你可能收到一个错误信息。(当然,如果变量被声明,则不会有错误信息,但它不会正常显示。)
CI 框架中的类彼此之间如何操控
当你编写你的控制器、模型时,你将会需要在他们之间进行互操作并传递数据。 让我们看看如何实现这些功能。
调用视图
我们已经见到控制器如何调用视图并传递数据给它:
首先它产生数组 ($data) 传给视图; 然后它装载而且调用视图:
$this->load->view('testview',$data);
直接地调用函数
如果你想要使用来自libraries、models、plug-ins或helpers的代码, 你必须首先装载他们, 然后按先前我们制作的列表里的方法调用它们。 因此, 如果 'display' 是一个model,而且我想要使用它的 mainpage 功能,我的控制器可能这样调用:
$this->display->mainpage();
如果函数需要叁数,我们能通过如下方式传递:
$this->display->mainpage('parameter1',$parameter2);
与控制器互动
你能调用同一控制器内部的libraries、models、plug-ins或helpers,而且models和libraries也能彼此调用,同plug-ins和helpers一样。
然而, 你不能从一个控制器调用另外一个控制器, 或从一个model或library调用一个控制器。 只有二个方法可以让一个model或者library与一个控制器关联:
首先,它能返回数据。 如果控制器作如下赋值:
$fred=$this->mymodel->myfunction();
而且函数中有return语句返回变量,那么控制器将得到赋给 $fred的值。
其次,你的model或library能产生(而且传递给视图)一个URL。控制器调用相关视图与使用者产生交互。
你不能把URL直接传递给一个model或library。 用户总是与控制器交互, 从不直接面对其它对象-但是你能在控制器里写一个调用函数。 换句话说, 你的视野可能包含一个URL指向一个控制器函数:
echo anchor(start/callmodel, Do something with a model);
通过callmodel函数,调用一个model中的一个函数:
function callmodel() {
$this->load->model(mymodel);
$this->mymodel->myfunction;()
}
其中的原理如下图:
+--------------+
| 用户 |<----------------+
+--------------+ |
| |
v |
+--------------+ +-------------+
| controllers|--------->| views |
+--------------+ +-------------+
| ^ ^
v | |
+----------------------+ |
| models and libraries |-------------+
+----------------------+
^ ^
| |
| |
+--------------+
这个图显示了控件间信息流的走向。
有的是直接的函数调用,如:
$this->mymodel->myfunction;()
models和libraries内部,或者从控制器到视图, 从控制器到libraries或models。 (models也能调用视图, 理论上这样做不是很合适.) 相反方向就不能调用,如:视图等等不能调用控制器。 然而,libraries和models能互相调用。
有的是返回值给调用它的对象,如:
model和libraries能在内部互相传递数据,也能返回值给控制器。 视野不返回值给调用它的控件。
用户可以通过地址栏发出URL request, 也可以通过点击视图上的URL发出request。
一个CI helper的例子: URL helper
下面介绍一个如何使用helper的例子,使用helper能使你的代码更整洁, 更有针对性。
CI的URL helper包含一组帮助你操作URL的函数。你可以像这样装载它:
this->load->helper('url');
然后, 你能用它寻找并返回URL或URL的base部分:
echo site_url;()
echo base_url;()
你也能使用它产生超链接。我们在上一节看到过在start控制器中存取hello函数, 而且把叁数 fred 传递给该函数, 这些都是通过一个网址实现的:
http://www.mysite.com/index.php/start/hello/fred
如果你想要你自己的代码生成一个像这样的URL,你可以使用URL helper实现。 语法是:
echo anchor(start/hello/fred, Say hello to Fred);
这生成一个同样的URL, 而且显示:“Say hello to Fred"。 换句话说,它是等同于:
<a href="http://www.mysite.com/index.php/start/hello/fred">Say hello to Fred</a>
请记住,使用 CI helper有二个好处:
第一, 录入字符较少
第二,URL helper自动在 config 文件中查找网站URL(和index文件名) 这意谓如果你改变你的网站URL,你只需要改变 config 文件一次,你不需要查遍代码修改变化。
URL helper还有其他的有用功能。比如:它能创建'mailto' 超链接。
echo mailto('me@example.com', 'Click Here to Email Me');
和下面的HTML代码等效:
<a href=" mailto:me@example.com">click here to email me</a>
如果你担心机器人从你的网站搜集电子邮件并使用它们发垃圾邮件,用safe_mailto 代替 mailto。屏幕内容相同,并且工作也正常。但是如果检查你的HTML代码,现在变成了复杂的JS代码,机器人也许什么也抓不到。
//<![CDATA[
var l=new Array();
l[0]='>';l[1]='a';l[2]='/
';l[3]='<';
...
for(var i=l.length-1; i>=0; i=i-1){
if (l.substring(0,1)=='|')
document.write("&#"+unescape(l.substring(1))+";");
else document.write(unescape(l));}
//]]>
</script>
复制代码
你, 和你的用户,不需要看到这些代码。 它只是用来迷惑机器人的,以确保你的电子邮件地址的安全。而你只需要增加四个字母和一个下划线: 你用 safe_mailto 代替 mailto, CI框架为你做其它所有的一切。
在URL helper中有一些其它有用函数。请查阅用户手册。
总结一下URL helper符合我们在这一章开始时讨论的话题:
。松藕合: URL helper有一个简单的接口,不依赖调用它的代码。你可以在任何CI框架项目中使用它。许多项目需要许许多多的超链接,你可以使用这个helper一遍一遍地创建它们。
。组件智能化: URL helper只做它要做的事情, 简化对应的编码工作。
如果你要研读URL helper的代码,它们保存在system/application/helpers/
url_helper.php) 你将会见到它是过程式的代码-只是一组函数功能而不是OO类。 它不装载任何其他的 CI 类或helpers。(它本身不是对象,不能这样做)
一个简单的librariy例子: 创建一个菜单
现在让我们看一些在CI框架中实际使用的代码。
举例来说,这里是一个创建三个菜单项的library文件:
class show_menu() {
function show_menu() {
$obj= & get_instance();
$obj->load->helper('url');
$menu = anchor("start/hello/fred","Say hello to Fred
|");
$menu .= anchor("start/hello/bert","Say hello to Bert|");
$menu .= anchor("start/another_function","Do something
else |");
return $menu;
}
}
?>
复制代码
(这时,不要为不寻常的语法担心,如“$obj->” 还有第六行的$this->. 这在第 7 章会详细介绍。)
注意:这些代码是 OO 代码, 在函数 show_menu() 中包含一个简单的类,“menu”。它能存取其他的 CI 类和helper: 在这个例子中,它调用URL helper--我们刚刚介绍过它。
首先,它装载URL helper, 然后它创建一个字符串 ($menu), 包含指向三个控制器和函数的HTML代码,然后它返回 $menu字符串。
你可以在一个控制器里这样调用它:
$mymenu=$this->menu->show_menu();
然后控制器能使用 $menu变量调用视图:
$data['menu'] = $mymenu;
$this->load->view('myview',$data);
这个类生成一个菜单,每个菜单项指向一个新的页面。 正因为这样,我把它保存在:
/system/application/libraries
而不是
/system/libraries
它与URL helper 藕合,并且我可以在任何CI框架构建的网站中使用它。
它还是智能化的,它创建一个菜单,我可以从任何的控制器调用它,显示一个标准菜单。
摘要
MVC 框架已被广泛地用于构建复杂的动态网站。CI 使用它帮助你编写高度可重用的代码。
始终保证代码的'松藕合' 和 '组件智能化', 当你编写你自己的代码时。不要担心你的项目是否严格遵守 MVC 的理论。 关键是理解文件的类型和它们如何彼此交互。然后, 你再确定使用library, model, helper或是plug-in编写代码。
我们已经看了CI框架的文件和目录结构, 你还能研读源代码,并请不要在不是很深入理解CI的动作原理时去修改它们。
config文件中包含网站的基本信息,可以使我们方便地修改信息,有利于我们快速迁移服务器,减少出错的机会。
我们已经见到控制器的基本结构, 而且用构造函烽从config 文件中读取数据并把它存入对象的属性中。我们还动态地把数据从控制器传递给视图。到现在为止, CI框架中的一些重要知识已经学习过了,当我们继续学习时,我们会很清楚这些知识是非常重要的。
同时,我们也学习了CI控件间传递数据的方式,了解这些对你编程是很重要的。
最后,我们分析了两个例子,一个是URL helper, 还有一个是创建菜单的例子。