Symfony 框架实战教程——第二天:创建新页面

Symfony 框架实战教程——第二天:创建新页面

Chris Yue 21 comments
Posts

昨天我们已经成功初始化一个 Symfony 项目,今天我们将在此基础上继续添砖加瓦。

在此之前,我们先明确一下我们要实现什么功能,在开始开展具体的代码工作前先明确自己的目标是一个节省时间的好习惯。我们的需求如下:

  1. 用户可以使用新浪微博或者 QQ 帐号登录。
  2. 用户可以投稿,需要填写的内容为“标题”+“正文”
  3. 用户可以对某篇文章进行评论

在以上的基础上,我们继续具体化我们的需求:

  1. 用户的内容都将使用 markdown 格式
  2. 评论内容不可超过 140 个字
  3. 新闻内容不可超过 5000 个字
  4. 标题内容不可超过 70 个字

好,到这里我们的需求已经很明确了,虽然简单得似乎不可能会有人用的样子~

修改配置文件

此时项目里还有很多不需要的文件。比如昨天我们看到的 Symfony 自带的演示页面。这些文件都应该被清理。不过清理之前请等一会儿,演示页面里有一个“configure”功能我们还可以利用一下(在较新的版本里已经没有 configure 了,如果是,跳过接下来的两段,继续往后看)。点击了“configure”按钮以后我们可以对数据库、以及网站的密钥进行配置。其中第二步骤是设置网站的“密钥”,先不用管“密钥”的用途,只管点“下一步”就行。

注意:由于我们此时需要使用 Mysql 来作为我们的数据存储方案,所以这里我们需要安装 Mysql,并且在第一步里将 driver 设置为 PDO_Mysql。由于我们这里只介绍 Symfony,关于 Mysql 的安装,不太熟悉的同学可以自行查询,相关文档也是非常之多,这里就略过了。当然,如果对存储层非常熟悉的同学,你们也可以选择熟悉的驱动,Mysql 并不是唯一方案。

当两个步骤都完成之后,Symfony 会提示你,新的配置已经取代了旧的配置。此时就可以把此演示项目从我们的项目代码里清理掉了。

刚才的步骤,其实只是修改了 app/config/parameter.yml 文件而已,直接修改也是可以的。此文件里包含了一些显而易见的配置,如果你英语还过关的话,应该一看就明白。

注意:如果安装的是 2.7 以及以上版本 Symfony,只能直接修改 app/config/parameter.yml 文件

清理不需要的文件和代码

首先需要清理的是 app/AppKernel.php 文件。在这里首先说一个 Symfony 世界里的“术语”:

什么是 Bundle

我认为 Bundle并没有明确的定义,一般来说,如果某几个功能,相互之间有关联,并且相互影响,或者都属于某一类功能,这些功能就可以捆绑在一起成为一个 Bundle。Bundle 是一个目录,里面包含了此 Bundle 的相关代码以及配置文件。“Bundle”本来就有“一捆”的意思。比如 Symfony 自带演示项目 Acme,就是一个 Bundle 的例子(在 2.7+ 版本里已经默认去掉了此 Bundle 而直接安装的 AppBundle,不过 AcmeDemoBundle 相关的话题也最好看看,因为可能包含一些你需要理解的概念,以及常见问题的处理方式)。在 AcmeDemoBundle 里的所有代码,都是为了演示用的,所以大家可以随意删除此 Bundle 而不用担心会影响现有的项目。但为了大家的入门速度以及不把大家搞晕,这里先不多说了。

现在打开 app/AppKernel.php

仔细观察 registerBundles(注册 Bundles)方法,可以看到此方法有许多名为 XxxBundle 的实例。所有的 Bundle 都需要一个类作为此 Bundle 的“代表”。只有 Bundle 的代表在此方法里被注册了,才可以使用此 Bundle 里的配置以及服务。大家可以看到此方法里已经注册了许多 Bundle。假如我们不使用 twig 作为我们的模板引擎,我们是完全可以把 TwigBundle 那行直接删除掉的。支持 Symfony 框架的第三方库,都是以 Bundle 的方式存在。后面我们便会举例子如何注册第三方 Bundle。

之前已经透露,演示项目的 Bundle 名叫“AcmeDemoBundle”,我们直接把 AcmeDemoBundle 那一行删掉。注意 AcmeDemoBundle 是在 if 里的,意思是如果当前环境是 dev 或者 test,才注册 AcmeDemoBundle。这个判断是什么意思?大家打开 web 目录,可以发现有 app.php 以及 app_dev.php 两个文件,大家先不要急着看这两个文件的内容,只用知道这两个文件都是入口文件就行了。所有的请求,都会首先执行它们中的其中一个,其实看文件名大家也应该明白 app_dev.php 是开发的时候用的入口文件。昨天使用 php app/console server:start localhost:8000 命令开启 web server 的时候,此命令已经自动将 app_dev.php 作为了入口文件。当我们的项目完成上线,就应该使用 Nginx、Apache 等 Web Server 把 app.php 作为入口文件。

开发环境不同会导致什么不同?再来看看 if 里的代码:不仅 AcmeDemoBundle,在这个 if 里的所有 Bundle 都是为了开发而存在的,比如 DebugBundle 是为了在代码里使用 dump() 方法打印格式化好的变量信息,WebProfilerBundle 则是为了收集开发所需要的调试数据,并且有好看的页面可以显示这些数据,是我们开发的好帮手。我们看到演示页面最下面的那条工具栏,就是 WebProfilerBundle 里包含的,后面我们将经常使用此工具栏做开发调试分析工作。

app/AppKernel.php 删除了 AcmeDemoBundle 那行代码之后,刷新页面,发现报错:

FileLoaderLoadException in FileLoader.php line 120: Bundle “AcmeDemoBundle” does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() method of your AppKernel.php file? in @AcmeDemoBundle/Resources/config/routing.yml (which is being imported from “/…/app/config/routing_dev.yml”). Make sure the “AcmeDemoBundle” bundle is correctly registered and loaded in the application kernel class.

意思是说,你是否忘记在 AppKernel.php 文件里注册 AcmeDemoBundle?因为在 app/config/routing_dev.yml 里还有 AcmeDemoBundle 的相关配置。

错误信息给我们提供了一个线索:app/config/routing_dev.yml 文件里也有需要删除的代码。我们将此文件打开,将一下代码也删除掉(代码里也有注释说“以下代码应该被删除”)

此文件是一个“YAML”格式文件,关于此文件格式这里也不多说,大家也不用有太多压力,因为 YAML 格式非常好懂,Symfony 的大多数配置文件,都是使用的 YAML 格式。Symfony 支持多种文件格式作为配置文件,常见的还有 XML 文件,以及直接使用 PHP 来写配置文件。对于配置文件的选择来说,XML 可以使用 DTD 来做校验,所以一些风格严谨的第三方 Bundle 内部的配置文件是用的 XML,但 XML 有写起来繁琐的问题,而编写方便正是 YAML 的优点。在这里我们遵守 Symfony installer 帮我们做的选择:使用 YAML。需要注意:YAML 和 XML 不是一个 Bundle 只能用一种,他们是可以混用的,而且从性能速度来说,没有丝毫差别,因为最终都会被编译成 PHP 文件。除了以上说的几种格式外,还有一种叫做“注解”的格式,后面再介绍。

routing***.yml 定义了访问我们的项目的访问路径。Symfony 框架使用的“前端控制器”模式来处理 HTTP 访问的需求,即每一种形式的路径,都将映射到某个类的某个方法来处理。比如说当用户访问 /hello/{name} 路径的时候,我们可以将此路径映射到 AppBundle 里的 HelloController(一般称为“控制器类”)的 helloAction($name)(一般称为控制器方法)方法来处理。routing***.yml 文件就是用来描述这种映射关系的。并且 routing***.yml 文件可以有包含关系,我们可以看到 routing_dev.yml 包含了 routing.yml 文件。另外,我们从文件名也可以看出, routing_dev.yml 是开发环境才加载的配置。

routing_dev.yml 里删除掉 acme 相关的路由以后,再访问首页。我们可以发现错误信息变了:

No route found for “GET /”

“route”即“路由映射规则”,出现此错误说明已经没有关于“GET /”路径相关的配置了。这说明至少从配置上,我们已经把 AcmeDemoBundle 删除掉了。

接下来我们再删除掉 src/Acme 目录,清理工作便告一段落,说是一个段落的原因是还有一个比较关键的配置文件我们没有提到,但不影响接下来的开发。以后会说。

添加页面

每次访问首页都报错,不是个好兆头,怎么着我们得有一个首页,无论有多简单。

按我们之前所说,要想首页能够被访问,我们得在 routing***.yml 里添加有关首页的配置。

由于首页是无论开发环境还是生产环境都需要访问的,我们就把配置写在 routing.yml 里好了,注意之前说过 routing_dev.yml 已经包含了 routing.yml 了。

我们打开 app/config/routing.yml文件,可以看到已经有如下内容:

这里的 resource 指向的不是一个文件,而是一个路径:@AppBundle 我想不用多说,一定是指 AppBundle 所在的目录,也就是 src/AppBundle。是的,resource 可以不用指定某个具体的文件,目录也行,意思是:此目录内的所有配置文件都包含进来,甚至包括子目录的配置。

然后 type 的值为 annotation,这就是之前说的“注解”格式。

我们打开 @AppBundle/Controller/ 里随便什么文件,看看注解格式到底是个啥。

@AppBundle/Controller/ 目录里目前只包含一个 DefaultController.php,打开此 PHP 文件:

仔细观察,像是配置的代码,很明显是 @Route("/app/example", name="homepage") 那一行。原来“注解”格式,即是写在代码里的注释。使用此格式的配置有一些其他格式不可比拟的好处,比如方便重构(举个栗子:控制器名字改了,改1个文件 VS 改2个文件)。

既然 Symfony installer 帮我们生成了此文件,我们也继续沿用。我们要做的只是把路径改成首页。然后路由名改短一点,路由名是个什么,后面会说到:

这个时候我们再访问首页,会出现写着“Homepage.”的页面。

这个“Homepage.”又是从哪儿来的?看代码里面给我们提供的线索:indexAction 里返回了一个$this->render('default/index.html.twig'),如果英语过关,很容易看出来此方法做的事情,就是“渲染”了一个模板文件default/index.html.twig

模板文件默认目录位于 app/Resources/views/,所以我们要找的文件位于 app/Resources/views/default/index.html.twig,打开此文件可以看到里面有一行 Homepage.,以及一些其他的代码。现在我们不用管其他的代码。

为了方便开发我们的“新闻”板块。我们先给首页加一个链接 /news

我们可以直接将 Homepage. 替换成 <a href="/news">新闻</a>。但是这样做有一个不好的地方:如果想改路径,比如改成 /新闻,那么每个连接到“新闻”的 href="/news" 都需要改一遍。Symfony 以及 Laravel 或者 ROR 等现代框架,几乎都支持“双向路由”,即在路径和对应的控制器方法之间,再加一个路由名。此路由名可对应一个路径,又对应一个控制器方法。前端模板里不再直接写路径,而是写路由名:

以后想修改路径,都只用改一下配置文件即可。

修改好以上代码,再访问首页,又会出现以下错误:

An exception has been thrown during the rendering of a template (“Unable to generate a URL for the named route “news_index” as such route does not exist.”) in default/index.html.twig at line 4.

意思是,目前还没有一个叫 news 的路由规则。OK 我们现在来创建它:

我们把新闻相关的路径都放在 AppBundle\Controller\NewsController 类里:

并且为其创建模板文件 app/Resources/views/news/index.html.twig,目前就是空文件就行。

此时再刷新首页,错误消失。并且“新闻“已经可以点击。

创建文件时需要大家注意的是,一定要确认代码的文件的编码格式是 UTF-8,否则会出现不可预料的字符乱码问题。

第三天

Symfony 框架实战教程——第二天:创建新页面 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

文章不错,我要帮站长分担建站费!
天使投赏人

21 Comments

PHP程序员雷雪松

九月 29, 2016 在 5:27 下午

支持一下@!!!

杨晓刚

六月 8, 2016 在 5:23 下午

之前已经透露,演示项目的Bundle名叫“AcmeDemoBundle”,我们直接把AcmeDemoBundle那一行删掉!

请问!这个AcmeDemoBundle在哪儿? 你给我找找啊!

    Chris Yue

    六月 13, 2016 在 1:24 上午

    没有那就不用管了呗,Symfony 版本迭代之后完全有可能已经不默认安装演示用的 Bundle 了

     

diudiu

十一月 10, 2015 在 11:41 上午

将homepage 替换成<a href> 就不行。syntax error

    Chris Yue

    十一月 15, 2015 在 2:19 上午

    你替换哪儿的homepage了?完整的错误信息是什么?

     

山中大王

七月 17, 2015 在 4:07 下午

use Sensio\Bundle\FrameworkExtraBundle\ConfigurationRoute; 路径错误use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;反复查了几遍

    Chris Yue

    七月 17, 2015 在 10:30 下午

    谢谢指正

     

Eva

四月 22, 2015 在 2:52 下午

其实也不能算是解决,就是如果我没有重新创newscontroller,在原先得代码该就没有问题!我晚上回去申请个git传上去,回家试试,麻烦了

Eva

四月 22, 2015 在 2:39 下午

我已经fix了谢谢

Eva

四月 21, 2015 在 11:45 上午

FileLoaderImportCircularReferenceException in FileLoader.php line 97:
Circular reference detected in “D:\WWW\news\app/config/routing_dev.yml” (“D:\WWW\news\app/config/routing_dev.yml” > “D:\WWW\news\app/config\routing.yml” > “D:\WWW\news\src\AppBundle/Controller/” > “D:\WWW\news\app/config/routing_dev.yml”).

因为比较菜,请不要嫌弃!
是这样我按照你的步骤一步步来仔细检查,还是没能发现哪里坏了

    Chris Yue

    四月 21, 2015 在 7:57 下午

    你把Acme的路由去掉了吗(在routing_dev.yml里)。

     

    Eva

    四月 22, 2015 在 10:00 上午

    去了的

     

    Eva

    四月 22, 2015 在 10:16 上午

    实在弄NewsController出错的

     

    Eva

    四月 22, 2015 在 11:24 上午

    是在引用symfony文件夹下的controller类出现了循环引用错误

     

    Chris Yue

    四月 22, 2015 在 1:53 下午

    你把NewsController和routing_dev.yml 以及 routing.yml 发来看看。如果可以的话你最好是把你的代码提交到github,或者国内的coding.net,把项目链接发给我,我看见你写的代码

     

ccna30

三月 26, 2015 在 11:03 上午

您写道“目前还没有一个叫news的路由规则。OK我们现在来创建它:”具体如何创建呢?我完全照抄了NewsController.php文件,还是显示“An exception has been thrown during the rendering of a template (“Unable to generate a URL for the named route “news_index” as such route does not exist.”) in default/index.html.twig at line 4.。。

    ccna30

    三月 26, 2015 在 11:33 上午

    问题解决了,但是显示的中文是乱码?����

     

    Chris Yue

    三月 26, 2015 在 6:23 下午

    请确保您的代码文件都是utf-8的,你可以查一下你常用的编辑器怎么看编码,一般来说是这个问题。然后确认一下数据库的表也是utf-8的:

     

    ccna30

    三月 27, 2015 在 12:10 下午

    果然是编码的问题,问题解决了,感谢。

     

    Chris Yue

    三月 27, 2015 在 9:37 下午

    客气,其实你也是在给我调毛病,我也得感谢你

     

ccna30

三月 26, 2015 在 10:50 上午

新闻是写在default/index.html.twig里面吗?

ccna30进行回复 取消回复

68 − 66 =