在這一章我們將會學習如何建立一個模組,這是組織頁面的結構化元素。同時我們也會學習如何創造一個分成一個動作也一個模板的頁面,之所以分成動作與模板,是因為MVC模式。連結與表彰是基本的頁面交互,我們將會學習如何在模板中插入這些元素並且在動作中進行處理。
創建一個模組框架
正是如我們在第2章所了解的,Symfony將頁面組織為模組。在創建一個頁面之前,我們需要建立一個模組,並且初始化為一個Symfony可以識別的檔案結構的空殼。
Symfony命令列自動化處理模組的建立。我們只需要呼叫init-module任務,並且使用程式名稱以及模組名稱作為參數。在前一章,我們建立了一個myapp程式。要為這個程式加入mymodule模組,我們可以輸入下面的指令:
> cd ~/myproject
> symfony init-module myapp mymodule
>> dir+ ~/myproject/apps/mymodule
>> dir+ ~/myproject/apps/mymodule/modmy/myapp > dir+ ~/myproject/apps/myapp/modules/mymodule/actions
>> file+ ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>> dir+ ~/myproject/apps/myappect/apps/myapp/apps/ modules/mymodule/config
>> dir+ ~/myproject/apps/myapp/modules/mymodule/lib
>> dir+ ~/myproject/apps/myapp/modules/mymodule/templates
> file+ ~/myproect/apps/file /modules/mymodule/templates/indexSuccess.php
>> dir+ ~/myproject/apps/myapp/modules/mymodule/validate
>>> file+ ~/myproject/test/functional/myapp/myuleActionsTest> 給myproject/test/functional/myapp/mymoduleActionsTest.php
>> tokens ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>> tokens ~/myproject/apps/myapp/modules/my templates/indexSuccess.php
與actions/,config/,lib/,templates/,validate/目錄相分離,這個指令只建立三個檔案。位於test/目錄中的一個為單元測試。 actions.class.php指向預設的模組歡迎頁面。 templates/indexSuccess.php檔案為空。
在actions/actions.class.php檔案中預設產生的動作:
<?php class mymoduleActions extends sfActions { public function executeIndex() { $this->forward('default', 'module'); } }
對於每一個新的模組,Symfony會建立一個預設的index動作。他是由一個名為executeIndex的動作方法以及一個名為indexSuccess.php的模板檔案所組成。我們可以透過下面的URL來瀏覽對應的頁面:
http://localhost/myapp_dev.php/mymodule/index
在這一章我們並不會使用預設的index動作,所以我們可以從actions.class.php檔案中移除executeIndex()方法,並且從templates/目錄中刪除indexSuccess.php檔。
除了命令列,Symfony還提供了其他的方法來初始化一個模組。其中一個方法就是手動來建立目錄與檔案。在許多情況下,一個模組的動作與模板就意味著操作給定資料表的資料。因為創建,獲取,更新,以及從一個資料表中刪除資料記錄的必須程式碼通常都是相同的,Symfony提供了一個名為框架的機制來我們產生這些程式碼。查看第十四章,我們可以了解更多關於這個技術的資訊。
新增一個頁面
在Symfony中,頁面後面的邏輯儲存在動作中,而表面則是在模板中。沒有邏輯的頁面仍然需要一個空的動作。
新增一個動作
"Hello,world!"頁面則會透過一個myAction的動作進行存取。要建立這個動作,只需要在mymoduleActions類別中加入一個executeMyAction方法,如下:
<?php class mymoduleActions extends sfActions { public function executeMyAction() { } }
动作方法的名字总是execute'Xxx'()的形式,其中名字的第二部分是动作的名字,并且第一个字母大写。
现在我们可以请求下面的URL:
http://localhost/myapp_dev.php/mymodule/myAction
Symfony将会抱怨丢失了myActionSuccess.php模板。这是正常的。在Symfony中,一个页面通常是由一个动和与一个模板组成的。
URL是响应的一部分
Symfony包含一个路由系统允许我们在实际的动作名与需要调用的URL格式之间有一个完整的分隔。这允许自定义URL的自定义格式,就如同他是响应的一部分。我们不再为文件的结构或是请求的参数据限制,一个动作的URL看起来就我们所希望的解析。例如,到一个名为article模块的索引动作调用通常如下面的样子:
http://localhost/myapp_dev.php/article/index?id=123
这个URL由一个数据获取一篇指定的文章。但是URL可以通过在routingyml配置文件中作一些小的改动而以一种完全不同的方式进行编写:
http://localhost/articles/europe/france/finance.html
这样的URL不仅对于搜索引擎友好的,他对于用户来说也是十分重要的,这样用户就可以将地址栏作为一个伪码命令来自定义查询,例如下面的例子:
http://localhost/articles/tagged/finance+france+euro
Symfony知道如何为用户解析并生成URL。路由系统会自动从一个简洁URL中脱去所请求的参数,并使其为动作可用。他同时也会格式化响应中所包含的超链接,从而使其看起来更为简洁。我们将会在第九章了解这个特性的更多内容。
总之,这就意味着我们命名程序的动作的方式不应受到调用他们的URL的样子的影响,而是受程序中动作的函数控制。一个动作的名了解释了动作实际所做的内容,而且通常为不定式格式中的一个动词(例如show,list,edit)。动作的名字可以做到对于终端用户完全不可见,从而不必担心使用显式的动作名。我们可以有效的利用代码注释来解释我们的函数功能,从而使代码更读。
添加一个模板
动作需要一个模板来进行封装。一个模板就是位于一个模块的templates/目录的一个文件,通常是以动作和动作的词尾来进行命名的。默认的动作词尾为"success",所以为myAction动作所创建的模板文件应命名为myActionSuccess.php。
模板只包含表现代码,所以在其中要包含尽可有少的PHP代码。实际上,一个显示"Hello,world!"的页面只有一行的代码的模板。
e388a4556c0f65e1904146cc1a846beeHello, world!94b3e26ee717c64999d7867364b1b4a3
如果我们需要在模板中运行一些PHP代码,我们应避免使用下面所列的通常的PHP语法。相反,应使用另一种PHP语法来编写我们的模板,从而使得代码对于非PHP程序来说更易于理解。不仅最终代码是正确的,而且有助于我们在动作中保持复杂的PHP代码,因为只有控制语句有对应代码。
通常的PHP语法如下:
<p>Hello, world!</p> <?php if ($test) { echo "<p>".time()."</p>"; } ?>
替代的PHP语法如下:
<p>Hello, world!</p> <?php if ($test): ?> <p><?php echo time(); ?></p> <?php endif; ?>
由动作向模板传递信息
动作的工作是要完成所有复杂的计算,数据读取以及测试,并且设置要输出或是测试的模板变量。Symfony使得动作类的属性在全局名字空间中为模板可用。下面显示如何由动作向模板传递信息。
在动作中设置动作属性从而使其为模板可用:
<?php class mymoduleActions extends sfActions { public function executeMyAction() { $today = getdate(); $this->hour = $today['hours']; } }
模板直接访问动作属性:
<p>Hello, world!</p> <?php if ($hour >= 18): ?> <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> <?php endif; ?>
模板已经可以访问一些数据,而不需要在动作中设置任何变量。每一个模板通常可以调用$sf_context,$sf_request,$sf_params,$sf_user对象的方法。他们包含与当前内容,请求,请求参数以及会话相关的数据。我们很快就会学到他们的用法。
使用表单向用户收集信息
表单是向用户收集信息的一个好方法。使用HTML编写表单以及表单元素有时是相当麻烦的,尤其是当我们希望适用于XTHML时更是如此。我们可以用通常的方式在Symfony模板中包含表单元素,如下面所示,但是Symfony提供了帮助器从而使得这个任务更为简单。
模板可以包含通常的HTML代码:
<p>Hello, world!</p> <?php if ($hour >= 18): ?> <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> <?php endif; ?>
一个帮助器是用在模板中的由Symfony定义的PHP函数。他输出HTML代码,并且比我们自己编写实际的HTML代码要快速得多。使用Symfony帮助器,我们用下面的代码得到的输出结果与上面通常的HTML代码相同:
<p>Hello, world!</p> <?php if ($hour >= 18): ?> <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> <?php endif; ?>
如果在上面的代码中,我们认为使用帮助器的版本并不会比编写HTML代码快,那么我们可以考虑一下下面的情况:
<?php $card_list = array( 'VISA' => 'Visa', 'MAST' => 'MasterCard', 'AMEX' => 'American Express', 'DISC' => 'Discover'); echo select_tag('cc_type', options_for_select($card_list, 'AMEX')); ?>
这会得到下面的HTML输出结果:
<select name="cc_type" id="cc_type"> <option value="VISA">Visa</option> <option value="MAST">MasterCard</option> <option value="AMEX" selected="selected">American Express</option> <option value="DISC">Discover</option> </select>
在模板中使用的帮助器的好处就在于加快了编码的速度,代码的清晰与简洁。而代价就是我们需要花费时进行学习。所以我们可以在模板中不使用Symfony帮助器,并且以我们通常的方式来编写代码,但是这会是一个巨大的损失。
注意,短开放标记的用法(9eee67b8e03f03e11e407215ebc041e8has()方法,而不使用get()测试实际的值。
在模板中测试请求参数的存在:
<?php if ($sf_params->has('name')): ?> <p>Hello, <?php echo $sf_params->get('name') ?>!</p> <?php else: ?> <p>Hello, John Doe!</p> <?php endif; ?>
我们已经猜到了,这可以在单一的代码行中编写。与Symfony中大多数的获取方法一样,动作中的getRequestParameter()方法与模板中的$sf_params->get()(实际上调用同一个对象的相同主法)方法接受第二个参数:如果没有提供请求参数则使用默认值:
<p>Hello, <?php echo $sf_params->get('name', 'John Doe') ?>!</p>
总结
在Symfony中,页面是由一个动作(actions/actions.class.php文件中以execute为前缀的一个方法)和一个模板(templates/目录下的一个文件,通常以Success.php结尾)组成的。他们通地在程序中的函数组织在一个模块中。编写模板是由帮助器来完成的,而帮助器则是由Symfony提供的返回HTML代码的函数。而我们需要将URL看作响应的一部分,而URL在需要可以格式化,所以我们应避免在动作命名中使用到URL的直接引用或者是请求参数检索。
一旦我们知道了这些基本原则,我们就可以使用Symfony来编写一个完整的Web程序了。但是我们的路还有很长,因为我们在程序开发过程需要处理的每一个任务由一些Symfony特性来完成的。