第04章 建立页面的基础知识

第4章 建立页面的基础知识很奇怪,每次学习新语言或者框架的第一个例子都是在屏幕上显示"Hello, world!"。目前为止所有利用人工智能来实现交谈的尝试的结果都很差,所以电脑能问候整个世界这种想

第4章 建立页面的基础知识

很奇怪,每次学习新语言或者框架的第一个例子都是在屏幕上显示"Hello, world!"。目前为止所有利用人工智能来实现交谈的尝试的结果都很差,所以电脑能问候整个世界这种想法实在有些古怪。但是symfony 并不比其他程序笨,证据是,你可以用symfony 创建一个说"Hello, <你的名字>"的页面。

本章会告诉你如何创建一个模块,也就是一组页面的集合体。你还将了解到如何建立一个页面,由于MVC,页面由一个动作和一个模板构成。链接和表单是web 交互的基础,你将在这一章了解如何在模板里增加他们,如何用动作处理他们。建立模块框架

在第二章中我们介绍过,symfony把页面组织成模块。建立页面之前,你必须先建立一个模块,也就是一个symfony 能识别的目录结构的一个空壳。symfony 命令行工具能自动建立模块。你只需要用symfony 命令行工具执行init-module 任务并传应用程序名与模块名这两个参数给它就可以了。在前一章里,你建立了myapp 应用程序。如果要在这个应用程序里增加一个mymodule 模块,只需要在命令行下输入下面的命令:

> cd ~/myproject

> symfony init-module myapp mymodule

>> 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

class mymoduleActions extends sfActions

{

public function executeIndex()

{

$this->forward('default', 'module');

}

}

NOTE 如果你看一下实际的actions.class.php 文件,你会注意到除了上面的这几行之外还有其他的内容,包括一些注释。这是因为symfony 推荐使用P H P 注释来为你的项目生成文档,所以每个类文件都与php D ocumentor 工具

() 兼容。

symfony 为每一个新模块建立一个index 动作。它是由一个execueIndex 的方法与一个叫indexSuccess.php 的模板组成的。execute 前缀与Success 后缀的含义会在第6章与第7章中分别解释。现在你可以认为这是一种命名习惯。在浏览器中输入下面的网址就可以看到这个页面(图4-1):

本章不会用到这个默认的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 - 增加一个动作就是给动作类增加一个执行方法

class mymoduleActions extends sfActions

{

public function executeMyAction()

{

}

}

动作方法的名字永远是execute ``XXX``(),方法名字的第二部分的第一个字母总是大写。

,

现在,如果你访问下面的网址:

symfony 会抱怨缺少`myActionSuccess.php'模板。这很正常;在symfony 里,一个页面永远是由一个动作与一个模板组成。

NOTE URL (不是域名)是区分大小写的,symfony也区分大小写(虽然在P H P 里方法名不区分大小写)。这就是说,如果你增加一个executemyaction()方法,或者executeMyaction(),然后你在浏览器里访问myAction,symfony会返回404错误信息。

SI D E B A R URL 是响应的一部分

symfony 包含一个路由系统,这个系统可以把真正的动作名与URL 的形式分开来。这样就可以实现特殊URL 格式。你可以不受文件结构或者请求参数的限制;动作的URL 可以是你想要的样子。例如,请求一个article 模块的index 动作的URL 常常是这样的:

这个URL 从数据库里面取出指定的文章。在这个例子里,这篇文章(id=123)是欧洲(europe)栏目里的一篇关于法国金融(finance in F rance)的文章。但是通过修改routing.yml 配置文件,这个URL 可以完全改成另外一种直观的形式:http ://localhost/articles/europe/france/finance.html

这个URL 不仅对搜索引擎更友好,也对用户更有意义,用户可以像使用命令行一样通过在地址栏执行特定的查找,例如:

symfony 知道如何为用户解析与生成漂亮的URL 。路由系统自动地从一个漂亮的URL 中剥离出参数然后传给动作。它也能格式化回应的超链接使他们看起来更" 漂亮"。这个功能详见第9章。

总之,这意味着应用程序的动作的命名可以和他们的URL 不一致,但是动作方法的命名必须与动作名相统一。动作名说明动作要做的事情,它通常是一个不定式动词(例如show,list,edit 等)。动作名可以隐藏起来不让用户知道,所以请放心的使用动作的名字(例如list B yName 或者show W ithComments)。这样可以有效地节省注释,另外代码的可读性也大大增强了。

增加一个模板

,

动作需要一个模板来表现自己。模板是模块的templates/目录里的一个文件,模板名字由动作名与动作终止组成。默认的动作终止是"success"也就是成功,所以myAction 动作的模板名是myActionSuccess.php。

理想的模板只包含显示代码,所以P H P 代码越少越好。显示"Hello, world!"的页面的模板可以如同例4-3中的那么简单。

例 4-3 - mymodule/templates/myActionSuccess.php 模板

Hello, world!

如果需要在模板里执行一些P H P 代码,你应该避免使用通常的P H P 语法(如例4-

4)。相反,你应该在模板里面使用特殊的P H P 语法,如例4-5所示,这样不是P H P 程序员的人也能理解。这样不仅最终生成的代码的缩进格式正确,而且可以让你把复杂的代码放在动作里面,因为只有控制语句(if,foreach,while等)有特殊语法。

例 4-4 - 通常的P H P 语法,对于动作没问题,对于模板就很糟糕

Hello, world!

if ($test)

{

echo "

".time()."

";

}

?>

例 4-5 - 另类P H P 语法,适合于模板

Hello, world!

TI P 一般来说模板语法的可读性是否够强是看这个文件是否不包含P H P 的echo 语句或者"{}"。大多数时候,开始的在同一行。从动作传递信息给模板

动作要做的事情是所有的复杂计算,取出数据,测试,为模板设定显示或者测试用的变量。symfony让动作类的属性(动作里的可以通过$this->variableName

,

访问)能够直接在模板里面的全局命名空间里面访问得到(通过$variableName)。例4-6与4-7演示如何从动作传递信息给模板。

例 4-6 - 设定动作的一个属性,把它传给模板

class mymoduleActions extends sfActions

{

public function executeMyAction()

{

$today = getdate();

$this->hour = $today['hours' ];

}

}

例 4-7 - 模板能直接访问动作的属性

Hello, world!

= 18) : ?>

Or should I say good evening? It's already .

NOTE 有几个数据可以直接在模板中访问而不需要在动作里面设置。每个模板都可以执行$sf_contex,$sf_re q uest,$sf_params 还有$sf_user 对象的方法。它们包含当前上下文、请求、请求参数还有session 的信息。不久你就能学会怎么有效的利用它们。

从用户表单取得数据

表单是从用户取得信息的好方法。用HTM L 写表单的元素有时会很麻烦,特别是你想要X HTM L 兼容时。你可以按照平常的方式在symfony 模板里面使用表单元素,如例4-8所示,不过symfony 提供了一些辅助函数来简化这个任务。

例 4-8 - 模板可以包含普通的HTM L 代码

Hello, world!

= 18) : ?>

Or should I say good evening? It's already .

,

辅助函数是symfony 定义的用在模板里的函数。它输出HTM L 代码从而节省你写HTM L 代码的时间。使用symfony 辅助函数,你可以用例4-9的代码达到与例4-8同样的结果。

例 4-9 - 用辅助函数比写HTM L 标签更快更容易

Hello, world!

= 18) : ?>

Or should I say good evening? It's already .

SI D E B A R 辅助函数是来帮助你的。

如果,你认为在例4-9的例子里,辅助函数的版本没有写HTM L 快,看看这个例子:

$card_list = array(

> 'VISA' => 'Visa',

> 'MAST' => 'MasterCard',

> 'AMEX ' => 'American Express',

> 'D ISC' => 'D iscover');

> echo select_tag('cc_type', options_for _select($card_list, 'AME X '));

> ?>

上面的代码的HTM L 输出如下:

,

在模板里使用辅助函数使编写代码的速度提高,代码更清晰,更简洁。唯一的代价是需要花时间学习他们,学习过程将一直持续到本书完结,到你在你习惯的编辑器中用快捷键写的时候。所以如果不会用symfony 的辅助函数,你仍然可以继续使用HTM L 标签,不过这很浪费也很枯燥。

注意我们不推荐专业web 开发者使用短开始标签(

由于symfony 提供了很多辅助函数简化表单,表单处理需要一整章来讲解。表单处理详见第10章。

链接到另一个动作

我们已经讲到动作名与访问这个动作的URL 之间需要有一个转换过程。所以如果你建立一个到anotherAction 的链接,如例4-10所示,它只适用于默认的路由设置。如果以后你决定修改URL 格式,那你还要修改所有包含这个链接的模板。例 4-10 - 传统的超链接

I never say my name

为了避免这样的麻烦,请使用link _to()辅助函数来建立所有的链接到应用程序内部的动作的超链接。例4-11演示了如何使用超链接辅助函数。

例 4-11 - link_to() 辅助函数

Hello, world!

= 18) : ?>

Or should I say good evening? It's already .

,

上面的代码生成的HTM L 与前一个例子完全一样,但是如果修改路由规则,所有的模板会根据规则重新格式URL 。

link _to()辅助函数,与很多辅助函数类似,接受另一个特殊的参数,这个参数用来传递HTM L 标签属性。例4-12是一个option 属性的例子还有生成的HTM L 。option 参数可以是一个数组或者一个简单的由几个key =value 与空格组成的字符串。

例 4-12 - 大多数辅助函数有Option 参数

// 用数组作option 参数

array(

'class' => 'special_link',

'confirm' => 'Are you sure?',

'absolute' => true

)) ?>

// 用字符串作option 参数

'class=special _link confirm=Are you sure? absolute=true') ?>// 结果一样

=>

href="http ://localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous">

I never say my name

任何使用symfony 辅助函数输出HTM L 标签的时候,都可以在option 参数中加入额外的属性(例如例4-12中的class 属性)。你甚至可以用HTM L 4.0的"快速而肮脏(q uick-and-dirty)"的方式(不写双引号),symfony会用漂亮的X HTM L 方式输出。这是用辅助函数比写HTM L 快的又一个原因。

NOTE 由于需要额外的解析与转换,字符串形式比数组要慢。

与其它辅助函数类似,链接辅助函数有好几种形式与参数。第9章将向你详细介绍这些内容。

从请求中取得信息

,

无论用户通过表单(通常是P OST 请求)还是通过URL (G ET 请求) 取得信息,你都可以在动作中通过sfActions 对象的get R e q uest P arameter()方法取得相关的数据。例4-13演示了如何在actionAction 中取得name 参数的值。

例 4-13 - 在动作中取得请求参数的值

class mymoduleActions extends sfActions

{

...

public function executeAnotherAction()

{

$this->name = $this->getR e q uest P arameter('name');

}

}

如果数据操作很简单,你甚至不必用动作来取得参数值。模板可以直接通过$sf_params 的get()方法来取得参数的值,类似于动作中的

get R e q uest P arameter()方法。

如果 executeAnotherAction() 方法是空的, 例 4-14 中的这种方法也可以从anotherActionSuccess.php 模板中取到name 参数的值。

例 4-14 - 直接从模板中取得参数的值

Hello, get('name') ?>!

NOTE 为什么不直接使用$_POST,$_G ET, 或 $_RE Q U EST 变量呢?因为如果你的URL 的格式会变化(例如

$sf_params 对象的作用仅仅是数组的替代品。例如,如果你想判断一个请求参数是否存在,你可以只用$sf_params->has()方法而不必用get()方法取得实际的值,如例4-15。

例 4-15 - 在模板中判断一个参数是否存在

has('name')): ?>

Hello, get('name') ?>!

标签: