In diesem Kapitel erfahren Sie, wie Sie ein Modul erstellen, bei dem es sich um ein Strukturelement handelt, das eine Seite organisiert. Gleichzeitig lernen wir auch, wie man eine Seite erstellt, die in eine Aktion und eine Vorlage unterteilt ist. Der Grund, warum sie in Aktionen und Vorlagen unterteilt ist, liegt im MVC-Muster. Links und Erkennung sind grundlegende Seiteninteraktionen, und wir lernen, wie man diese Elemente in Vorlagen einfügt und sie in Aktionen verarbeitet.
Erstellen Sie ein Modul-Framework
Genau wie wir in Kapitel 2 gelernt haben, organisiert Symfony Seiten in Modulen. Bevor wir eine Seite erstellen, müssen wir ein Modul erstellen und es in einer leeren Shell mit einer Dateistruktur initialisieren, die Symfony erkennen kann.
Symfony-Befehlszeile automatisiert die Erstellung von Modulen. Wir müssen lediglich die Aufgabe „init-module“ aufrufen und den Programmnamen und den Modulnamen als Parameter verwenden. Im vorherigen Kapitel haben wir ein myapp-Programm erstellt. Um diesem Programm ein mymodule-Modul hinzuzufügen, können wir den folgenden Befehl eingeben:
> cd ~/myproject
> ~/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/functions/myapp/mymoduleActionsTest.php
>> /test/functions/myapp/mymoduleActionsTest.php
>> tokens ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>> /myapp/modules/mymodule/templates/indexSuccess.php
ist vom Verzeichnis actions/,config/,lib/,templates/,validate/ getrennt. Dieser Befehl erstellt nur drei Dateien. Der im test/-Verzeichnis befindliche Unit-Test ist der Unit-Test. actions.class.php verweist auf die Begrüßungsseite des Standardmoduls. Die Datei templates/indexSuccess.php ist leer.
Die standardmäßig in der Datei actions/actions.class.php generierten Aktionen:
<?php class mymoduleActions extends sfActions { public function executeIndex() { $this->forward('default', 'module'); } }
In diesem Kapitel werden wir nicht die Standardindexaktion verwenden, daher können wir Aktionen verwenden, um den ExecuteIndex zu entfernen ()-Methode aus der Datei .class.php und löschen Sie die Datei indexSuccess.php aus dem Verzeichnis templates/.
Neben der Kommandozeile stellt Symfony auch andere Methoden zur Initialisierung eines Moduls zur Verfügung. Eine Methode besteht darin, Verzeichnisse und Dateien manuell zu erstellen. In vielen Fällen dienen die Aktionen und Vorlagen eines Moduls dazu, Daten aus einer bestimmten Datentabelle zu manipulieren. Da der erforderliche Code zum Erstellen, Abrufen, Aktualisieren und Löschen von Datensätzen aus einer Datentabelle normalerweise derselbe ist, stellt Symfony einen Mechanismus namens Framework zur Verfügung, mit dem wir diesen Code generieren können. Schauen Sie sich Kapitel 14 an, wo wir mehr über diese Technik erfahren können.
Eine Seite hinzufügen
In Symfony wird die Logik hinter der Seite in der Aktion gespeichert, während sich die Oberfläche in der Vorlage befindet. Seiten ohne Logik erfordern weiterhin eine leere Aktion.
Eine Aktion hinzufügen
Auf die Seite „Hallo Welt!“ wird über eine myAction-Aktion zugegriffen. Um diese Aktion zu erstellen, fügen Sie einfach eine Methode „executeMyAction“ in der Klasse „mymoduleActions“ wie folgt hinzu:
<?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!"的页面只有一行的代码的模板。
Hello, world!
<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帮助器,并且以我们通常的方式来编写代码,但是这会是一个巨大的损失。
注意,短开放标记的用法(=,等同于
表单处理有专门的一章进行讨论,因为Symfony提供了许多工具,绝大数的帮助器,来使其简单。我们将会在第10章了解到关于帮助器更多的内容。
链接到另一个动作
我们现在已经知道在动作名字与需要调用的URL之间有一个分离。所以我们使用下面的方式来创建到另一个动作的链接时,他只会工作在默认的路由系统中。如果我们以后决定改变URL的样子,那么我们就需要查看所有的模板来改变超链接。
超链接,通常的方法:
<a href="/myapp_dev.php/mymodule/anotherAction?name=anonymous"> I never say my name </a>
要避免这样的麻烦,我们应总是使用link_to()帮助器来我们的程序动作创建超链接。下面的例子演示了超链接帮助器的用法。
link_to()帮助器:
<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与前面的相同,所不同的就在于当我们改变我们的路由规则时,所有的模板都会正确工作,并且重新格式化URL。
link_to()帮助器,就像其他的帮助器,会接受特定选项的额外参数和额外的标签属性。下面的例子显示了一个可选参数以及生成的HTML。选项参数或者是一个相关的数组或者是由空格分隔的显示key=value的简单字符串。
大多数帮助器接收一个可选参数:
// Option argument as an associative array
<?php echo link_to('I never say my name', 'mymodule/anotherAction?name=anonymous', array( 'class' => 'special_link', 'confirm' => 'Are you sure?', 'absolute' => true )) ?>
// Option argument as a string <?php echo link_to('I never say my name', 'mymodule/anotherAction?name=anonymous', 'class=special_link confirm=Are you sure? absolute=true') ?> // Both calls output the same => <a class="special_link" onclick="return confirm('Are you sure?');" href="http://localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous"> I never say my name</a>
任何时候我们使用一个Symfony帮助器来输出一个HTML标记时,我们可以在可选参数中插入额外的标记属性。我们可以使用HTML 4.0的方式来编写这样的属性,而Symfony将会以更简洁的格式进行输出。这也就是为什么帮助器会比HTML更容易编写的原因。
因为他需要一个额外的分析与转换,字符串语法比数组语法要慢一些。
与表单帮助器相类似,链接帮助器有更多的数量和选项。第九章将会详细讨论他们。
由请求得到信息
无论用户通过表单发送信息(通常以POST请求的方式)还是通过URL(GET请求),我们可以通过带有sfActions对象的getRequestParameter()方法的动作来获取数据。下面的例子显示如何在anotherAction中得到name参数的值。
在动作中由请求参数得到数据:
<?php class mymoduleActions extends sfActions { ... public function executeAnotherAction() { $this->name = $this->getRequestParameter('name'); } }
如果数据的处理是简单的,我们甚至并不需要使用动作来得到请求参数。模板可以访问一个名为$sf_params的对象,他提供了get()方法来得到请求参数,就如同动作中的getRequestParameter()方法。
如果executeAnotherAction()方法是空的,下面的例子显示了anotherActionSuccess.php模板文件如何得到同样的name参数。
在模板中直接由请求参数得到数据:
<p>Hello, <?php echo $sf_params->get('name') ?>!</p>
那么为什么不使用$_POST,$_GET或是$_REQUEST变量呢?因为我们的URL将会不同的方式进行格式化(http://localhost/articles/europe/france/finance.html),这样通常的PHP变量就会再起作用,并且只有路由系统可以得到请求参数。而我们希望添加输入过滤来阻止恶意代码注入,而这只有当我们将所有的请求参数保存在一个简洁的参数装配器中才可能。
$sf_params对象比仅提供一个与数组等同的方法要强大得多。例如,如果我们只是希望检测一个请求参数是否存在,我们可以简单的使用$sf_params->has()方法,而不使用get()测试实际的值。
在模板中测试请求参数的存在:
has('name')): ?> <p>Hello, <?php echo $sf_params->get('name') ?>!</p>Hello, John Doe!
我们已经猜到了,这可以在单一的代码行中编写。与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特性来完成的。