第04章 建立頁面的基礎(chǔ)知識
第4章 建立頁面的基礎(chǔ)知識很奇怪,每次學(xué)習(xí)新語言或者框架的第一個(gè)例子都是在屏幕上顯示"Hello, world!"。目前為止所有利用人工智能來實(shí)現(xiàn)交談的嘗試的結(jié)果都很差,所以電腦能問候整個(gè)世界這種想
第4章 建立頁面的基礎(chǔ)知識
很奇怪,每次學(xué)習(xí)新語言或者框架的第一個(gè)例子都是在屏幕上顯示"Hello, world!"。目前為止所有利用人工智能來實(shí)現(xiàn)交談的嘗試的結(jié)果都很差,所以電腦能問候整個(gè)世界這種想法實(shí)在有些古怪。但是symfony 并不比其他程序笨,證據(jù)是,你可以用symfony 創(chuàng)建一個(gè)說"Hello, <你的名字>"的頁面。
本章會告訴你如何創(chuàng)建一個(gè)模塊,也就是一組頁面的集合體。你還將了解到如何建立一個(gè)頁面,由于MVC,頁面由一個(gè)動作和一個(gè)模板構(gòu)成。鏈接和表單是web 交互的基礎(chǔ),你將在這一章了解如何在模板里增加他們,如何用動作處理他們。建立模塊框架
在第二章中我們介紹過,symfony把頁面組織成模塊。建立頁面之前,你必須先建立一個(gè)模塊,也就是一個(gè)symfony 能識別的目錄結(jié)構(gòu)的一個(gè)空殼。symfony 命令行工具能自動建立模塊。你只需要用symfony 命令行工具執(zhí)行init-module 任務(wù)并傳應(yīng)用程序名與模塊名這兩個(gè)參數(shù)給它就可以了。在前一章里,你建立了myapp 應(yīng)用程序。如果要在這個(gè)應(yīng)用程序里增加一個(gè)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/目錄,這條命令只建立了三個(gè)文件。test/目錄里的文件與單元測試有關(guān),在第15章之前你都不用管它。actions.class.php(見例4-1)做了一個(gè)到默認(rèn)模塊的成功頁面的跳轉(zhuǎn)。templates/indexSuccess.php文件是空的。
例 4-1 - 默認(rèn)的自動生成的動作 actions/actions.class.php
class mymoduleActions extends sfActions
{
public function executeIndex()
{
$this->forward('default', 'module');
}
}
NOTE 如果你看一下實(shí)際的actions.class.php 文件,你會注意到除了上面的這幾行之外還有其他的內(nèi)容,包括一些注釋。這是因?yàn)閟ymfony 推薦使用P H P 注釋來為你的項(xiàng)目生成文檔,所以每個(gè)類文件都與php D ocumentor 工具
() 兼容。
symfony 為每一個(gè)新模塊建立一個(gè)index 動作。它是由一個(gè)execueIndex 的方法與一個(gè)叫indexSuccess.php 的模板組成的。execute 前綴與Success 后綴的含義會在第6章與第7章中分別解釋?,F(xiàn)在你可以認(rèn)為這是一種命名習(xí)慣。在瀏覽器中輸入下面的網(wǎng)址就可以看到這個(gè)頁面(圖4-1):
本章不會用到這個(gè)默認(rèn)的index 動作,所以你可以把executeIndex()方法從actions.clas.hpp 文件中去掉,并把indexSuccess.php 文件從templates/目錄中刪除。
NOTE 除了命令行,symfony還提供了其他的建立模塊的方法。其中之一是你自己來建立這些文件與目錄。很多時(shí)候,模塊中的動作和模板用來處理一個(gè)表里面的數(shù)據(jù)。由于建立、獲取、更新與刪除所需的代碼往往是一樣的,symfony提供一種稱之為腳手架(scaffolding)的機(jī)制來自動生成一個(gè)模塊。這種技術(shù)詳見第14章。
圖 4-1 - 自動生成的默認(rèn)index 頁
,增加一個(gè)頁面
symfony 里面,頁面背后的邏輯放在動作里面,表現(xiàn)放在模板里。不需要邏輯的頁面也需要一個(gè)空的動作。
增加一個(gè)動作
我們需要一個(gè)通過myAction 動作來訪問"Hello, world!"的頁面。要建立這個(gè)頁面,只要在mymyduleActions 類里面增加一個(gè)executeMyAction 方法,如例4-2。
例 4-2 - 增加一個(gè)動作就是給動作類增加一個(gè)執(zhí)行方法
class mymoduleActions extends sfActions
{
public function executeMyAction()
{
}
}
動作方法的名字永遠(yuǎn)是execute ``XXX``(),方法名字的第二部分的第一個(gè)字母總是大寫。
,現(xiàn)在,如果你訪問下面的網(wǎng)址:
symfony 會抱怨缺少`myActionSuccess.php'模板。這很正常;在symfony 里,一個(gè)頁面永遠(yuǎn)是由一個(gè)動作與一個(gè)模板組成。
NOTE URL (不是域名)是區(qū)分大小寫的,symfony也區(qū)分大小寫(雖然在P H P 里方法名不區(qū)分大小寫)。這就是說,如果你增加一個(gè)executemyaction()方法,或者executeMyaction(),然后你在瀏覽器里訪問myAction,symfony會返回404錯誤信息。
SI D E B A R URL 是響應(yīng)的一部分
symfony 包含一個(gè)路由系統(tǒng),這個(gè)系統(tǒng)可以把真正的動作名與URL 的形式分開來。這樣就可以實(shí)現(xiàn)特殊URL 格式。你可以不受文件結(jié)構(gòu)或者請求參數(shù)的限制;動作的URL 可以是你想要的樣子。例如,請求一個(gè)article 模塊的index 動作的URL 常常是這樣的:
這個(gè)URL 從數(shù)據(jù)庫里面取出指定的文章。在這個(gè)例子里,這篇文章(id=123)是歐洲(europe)欄目里的一篇關(guān)于法國金融(finance in F rance)的文章。但是通過修改routing.yml 配置文件,這個(gè)URL 可以完全改成另外一種直觀的形式:http ://localhost/articles/europe/france/finance.html
這個(gè)URL 不僅對搜索引擎更友好,也對用戶更有意義,用戶可以像使用命令行一樣通過在地址欄執(zhí)行特定的查找,例如:
symfony 知道如何為用戶解析與生成漂亮的URL 。路由系統(tǒng)自動地從一個(gè)漂亮的URL 中剝離出參數(shù)然后傳給動作。它也能格式化回應(yīng)的超鏈接使他們看起來更" 漂亮"。這個(gè)功能詳見第9章。
總之,這意味著應(yīng)用程序的動作的命名可以和他們的URL 不一致,但是動作方法的命名必須與動作名相統(tǒng)一。動作名說明動作要做的事情,它通常是一個(gè)不定式動詞(例如show,list,edit 等)。動作名可以隱藏起來不讓用戶知道,所以請放心的使用動作的名字(例如list B yName 或者show W ithComments)。這樣可以有效地節(jié)省注釋,另外代碼的可讀性也大大增強(qiáng)了。
增加一個(gè)模板
,動作需要一個(gè)模板來表現(xiàn)自己。模板是模塊的templates/目錄里的一個(gè)文件,模板名字由動作名與動作終止組成。默認(rèn)的動作終止是"success"也就是成功,所以myAction 動作的模板名是myActionSuccess.php。
理想的模板只包含顯示代碼,所以P H P 代碼越少越好。顯示"Hello, world!"的頁面的模板可以如同例4-3中的那么簡單。
例 4-3 - mymodule/templates/myActionSuccess.php 模板
Hello, world!
如果需要在模板里執(zhí)行一些P H P 代碼,你應(yīng)該避免使用通常的P H P 語法(如例4-
4)。相反,你應(yīng)該在模板里面使用特殊的P H P 語法,如例4-5所示,這樣不是P H P 程序員的人也能理解。這樣不僅最終生成的代碼的縮進(jìn)格式正確,而且可以讓你把復(fù)雜的代碼放在動作里面,因?yàn)橹挥锌刂普Z句(if,foreach,while等)有特殊語法。
例 4-4 - 通常的P H P 語法,對于動作沒問題,對于模板就很糟糕
Hello, world!
if ($test)
{
echo "
".time()."
";}
?>
例 4-5 - 另類P H P 語法,適合于模板
Hello, world!
TI P 一般來說模板語法的可讀性是否夠強(qiáng)是看這個(gè)文件是否不包含P H P 的echo 語句或者"{}"。大多數(shù)時(shí)候,開始的在同一行。從動作傳遞信息給模板
動作要做的事情是所有的復(fù)雜計(jì)算,取出數(shù)據(jù),測試,為模板設(shè)定顯示或者測試用的變量。symfony讓動作類的屬性(動作里的可以通過$this->variableName
,訪問)能夠直接在模板里面的全局命名空間里面訪問得到(通過$variableName)。例4-6與4-7演示如何從動作傳遞信息給模板。
例 4-6 - 設(shè)定動作的一個(gè)屬性,把它傳給模板
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 有幾個(gè)數(shù)據(jù)可以直接在模板中訪問而不需要在動作里面設(shè)置。每個(gè)模板都可以執(zhí)行$sf_contex,$sf_re q uest,$sf_params 還有$sf_user 對象的方法。它們包含當(dāng)前上下文、請求、請求參數(shù)還有session 的信息。不久你就能學(xué)會怎么有效的利用它們。
從用戶表單取得數(shù)據(jù)
表單是從用戶取得信息的好方法。用HTM L 寫表單的元素有時(shí)會很麻煩,特別是你想要X HTM L 兼容時(shí)。你可以按照平常的方式在symfony 模板里面使用表單元素,如例4-8所示,不過symfony 提供了一些輔助函數(shù)來簡化這個(gè)任務(wù)。
例 4-8 - 模板可以包含普通的HTM L 代碼
Hello, world!
= 18) : ?>
Or should I say good evening? It's already .
輔助函數(shù)是symfony 定義的用在模板里的函數(shù)。它輸出HTM L 代碼從而節(jié)省你寫HTM L 代碼的時(shí)間。使用symfony 輔助函數(shù),你可以用例4-9的代碼達(dá)到與例4-8同樣的結(jié)果。
例 4-9 - 用輔助函數(shù)比寫HTM L 標(biāo)簽更快更容易
Hello, world!
= 18) : ?>
Or should I say good evening? It's already .
SI D E B A R 輔助函數(shù)是來幫助你的。
如果,你認(rèn)為在例4-9的例子里,輔助函數(shù)的版本沒有寫HTM L 快,看看這個(gè)例子:
$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 輸出如下:
,
在模板里使用輔助函數(shù)使編寫代碼的速度提高,代碼更清晰,更簡潔。唯一的代價(jià)是需要花時(shí)間學(xué)習(xí)他們,學(xué)習(xí)過程將一直持續(xù)到本書完結(jié),到你在你習(xí)慣的編輯器中用快捷鍵寫的時(shí)候。所以如果不會用symfony 的輔助函數(shù),你仍然可以繼續(xù)使用HTM L 標(biāo)簽,不過這很浪費(fèi)也很枯燥。
注意我們不推薦專業(yè)web 開發(fā)者使用短開始標(biāo)簽(=, 等效于
由于symfony 提供了很多輔助函數(shù)簡化表單,表單處理需要一整章來講解。表單處理詳見第10章。
鏈接到另一個(gè)動作
我們已經(jīng)講到動作名與訪問這個(gè)動作的URL 之間需要有一個(gè)轉(zhuǎn)換過程。所以如果你建立一個(gè)到anotherAction 的鏈接,如例4-10所示,它只適用于默認(rèn)的路由設(shè)置。如果以后你決定修改URL 格式,那你還要修改所有包含這個(gè)鏈接的模板。例 4-10 - 傳統(tǒng)的超鏈接
為了避免這樣的麻煩,請使用link _to()輔助函數(shù)來建立所有的鏈接到應(yīng)用程序內(nèi)部的動作的超鏈接。例4-11演示了如何使用超鏈接輔助函數(shù)。
例 4-11 - link_to() 輔助函數(shù)
Hello, world!
= 18) : ?>
Or should I say good evening? It's already .
,上面的代碼生成的HTM L 與前一個(gè)例子完全一樣,但是如果修改路由規(guī)則,所有的模板會根據(jù)規(guī)則重新格式URL 。
link _to()輔助函數(shù),與很多輔助函數(shù)類似,接受另一個(gè)特殊的參數(shù),這個(gè)參數(shù)用來傳遞HTM L 標(biāo)簽屬性。例4-12是一個(gè)option 屬性的例子還有生成的HTM L 。option 參數(shù)可以是一個(gè)數(shù)組或者一個(gè)簡單的由幾個(gè)key =value 與空格組成的字符串。
例 4-12 - 大多數(shù)輔助函數(shù)有Option 參數(shù)
// 用數(shù)組作option 參數(shù)
array(
'class' => 'special_link',
'confirm' => 'Are you sure?',
'absolute' => true
)) ?>
// 用字符串作option 參數(shù)
'class=special _link confirm=Are you sure? absolute=true') ?>// 結(jié)果一樣
=> href="http ://localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous"> I never say my name
任何使用symfony 輔助函數(shù)輸出HTM L 標(biāo)簽的時(shí)候,都可以在option 參數(shù)中加入額外的屬性(例如例4-12中的class 屬性)。你甚至可以用HTM L 4.0的"快速而骯臟(q uick-and-dirty)"的方式(不寫雙引號),symfony會用漂亮的X HTM L 方式輸出。這是用輔助函數(shù)比寫HTM L 快的又一個(gè)原因。
NOTE 由于需要額外的解析與轉(zhuǎn)換,字符串形式比數(shù)組要慢。
與其它輔助函數(shù)類似,鏈接輔助函數(shù)有好幾種形式與參數(shù)。第9章將向你詳細(xì)介紹這些內(nèi)容。
從請求中取得信息
,無論用戶通過表單(通常是P OST 請求)還是通過URL (G ET 請求) 取得信息,你都可以在動作中通過sfActions 對象的get R e q uest P arameter()方法取得相關(guān)的數(shù)據(jù)。例4-13演示了如何在actionAction 中取得name 參數(shù)的值。
例 4-13 - 在動作中取得請求參數(shù)的值
class mymoduleActions extends sfActions
{
...
public function executeAnotherAction()
{
$this->name = $this->getR e q uest P arameter('name');
}
}
如果數(shù)據(jù)操作很簡單,你甚至不必用動作來取得參數(shù)值。模板可以直接通過$sf_params 的get()方法來取得參數(shù)的值,類似于動作中的
get R e q uest P arameter()方法。
如果 executeAnotherAction() 方法是空的, 例 4-14 中的這種方法也可以從anotherActionSuccess.php 模板中取到name 參數(shù)的值。
例 4-14 - 直接從模板中取得參數(shù)的值
Hello, get('name') ?>!
NOTE 為什么不直接使用$_POST,$_G ET, 或 $_RE Q U EST 變量呢?因?yàn)槿绻愕腢RL 的格式會變化(例如
$sf_params 對象的作用僅僅是數(shù)組的替代品。例如,如果你想判斷一個(gè)請求參數(shù)是否存在,你可以只用$sf_params->has()方法而不必用get()方法取得實(shí)際的值,如例4-15。
例 4-15 - 在模板中判斷一個(gè)參數(shù)是否存在
has('name')): ?>
Hello, get('name') ?>!