Development

Documentation/zh_CN/book/1.0/04-The-Basics-of-Page-Creation (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/zh_CN/book/1.0/04-The-Basics-of-Page-Creation

Show
Ignore:
Author:
Le.Jiang (IP: 218.80.121.212)
Timestamp:
03/13/07 17:14:50 (11 years ago)
Comment:

page creation

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/zh_CN/book/1.0/04-The-Basics-of-Page-Creation

    v0 v1  
     1{{{ 
     2#!WikiMarkdown 第4章 - 建立页面的基础知识 
     3======================================= 
     4 
     5很奇怪,每次学习新语言或者框架的第一个例子都是在屏幕上显示"Hello, world!"。目前为止所有利用人工智能来实现交谈的尝试的结果都很差,所以电脑能问候整个世界这种想法实在有些古怪。但是symfony并不比其他程序笨,证据是,你可以用symfony创建一个说"Hello, `<你的名字>`"的页面。 
     6 
     7本章会告诉你如何创建一个模块,也就是一组页面的集合体。你还将了解到如何建立一个页面,由于MVC,页面由一个动作和一个模版构成。链接和表但是web交互的基础,你将在这一张了解如何在模版里增加他们,如何用动作处理他们。 
     8 
     9建立模块框架 Creating a Module Skeleton 
     10-------------------------- 
     11 
     12在第二章中我们介绍过,symfony把页面组织成模块。建立页面之前,你必须先建立一个模块,也就是一个symfony能识别的目录结构的一个空壳。 
     13 
     14symfony命令行工具能自动建立模块。你只需要用symfony命令行工具执行`init-module`任务并传应用程序名与模块名这两个参数给它就可以了。在前一章里,你建立了`myapp`应用程序。如果要在这个应用程序里增加一个`mymodule`模块,只需要在命令行下输入下面的命令: 
     15 
     16    > cd ~/myproject 
     17    > symfony init-module myapp mymodule 
     18 
     19    >> dir+      ~/myproject/apps/myapp/modules/mymodule 
     20    >> dir+      ~/myproject/apps/myapp/modules/mymodule/actions 
     21    >> file+     ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php 
     22    >> dir+      ~/myproject/apps/myapp/modules/mymodule/config 
     23    >> dir+      ~/myproject/apps/myapp/modules/mymodule/lib 
     24    >> dir+      ~/myproject/apps/myapp/modules/mymodule/templates 
     25    >> file+     ~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php 
     26    >> dir+      ~/myproject/apps/myapp/modules/mymodule/validate 
     27    >> file+     ~/myproject/test/functional/myapp/mymoduleActionsTest.php 
     28    >> tokens    ~/myproject/test/functional/myapp/mymoduleActionsTest.php 
     29    >> tokens    ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php 
     30    >> tokens    ~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php 
     31 
     32除了`actions/`, `config/`, `lib/`, `templates/`, 与 `validate/`目录,这条命令只建立了三个文件。test/目录里的文件与单元测试有关,在第15章之前你都不用管它。`actions.class.php`(见例4-1)做了一个到默认的模块成功页面的跳转。`templates/indexSuccess.php`文件是空的。 
     33 
     34例 4-1 - 默认的自动生成的动作 `actions/actions.class.php` 
     35 
     36    [php] 
     37    <?php 
     38 
     39    class mymoduleActions extends sfActions 
     40    { 
     41      public function executeIndex() 
     42      { 
     43        $this->forward('default', 'module'); 
     44      } 
     45    } 
     46 
     47>**NOTE** 
     48>如果你看一下实际的`actions.class.php`文件,你会注意到除了上面的这几行之外还有其他的内容,包括一些注释。这是因为symfony推荐使用PHP注释来为你的项目生成文档,所以每个类文件都与phpDocumentor工具([http://www.phpdoc.org/](http://www.phpdoc.org/))兼容。 
     49 
     50symfony为每一个新模块建立一个`index`动作。它是由一个`execueIndex`的方法与一个叫`indexSuccess.php`的模版组成的。`execute`前缀与`Success`后缀的含义会在第6章与第7章中分别解释。现在你可以认为这是一种命名习惯。在浏览器中输入下面的网址就可以看到这个页面(图4-1): 
     51 
     52    http://localhost/myapp_dev.php/mymodule/index 
     53 
     54本章不会用到这个默认的`index`动作,所以你可以把`executeIndex()`方法从`actions.clas.hpp`文件中去掉,并删除把`indexSuccess.php`文件从`templates/`目录中删除。 
     55 
     56>**NOTE** 
     57>除了命令行,symfony还提供了其他的建立模块的方法。其中之一是你自己来建立这些文件与目录。很多时候,模块中的动作和模版用来处理一个表里面的数据。由于建立、获取、更新与删除所需的代码往往是一样的,symfony提供一种称之为脚手架(scaffolding)的机制来自动生成一个模块。这种技术详见第14章。 
     58 
     59图 4-1 - 自动生成的默认index页 
     60 
     61![自动生成的默认index页](/images/book/F0401.jpg "自动生成的默认index页") 
     62 
     63增加一个页面 Adding a Page 
     64------------- 
     65 
     66symfony里面,页面背后的逻辑放在动作里面,表现放在模版里。不需要逻辑的页面也需要一个空的动作。 
     67 
     68### 增加一个动作 Adding an Action 
     69 
     70我们需要一个通过`myAction`动作来访问"Hello, world!"的页面。要建立这个页面,只要在`mymyduleActions`类里面增加一个`executeMyAction`方法,如例4-2。 
     71 
     72例 4-2 - 增加一个动作就是给动作类增加一个执行方法 
     73 
     74    [php] 
     75    <?php 
     76 
     77    class mymoduleActions extends sfActions 
     78    { 
     79      public function executeMyAction() 
     80      { 
     81      } 
     82    } 
     83 
     84动作方法的名字永远是`execute``XXX``()`,方法名字的第二部分的第一个字母总是大写。 
     85 
     86现在,如果你访问下面的网址: 
     87 
     88    http://localhost/myapp_dev.php/mymodule/myAction 
     89 
     90symfony会抱怨缺少`myActionSuccess.php'模版。这很正常;在symfony里,一个页面永远是由一个动作与一个模版组成。 
     91 
     92>**NOTE** 
     93>URL(不是域名)是区分大小写的,symfony也区分大小写(虽然在PHP里方法名不区分大小写)。这就是说,如果你增加一个`executemyaction()`方法,或者`executeMyaction()`,然后你在浏览器里访问`myAction`,symfony会返回404错误信息。 
     94 
     95- 
     96 
     97>**SIDEBAR** 
     98>URL是响应的一部分 
     99> 
     100>symfony包含一个路由系统,这个系统可以把真正的动作名与URL的形式分开来。这样就可以实现特殊URL格式。你可以不受文件结构或者请求参数的限制;动作的URL可以是你想要的样子。例如,请求一个article模块的index动作的URL常常是这样的: 
     101> 
     102>     http://localhost/myapp_dev.php/article/index?id=123 
     103> 
     104>这个URL从数据库里面取出指定的文章。在这个例子里,这篇文章(`id=123`)是欧洲(europe)栏目里的一篇关于法国金融(finance in France)的文章。但是通过修改`routing.yml`配置文件,这个URL可以完全改成另外一种简单的形式: 
     105> 
     106>     http://localhost/articles/europe/france/finance.html 
     107> 
     108>这个URL不仅对搜索引擎更友好,也对用户更有意义,用户可以像使用命令行一样通过地址栏执行特定的查找,例如: 
     109> 
     110>     http://localhost/articles/tagged/finance+france+euro 
     111> 
     112>symfony知道如何为用户解析与生成漂亮的URL。路由系统自动地从一个漂亮的URL中剥离出参数然后传给动作。它也能格式化回应的超链接是他们看起来更"漂亮"。这个功能详见第9章。 
     113> 
     114>总之,这意味着应用程序的动作的命名可以和他们的URL不一致,但是动作方法的命名必须与动作名相统一。动作名说明动作要做的事情,它通常是一个不定式动词(例如`show`,`list`,`edit`等)。动作名可以隐藏起来不让用户知道,所以请放心的解释动作的名字(例如`listByName`或者`showWithComments`)。这样可以有效地节省注释,另外代码的可能性也大大增强了。 
     115 
     116### 增加一个模版 Adding a Template 
     117 
     118动作需要一个模版来表现自己。模版是模块的`templates/`目录里的一个文件,模版名字由动作名与动作终止组成。默认的动作终止是"success"也就是成功,所以`myAction`动作的模版名是`myActionSuccess.php`。 
     119 
     120理想的模版只包含显示代码,所以PHP代码越少越好。显示"Hello, world!"的页面的模版可以如同例4-3中的那么简单。 
     121 
     122例 4-3 - `mymodule/templates/myActionSuccess.php` 模版 
     123 
     124    [php] 
     125    <p>Hello, world!</p> 
     126 
     127如果需要在模版里执行一些PHP代码,你应该避免使用通常的PHP语法(如例4-4)。相反,你应该在模版里面使用特殊的PHP语法,如例4-5所示,这样不是PHP程序员的人也能理解。这样不仅最终生成的代码的缩进格式正确,这么做还可以让你把复杂的代码放在动作里面,因为只有控制语句(`if`,`foreach`,`while`等)有特殊语法。 
     128 
     129例 4-4 - 通常的PHP语法,对于动作没问题,对于模版就很糟糕 
     130 
     131    [php] 
     132    <p>Hello, world!</p> 
     133    <?php 
     134 
     135    if ($test) 
     136    { 
     137      echo "<p>".time()."</p>"; 
     138    } 
     139 
     140    ?> 
     141 
     142例 4-5 - 另类PHP语法,适合于模版 
     143 
     144    [php] 
     145    <p>Hello, world!</p> 
     146    <?php if ($test): ?> 
     147    <p><?php echo time(); ?></p> 
     148    <?php endif; ?> 
     149 
     150>**TIP** 
     151>一般来说模版语法的可读性是否够强是看这个文件是否不包含PHP的echo语句或者"{}"。大多数时候,开始的`<?php`应该与结束的`?>`在同一行。 
     152 
     153### 从动作传递信息给模版 Passing Information from the Action to the Template 
     154 
     155动作要做的事情是所有的复杂计算,取出数据,测试,为模版设定显示或者测试用的变量。symfony让动作类的属性(动作里的可以通过`$this->variableName`访问)能够直接在模版里面的全局命名空间里面访问得到(通过`$variableName`)。例4-6与4-7演示如何从动作传递信息给模版。 
     156 
     157例 4-6 - 设定动作的一个属性,把它传给模版 
     158 
     159    [php] 
     160    <?php 
     161 
     162    class mymoduleActions extends sfActions 
     163    { 
     164      public function executeMyAction() 
     165      { 
     166        $today = getdate(); 
     167        $this->hour = $today['hours']; 
     168      } 
     169    } 
     170 
     171例 4-7 - 模版能直接访问动作的属性 
     172 
     173    [php] 
     174    <p>Hello, world!</p> 
     175    <?php if ($hour >= 18): ?> 
     176    <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> 
     177    <?php endif; ?> 
     178 
     179>**NOTE** 
     180>有几个数据可以直接在模版中访问而不需要再动作里面设置。每个模版都可以执行`$sf_contex`,`$sf_request`,`$sf_params`还有`$sf_user`对象的方法。它们包含当前上下文,请求,请求参数还有session的信息。不久你就能学会怎么有效的利用它们。 
     181 
     182从用户与表单取得数据 Gathering Information from the User with Forms 
     183---------------------------------------------- 
     184 
     185表单是从用户取得信息的好方法。用HTML写表单的元素有时会很麻烦,特别是你想要XHTML兼容时。你可以按照平常的方式在symfony模版里面使用表单元素,如例4-8所示,不过symfony提供了一些辅助函数来简化这个任务。 
     186 
     187例 4-8 - 模版可以包含普通的HTML代码 
     188 
     189    [php] 
     190    <p>Hello, world!</p> 
     191    <?php if ($hour >= 18): ?> 
     192    <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> 
     193    <?php endif; ?>      
     194    <form method="post" target="/myapp_dev.php/mymodule/anotherAction"> 
     195      <label for="name">What is your name?</label> 
     196      <input type="text" name="name" id="name" value="" /> 
     197      <input type="submit" value="Ok" /> 
     198    </form> 
     199 
     200辅助函数是symfony定义的用在模版里的函数。它输出HTML代码从而节省你写HTML代码的时间。使用symfony辅助函数,你可以用例4-9的代码达到与例4-8同样的结果。 
     201 
     202例 4-9 - 用辅助函数比写HTML标签更快更容易 
     203 
     204    [php] 
     205    <p>Hello, world!</p> 
     206    <?php if ($hour >= 18): ?> 
     207    <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> 
     208    <?php endif; ?> 
     209    <?php echo form_tag('mymodule/anotherAction') ?> 
     210      <?php echo label_for('name', 'What is your name?') ?> 
     211      <?php echo input_tag('name') ?> 
     212      <?php echo submit_tag('Ok') ?> 
     213    </form> 
     214 
     215>**SIDEBAR** 
     216>辅助函数是来帮助你的 
     217> 
     218>如果,你认为在在例4-9的例子里,辅助函数的版本没有写HTML快,看看这个例子: 
     219> 
     220>     [php] 
     221>     <?php 
     222>     $card_list = array( 
     223>       'VISA' => 'Visa', 
     224>       'MAST' => 'MasterCard', 
     225>       'AMEX' => 'American Express', 
     226>       'DISC' => 'Discover'); 
     227>     echo select_tag('cc_type', options_for_select($card_list, 'AMEX')); 
     228>     ?> 
     229> 
     230>上面的代码的HTML输出如下: 
     231> 
     232>     [php] 
     233>     <select name="cc_type" id="cc_type"> 
     234>       <option value="VISA">Visa</option> 
     235>       <option value="MAST">MasterCard</option> 
     236>       <option value="AMEX" selected="selected">American Express</option> 
     237>       <option value="DISC">Discover</option> 
     238>     </select> 
     239> 
     240>在模版里使用辅助函数使编写代码的速度的提高,代码更清晰,更简洁。唯一的代价是需要花时间学习他们,学习一直持续到本书完结,到你在你习惯的编辑器中用快捷键写<?php echo ?>的时候。所以如果不不会用symfony的辅助函数,你仍然可以继续使用HTML标签,不过这很浪费很枯燥。 
     241 
     242注意我们不推荐专业web开发者使用短的开始标签(`<?=`,等效于 `<?php echo `),因为你的正是服务器可能能够支持多种脚本语言而把短标签与别的脚本语言混淆。另外,短开始标签不是PHP的默认设置需要打开才能使用。最后,如果你需要处理XML与验证,短标签会有问题因为`<?`在XML里有特殊含义。 
     243 
     244由于symfony提供了很多辅助函数简化表单,表单处理需要一整整章来讲解。表单处理详见第10章。 
     245 
     246链接到另一个动作 Linking to Another Action 
     247------------------------- 
     248 
     249我们已经讲到动作名与访问这个动作的URL之间需要有一个转换过程。所以如果你建立一个链接到`anotherAction`的链接,如例4-10所示,它只适用于默认的路由设置。如果以后你决定修改URL格式,那你还要修改所有包含这个链接的模版。 
     250 
     251例 4-10 - 传统的超链接 
     252 
     253    [php] 
     254    <a href="/myapp_dev.php/mymodule/anotherAction?name=anonymous"> 
     255      I never say my name 
     256    </a> 
     257 
     258为了避免这样的麻烦,请使用`link_to()`辅助函数来建立所有的链接到应用程序内部的动作的超链接。例4-11演示了如何使用超链接辅助函数。 
     259 
     260例 4-11 - `link_to()` 辅助函数 
     261 
     262    [php] 
     263    <p>Hello, world!</p> 
     264    <?php if ($hour >= 18): ?> 
     265    <p>Or should I say good evening? It's already <?php echo $hour ?>.</p> 
     266    <?php endif; ?> 
     267    <?php echo form_tag('mymodule/anotherAction') ?> 
     268      <?php echo label_for('name', 'What is your name?') ?> 
     269      <?php echo input_tag('name') ?> 
     270      <?php echo submit_tag('Ok') ?> 
     271      <?php echo link_to('I never say my name','mymodule/anotherAction?name=anonymous') ?> 
     272    </form> 
     273 
     274上面的代码生成的HTML与前一个例子完全一样,但是如果修改路由规则,所有的模版会根据规则重新格式URL。 
     275 
     276`link_to()`辅助函数,与很多辅助函数类似,接受另一个特殊的参数,这个参数用来传递HTML标签属性。例4-12是一个option属性的例子还有生成的HTML。option参数可以是一个数组或者一个简单的由几个`key=value`与空格组成的字符串。 
     277 
     278例 4-12 - 大多数辅助函数有Option参数 
     279 
     280    [php] 
     281    // 用数组作option参数 
     282    <?php echo link_to('I never say my name', 'mymodule/anotherAction?name=anonymous', 
     283      array( 
     284        'class'    => 'special_link', 
     285        'confirm'  => 'Are you sure?', 
     286        'absolute' => true 
     287    )) ?> 
     288 
     289    // 用字符串作option参数 
     290    <?php echo link_to('I never say my name', 'mymodule/anotherAction?name=anonymous', 
     291      'class=special_link confirm=Are you sure? absolute=true') ?> 
     292 
     293    // 结果一样 
     294     => <a class="special_link" onclick="return confirm('Are you sure?');" 
     295        href="http://localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous"> 
     296        I never say my name</a> 
     297 
     298任何使用symfony辅助函数输出HTML标签的时候,都可以在option参数中加入额外的属性(例如例4-12中的`class`属性)。你甚至可以以HTML 4.0的"快速而肮脏(quick-and-dirty)"的方式(不写双引号),symfony会用漂亮的XHTML方式输出。这是用辅助函数比写HTML快的又一个原因。 
     299 
     300>**NOTE** 
     301>由于需要需要额外的解析与转换,字符串形式比数组要慢。 
     302 
     303与其它辅助函数类似,链接辅助函数有好几种形式与参数。第9章将向你详细介绍这些内容。 
     304 
     305从请求中取得信息 Getting Information from the Request 
     306------------------------------------ 
     307 
     308无论用户通过表单(通常是POST请求)还是通过URL(GET请求),你都可以在动作中通过`sfActions`对象的`getRequestParameter()`方法取得相关的数据。例4-13演示了如何在`actionAction`中取得`name`参数的值。 
     309 
     310例 4-13 - 在动作中取得请求参数的值 
     311 
     312    [php] 
     313    <?php 
     314 
     315    class mymoduleActions extends sfActions 
     316    { 
     317      ... 
     318 
     319      public function executeAnotherAction() 
     320      { 
     321        $this->name = $this->getRequestParameter('name'); 
     322      } 
     323    } 
     324 
     325如果数据操作很简单,你甚至不必动作来取得参数值。模版可以直接通过`$sf_params`,它提供了`get()`方法来取得参数的值,类似于动作中的getRequestParameter()方法。 
     326 
     327如果 `executeAnotherAction()` 方法是空的, 例 4-14 中的这种方法也可以从`anotherActionSuccess.php`模版中取到`name`参数的值。 
     328 
     329例 4-14 - 直接从模版中取得参数的值 
     330 
     331    [php] 
     332    <p>Hello, <?php echo $sf_params->get('name') ?>!</p> 
     333 
     334>**NOTE** 
     335>为什么不直接使用`$_POST`,`$_GET`, 或 `$_REQUEST` 变量呢?因为如果你的URL的格式会变化(例如`http://localhost/articles/europe/france/finance.html` ,没有`?`或者`=`),这样这些PHP变量就不管用了,只有路由系统能够取得请求参数。还有你可能需要输入过滤器来防止恶意代码注入,只有保持所有的参数使用一个干净的参数holder的时候才能实现。 
     336 
     337`$sf_params`对象的作用比仅仅是数组的替代品。例如,如果你想判断一个请求参数是否存在,你可以只用`$sf_params->has()`方法而不必用`get()`方法取得实际的值,如利4-15。 
     338 
     339例 4-15 - 在模版中判断一个参数是否存在 
     340 
     341    [php] 
     342    <?php if ($sf_params->has('name')): ?> 
     343      <p>Hello, <?php echo $sf_params->get('name') ?>!</p> 
     344    <?php else: ?> 
     345      <p>Hello, John Doe!</p> 
     346    <?php endif; ?> 
     347 
     348你可能已经猜到这个一行代码就可以完成。与symfony里面的大多数getter方法一样,动作里的`getRequestParameter()`还有模版里的`$sf_params->get()`方法(实际上两者调用的是同一个对象的同一个方法)可以有第二个参数:默认值,在参数不存在的时候起作用。 
     349 
     350    [php] 
     351    <p>Hello, <?php echo $sf_params->get('name', 'John Doe') ?>!</p> 
     352 
     353总结 Summary 
     354------- 
     355 
     356在symfony里面,页面由一个动作(`actions/actions.class.php`文件里的一个方法,以`execute`开头)还有一个模版(`templates/`目录里的一个文件,通常以`Success.php`结尾)组成。功能有关联的页面组成模块。写模版有辅助函数帮忙,辅助函数是symfony提供的返回HTML代码的函数。并且你需要把URL考虑成辉映的一部分,URL也可以根据需要重新安排格式,所以你需要避免绕过超链接辅助方法直接写动作的URL。 
     357 
     358一旦你了解了这些基本原理,你就可以开始用symfony写一个完整的web应用程序了。但是这需要花很长时间,因为几乎所有的功能都可以通过symfony的某种功能来简化开发……所以这本书还没结束。 
     359}}}