第04章建立页面的基础知识.docx
《第04章建立页面的基础知识.docx》由会员分享,可在线阅读,更多相关《第04章建立页面的基础知识.docx(13页珍藏版)》请在冰豆网上搜索。
第04章建立页面的基础知识
第4章建立页面的基础知识
很奇怪,每次学习新语言或者框架的第一个例子都是在屏幕上显示"Hello,world!
"。
目前为止所有利用人工智能来实现交谈的尝试的结果都很差,所以电脑能问候整个世界这种想法实在有些古怪。
但是symfony并不比其他程序笨,证据是,你可以用symfony创建一个说"Hello,<你的名字>"的页面。
本章会告诉你如何创建一个模块,也就是一组页面的集合体。
你还将了解到如何建立一个页面,由于MVC,页面由一个动作和一个模板构成。
链接和表单是web交互的基础,你将在这一章了解如何在模板里增加他们,如何用动作处理他们。
建立模块框架
在第二章中我们介绍过,symfony把页面组织成模块。
建立页面之前,你必须先建立一个模块,也就是一个symfony能识别的目录结构的一个空壳。
symfony命令行工具能自动建立模块。
你只需要用symfony命令行工具执行init-module任务并传应用程序名与模块名这两个参数给它就可以了。
在前一章里,你建立了myapp应用程序。
如果要在这个应用程序里增加一个mymodule模块,只需要在命令行下输入下面的命令:
>cd~/myproject
>symfonyinit-modulemyappmymodule
>>dir+~/myproject/apps/myapp/modules/mymodule
>>dir+~/myproject/apps/myapp/modules/mymodule/actions
>>file+~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>>dir+~/myproject/apps/myapp/modules/mymodule/config
>>dir+~/myproject/apps/myapp/modules/mymodule/lib
>>dir+~/myproject/apps/myapp/modules/mymodule/templates
>>file+~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php
>>dir+~/myproject/apps/myapp/modules/mymodule/validate
>>file+~/myproject/test/functional/myapp/mymoduleActionsTest.php
>>tokens~/myproject/test/functional/myapp/mymoduleActionsTest.php
>>tokens~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>>tokens~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php
除了actions/,config/,lib/,templates/,与validate/目录,这条命令只建立了三个文件。
test/目录里的文件与单元测试有关,在第15章之前你都不用管它。
actions.class.php(见例4-1)做了一个到默认模块的成功页面的跳转。
templates/indexSuccess.php文件是空的。
例4-1-默认的自动生成的动作actions/actions.class.php
php
classmymoduleActionsextendssfActions
{
publicfunctionexecuteIndex()
{
$this->forward('default','module');
}
}
NOTE如果你看一下实际的actions.class.php文件,你会注意到除了上面的这几行之外还有其他的内容,包括一些注释。
这是因为symfony推荐使用PHP注释来为你的项目生成文档,所以每个类文件都与phpDocumentor工具(http:
//www.phpdoc.org/)兼容。
symfony为每一个新模块建立一个index动作。
它是由一个execueIndex的方法与一个叫indexSuccess.php的模板组成的。
execute前缀与Success后缀的含义会在第6章与第7章中分别解释。
现在你可以认为这是一种命名习惯。
在浏览器中输入下面的网址就可以看到这个页面(图4-1):
http:
//localhost/myapp_dev.php/mymodule/index
本章不会用到这个默认的index动作,所以你可以把executeIndex()方法从actions.clas.hpp文件中去掉,并把indexSuccess.php文件从templates/目录中删除。
NOTE除了命令行,symfony还提供了其他的建立模块的方法。
其中之一是你自己来建立这些文件与目录。
很多时候,模块中的动作和模板用来处理一个表里面的数据。
由于建立、获取、更新与删除所需的代码往往是一样的,symfony提供一种称之为脚手架(scaffolding)的机制来自动生成一个模块。
这种技术详见第14章。
图4-1-自动生成的默认index页
增加一个页面
symfony里面,页面背后的逻辑放在动作里面,表现放在模板里。
不需要逻辑的页面也需要一个空的动作。
增加一个动作
我们需要一个通过myAction动作来访问"Hello,world!
"的页面。
要建立这个页面,只要在mymyduleActions类里面增加一个executeMyAction方法,如例4-2。
例4-2-增加一个动作就是给动作类增加一个执行方法
php
classmymoduleActionsextendssfActions
{
publicfunctionexecuteMyAction()
{
}
}
动作方法的名字永远是execute``XXX``(),方法名字的第二部分的第一个字母总是大写。
现在,如果你访问下面的网址:
http:
//localhost/myapp_dev.php/mymodule/myAction
symfony会抱怨缺少`myActionSuccess.php'模板。
这很正常;在symfony里,一个页面永远是由一个动作与一个模板组成。
NOTEURL(不是域名)是区分大小写的,symfony也区分大小写(虽然在PHP里方法名不区分大小写)。
这就是说,如果你增加一个executemyaction()方法,或者executeMyaction(),然后你在浏览器里访问myAction,symfony会返回404错误信息。
SIDEBARURL是响应的一部分
symfony包含一个路由系统,这个系统可以把真正的动作名与URL的形式分开来。
这样就可以实现特殊URL格式。
你可以不受文件结构或者请求参数的限制;动作的URL可以是你想要的样子。
例如,请求一个article模块的index动作的URL常常是这样的:
http:
//localhost/myapp_dev.php/article/index?
id=123
这个URL从数据库里面取出指定的文章。
在这个例子里,这篇文章(id=123)是欧洲(europe)栏目里的一篇关于法国金融(financeinFrance)的文章。
但是通过修改routing.yml配置文件,这个URL可以完全改成另外一种直观的形式:
http:
//localhost/articles/europe/france/finance.html
这个URL不仅对搜索引擎更友好,也对用户更有意义,用户可以像使用命令行一样通过在地址栏执行特定的查找,例如:
http:
//localhost/articles/tagged/finance+france+euro
symfony知道如何为用户解析与生成漂亮的URL。
路由系统自动地从一个漂亮的URL中剥离出参数然后传给动作。
它也能格式化回应的超链接使他们看起来更"漂亮"。
这个功能详见第9章。
总之,这意味着应用程序的动作的命名可以和他们的URL不一致,但是动作方法的命名必须与动作名相统一。
动作名说明动作要做的事情,它通常是一个不定式动词(例如show,list,edit等)。
动作名可以隐藏起来不让用户知道,所以请放心的使用动作的名字(例如listByName或者showWithComments)。
这样可以有效地节省注释,另外代码的可读性也大大增强了。
增加一个模板
动作需要一个模板来表现自己。
模板是模块的templates/目录里的一个文件,模板名字由动作名与动作终止组成。
默认的动作终止是"success"也就是成功,所以myAction动作的模板名是myActionSuccess.php。
理想的模板只包含显示代码,所以PHP代码越少越好。
显示"Hello,world!
"的页面的模板可以如同例4-3中的那么简单。
例4-3-mymodule/templates/myActionSuccess.php模板
Hello,world!
如果需要在模板里执行一些PHP代码,你应该避免使用通常的PHP语法(如例4-4)。
相反,你应该在模板里面使用特殊的PHP语法,如例4-5所示,这样不是PHP程序员的人也能理解。
这样不仅最终生成的代码的缩进格式正确,而且可以让你把复杂的代码放在动作里面,因为只有控制语句(if,foreach,while等)有特殊语法。
例4-4-通常的PHP语法,对于动作没问题,对于模板就很糟糕
Hello,world!
php
if($test)
{
echo"
".time()."
";
}
?
>
例4-5-另类PHP语法,适合于模板
Hello,world!
phpif($test):
?
>
phpechotime();?
>
phpendif;?
>
TIP一般来说模板语法的可读性是否够强是看这个文件是否不包含PHP的echo语句或者"{}"。
大多数时候,开始的
php应该与结束的?
>在同一行。
从动作传递信息给模板
动作要做的事情是所有的复杂计算,取出数据,测试,为模板设定显示或者测试用的变量。
symfony让动作类的属性(动作里的可以通过$this->variableName访问)能够直接在模板里面的全局命名空间里面访问得到(通过$variableName)。
例4-6与4-7演示如何从动作传递信息给模板。
例4-6-设定动作的一个属性,把它传给模板
php
classmymoduleActionsextendssfActions
{
publicfunctionexecuteMyAction()
{
$today=getdate();
$this->hour=$today['hours'];
}
}
例4-7-模板能直接访问动作的属性
Hello,world!
phpif($hour>=18):
?
>
OrshouldIsaygoodevening?
It'salready
phpecho$hour?
>.
phpendif;?
>
NOTE有几个数据可以直接在模板中访问而不需要在动作里面设置。
每个模板都可以执行$sf_contex,$sf_request,$sf_params还有$sf_user对象的方法。
它们包含当前上下文、请求、请求参数还有session的信息。
不久你就能学会怎么有效的利用它们。
从用户表单取得数据
表单是从用户取得信息的好方法。
用HTML写表单的元素有时会很麻烦,特别是你想要XHTML兼容时。
你可以按照平常的方式在symfony模板里面使用表单元素,如例4-8所示,不过symfony提供了一些辅助函数来简化这个任务。
例4-8-模板可以包含普通的HTML代码
Hello,world!
phpif($hour>=18):
?
>
OrshouldIsaygoodevening?
It'salready
phpecho$hour?
>.
phpendif;?
>
Whatisyourname?
辅助函数是symfony定义的用在模板里的函数。
它输出HTML代码从而节省你写HTML代码的时间。
使用symfony辅助函数,你可以用例4-9的代码达到与例4-8同样的结果。
例4-9-用辅助函数比写HTML标签更快更容易
Hello,world!
phpif($hour>=18):
?
>
OrshouldIsaygoodevening?
It'salready
phpecho$hour?
>.
phpendif;?
>
phpechoform_tag('mymodule/anotherAction')?
>
phpecholabel_for('name','Whatisyourname?
')?
>
phpechoinput_tag('name')?
>
phpechosubmit_tag('Ok')?
>
SIDEBAR辅助函数是来帮助你的。
如果,你认为在例4-9的例子里,辅助函数的版本没有写HTML快,看看这个例子:
$card_list=array(
>'VISA'=>'Visa',
>'MAST'=>'MasterCard',
>'AMEX'=>'AmericanExpress',
>'DISC'=>'Discover');
>echoselect_tag('cc_type',options_for_select($card_list,'AMEX'));
>?
>
上面的代码的HTML输出如下:
Visa
MasterCard
AmericanExpress
Discover
在模板里使用辅助函数使编写代码的速度提高,代码更清晰,更简洁。
唯一的代价是需要花时间学习他们,学习过程将一直持续到本书完结,到你在你习惯的编辑器中用快捷键写的时候。
所以如果不会用symfony的辅助函数,你仍然可以继续使用HTML标签,不过这很浪费也很枯燥。
注意我们不推荐专业web开发者使用短开始标签(
=,等效于
phpecho),因为你的正式服务器可能能够支持多种脚本语言而把短标签与别的脚本语言混淆。
另外,短开始标签不是PHP的默认设置,需要打开才能使用。
最后,如果你需要处理XML与验证,短标签会有问题因为
在XML里有特殊含义。
由于symfony提供了很多辅助函数简化表单,表单处理需要一整章来讲解。
表单处理详见第10章。
链接到另一个动作
我们已经讲到动作名与访问这个动作的URL之间需要有一个转换过程。
所以如果你建立一个到anotherAction的链接,如例4-10所示,它只适用于默认的路由设置。
如果以后你决定修改URL格式,那你还要修改所有包含这个链接的模板。
例4-10-传统的超链接
name=anonymous">
Ineversaymyname
为了避免这样的麻烦,请使用link_to()辅助函数来建立所有的链接到应用程序内部的动作的超链接。
例4-11演示了如何使用超链接辅助函数。
例4-11-link_to()辅助函数
Hello,world!
phpif($hour>=18):
?
>
OrshouldIsaygoodevening?
It'salready
phpecho$hour?
>.
phpendif;?
>
phpechoform_tag('mymodule/anotherAction')?
>
phpecholabel_for('name','Whatisyourname?
')?
>
phpechoinput_tag('name')?
>
phpechosubmit_tag('Ok')?
>
phpecholink_to('Ineversaymyname','mymodule/anotherAction?
name=anonymous')?
>
上面的代码生成的HTML与前一个例子完全一样,但是如果修改路由规则,所有的模板会根据规则重新格式URL。
link_to()辅助函数,与很多辅助函数类似,接受另一个特殊的参数,这个参数用来传递HTML标签属性。
例4-12是一个option属性的例子还有生成的HTML。
option参数可以是一个数组或者一个简单的由几个key=value与空格组成的字符串。
例4-12-大多数辅助函数有Option参数
//用数组作option参数
phpecholink_to('Ineversaymyname','mymodule/anotherAction?
name=anonymous',
array(
'class'=>'special_link',
'confirm'=>'Areyousure?
',
'absolute'=>true
))?
>
//用字符串作option参数
phpecholink_to('Ineversaymyname','mymodule/anotherAction?
name=anonymous',
'class=special_linkconfirm=Areyousure?
absolute=true')?
>
//结果一样
=>');"
href="http:
//localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous">
Ineversaymyname
任何使用symfony辅助函数输出HTML标签的时候,都可以在option参数中加入额外的属性(例如例4-12中的class属性)。
你甚至可以用HTML4.0的"快速而肮脏(quick-and-dirty)"的方式(不写双引号),symfony会用漂亮的XHTML方式输出。
这是用辅助函数比写HTML快的又一个原因。
NOTE由于需要额外的解析与转换,字符串形式比数组要慢。
与其它辅助函数类似,链接辅助函数有好几种形式与参数。
第9章将向你详细介绍这些内容。
从请求中取得信息
无论用户通过表单(通常是POST请求)还是通过URL(GET请求)取得信息,你都可以在动作中通过sfActions对象的getRequestParameter()方法取得相关的数据。
例4-13演示了如何在actionAction中取得name参数的值。
例4-13-在动作中取得请求参数的值
php
classmymoduleActionsextendssfActions
{
...
publicfunctionexecuteAnotherAction()
{
$this->name=$this->getRequestParameter('name');
}
}
如果数据操作很简单,你甚至不必用动作来取得参数值。
模板可以直接通过$sf_params的get()方法来取得参数的值,类似于动作中的getRequestParameter()方法。
如果executeAnotherAction()方法是空的,例4-14中的这种方法也可以从anotherActionSuccess.php模板中取到name参数的值。
例4-14-直接从模板中取得参数的值
Hello,
phpecho$sf_params->get('name')?
>!
NOTE为什么不直接使用$_POST,$_GET,或$_REQUEST变量呢?
因为如果你的URL的格式会变化(例如http:
//localhost/articles/europe/france/finance.html,没有?
或者=),这样这些PHP变量就不管用了,只有路由系统能够取得请求参数。
还有你可能需要输入过滤器来防止恶意代码注入,只有保持所有的参数使用一个干净的参数存储器的时候才能实现。
$sf_params对象的作用仅仅是数组的替代品。
例如,如果你想判断一个请求参数是否存在,你可以只用$sf_params->has()方法而不必用get()方法取得实际的值,如例4-15。
例4-15-在模板中判断一个参数是否存在
phpif($sf_params->has('name')):
?
>
Hello,
phpecho$sf_params->get('name')?
>!
phpelse:
?
>
Hello,JohnDoe!
phpendif;?
>
你可能已经猜到这用一行代码就可以完成。
与symfony里面的大多数getter方法一样,动作里的getRequestParameter()还有模板里的$sf_params->get()方法(实际上两者调用的是同一个对象的同一个方法)可以有第二个参数:
默认值,在参数不存在的时候起作用。
Hello,
phpecho$sf_params->get('name','JohnDoe')?
>!
总结
在symfony里面,页面由一个动作(actions/actions.class.php文件里的一个方法,以execute开头)还有一个模板(templates/目录里的一