mvc的三层架构,mvc三层结构

  mvc的三层架构,mvc三层结构

  在第二天的学习中,我们学习了如何基于关系数据模型构建对象模型,并为其中一个对象生成了程序框架。顺便说一下,前一天生成的程序代码可以在askeet的SVN仓库获得:

  http://svn.askeet.com/

  我们第三天的目标是为这个网站定义一个漂亮的结构布局,以问题列表为默认主页,显示对某个问题感兴趣的用户数量,将样本文本文件迁移到数据库进行数据测试。要做的事情不多,但是要读要懂的东西很多。

  为了阅读本教程,我们需要熟悉Symfony中解释的工程、过程、模块和动作的概念。

  MVC模式

  今天是我们第一次进入MVC架构的世界。这是什么意思?简单来说,生成页面的代码根据其特性位于不同的文件中。

  如果代码独立于页面专注于数据的操作,那么它应该位于模型中(大多数情况下,在askeet/lib/model/目录中)。如果他专注于最终显示,他应该位于视野中。在Symfony中,视图层基于模型(如Askeet/Apps/Frontend/Modules/Question/Templates/)和配置文件。最后,将所有这些链接在一起并将网站逻辑转换为PHP代码的程序代码位于控制器中,而在Symfony中,指定页面的控制器称为动作。我们可以在symfony中的MVC实现一章中了解更多关于这个模型的内容。

  然而今天,我们的程序只做了一些小的改动,我们将操作许多不同的文件。不用麻烦,因为文件组织与不同代码层的分离很快就会变得明显和有用。

  更改布局

  在设计模式中,由操作调用的模板内容被集成到全局模板或布局中。换句话说,布局包含了所有界面的不变部分,并且修饰了动作的结果。打开默认布局(askeet/apps/frontend/templates/layout . PHP)并将其更改为以下内容:

  ! DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www . w3 . org/TR/XHTML 1/DTD/XHTML 1-Transitional . DTD

  html xmlns= http://www . w3 . org/1999/XHTML XML:lang= en lang= en

  头

  ?php echo include_http_metas()?

  ?php echo include_metas()?

  ?php echo include_title()?

  link rel=快捷图标 href=/favicon.ico /

  /头

  身体

  div id=header

  保险商实验所

  李?php echo link_to(about , @homepage )?/李

  /ul

  h1?PHP echo link _ to(image _ tag( askeet _ logo . gif , alt=askeet ), @homepage )?/h1

  /div

  div id=content

  div id=content_main

  ?PHP echo $ SF _ data-getRaw( SF _ content )?

  分区/分区

  /div

  div id=content_bar

  !-暂时没有-

  分区/分区

  /div

  /div

  /body

  /html

  我们尽可能让标记易于理解,并将所有样式转移到CSS样式表中。这里我们将不描述样式文件,因为CSS语法不是本教程的目的。我们可以在SVN仓库下载这些风格文件。

  我们创建了两个样式文件(main.css,layout.css)。将它们复制到我们的askeet/web/css/目录,并编辑我们的frontend/config/view.yml文件以更改自动加载的样式文件:

  样式表:[主,布局]

  这个时候布局还是轻量级的,后面我们会重新构建。模板中很重要的一点是head部分,它是自动生成的,sf_content变量包含了动作的结果。

  我们可以通过请求主页来检查修改是否可以正确显示——这次是在开发环境中:

  http://askeet/frontend_dev.php/

  环境的描述

  如果我们想知道http://askeet/frontend_dev.php/和http://askeet/的区别,那么我们需要看一下Symfony的配置部分。现在我们只需要知道它们指向的是同一个程序,只是环境不同而已。一个环境是一个独特的配置,此时框架的特性可以根据需要决定是否激活。

  在这种情况下,/frontend_dev.php/URL指向开发环境。此时,将在每个请求时解析整个配置,HTML缓存未激活,调试工具可用(包括窗口右上角的半透明工具栏)。而/URL——相当于/index . PHP/——指向生产环境。此时,配置被“编译”,并且为了加速页面传输,调试工具栏被禁用。

  这两个PHP脚本——frontend _ dev.php和index . PHP——被称为前端控制器,所有对程序的请求都由它们处理。我们可以在askeet/web/目录中找到它们。实际上,index.php应该被命名为frontend_dev.php,但由于frontend是我们创建的第一个程序,Symfony推测我们可能希望它作为默认程序,所以我们将其重命名为index.php,这样我们就只能在生产环境中请求/来查看我们的程序。如果想了解更多通常MVC模型中的前端控制器和控制器层,可以查看Symfony中的控制器章节。

  一个好的规则是,我们在开发环境中浏览,直到我们对所有的特性都满意,然后切换到生产环境,检查它的速度和良好的URL。

  记住,当我们添加一个新的类或者更改配置文件时,为了在生产环境中查看结果,我们应该首先清除缓存。

  重新定义主页

  现在,当我们请求新网站的主页时,他显示一个“祝贺”页面。一个更好的主意是显示一个问题列表。为此,打开前端程序的路由配置文件(askeet/apps/frontend/config/routing . yml),导航到homepage:部分并进行更改:

  主页:

  网址:/

  param: {模块:问题,操作:列表}

  在开发环境中刷新页面(http://askeet/frontend_dev.php),现在会显示问题列表。

  如果我们是一个好奇的人,我们可能会寻找带有“祝贺”信息的页面。如果在askeet目录中找不到这个文件,我们会很惊讶。其实default/index动作的模板是在Symfony的数据目录中定义的,它是独立于项目的。如果我们想覆盖它,我们可以在我们自己的目录中创建一个默认模块。

  路由系统提供的功能后面会详细讨论,但是如果感兴趣可以看Symfony中routing这一章。

  定义测试数据

  主页的列表显示仍然是空的,除非我们添加自己的问题。当我们开发一个程序时,拥有一些测试数据是一个好主意。手动输入测试数据相当痛苦,这也是Symfony可以使用文件迁移到数据库的原因。

  我们将在目录askeet/data/fixtures/(需要创建这个目录)中创建一个测试数据文件。使用以下代码创建名为test_data.yml的文件:

  用户:

  匿名:

  昵称:匿名

  名字:匿名

  姓氏:懦夫

  法比安:

  昵称:法布波特

  名字:杨奇煜

  姓氏:权力者

  弗朗索瓦:

  昵称:弗朗索瓦

  名字:弗朗索瓦

  姓氏:扎尼诺托

  问题:

  q1:

  标题:今晚我和女朋友做什么?

  用户标识:法比安

  正文:

  晚饭前我们在邓肯甜甜圈前见面,

  我完全不知道该拿她怎么办。

  她对编程、太空歌剧电影和昆虫都不感兴趣。

  她挺可爱的,所以我真的需要找些东西

  那会让她在我身边再呆一个晚上。

  第二季度:

  标题:我能给我的继母提供什么?

  用户标识:匿名

  正文:

  我的继母拥有继母通常能得到的一切

  (手表,吸尘器,耳环,del.icio.us账号)。

  她的生日就在下周,我破产了,我知道

  如果我不给她一些甜的东西,我的女朋友

  一个月都不会看我的眼睛。

  q3:

  标题:我怎样才能给我的博客带来流量?

  用户标识:弗朗索瓦

  正文:

  我有一个非常棒的博客

  关于我的班级、朋友、宠物和最喜欢的电影。

  兴趣:

  i1: {用户id: fabien,问题id: q1 }

  i2: {用户id: francois,问题id: q1 }

  i3: {用户标识:弗朗索瓦,问题标识:q2 }

  i4: { user_id: fabien,question_id: q2 }

  首先,也许我们会在这里认出YAML语法。如果我们不熟悉Symfony,那么也许我们不知道YAML格式是框架中最喜欢的配置文件格式。这不是唯一的——如果我们也可以使用XML或。ini文件,我们可以很容易地添加一个配置处理器来允许Symfony读取它们。如果我们有时间和耐心,我们可以在Symfony的实际配置一章中读到更多关于YAML和Symfony的配置。现在,如果我们不熟悉YAML语法,那么我们需要立即开始,因为本教程广泛使用YAML语法格式。

  好了,现在回到测试数据文件。他定义对象实体并通过其内部名称来识别它。这个标签对于链接相关对象很有用,不需要定义id。例如,创建的第一个对象是User类,标识为fabien。第一个问题标识为q1。通过指定相关的对象标签,很容易创建一个类的对象:

  兴趣:

  i1:

  用户标识:法比安

  问题id: q1

  上面给出的数据文件使用简短的YAML语法来描述这些内容。我们可以在Symfony的数据文件章节中了解更多关于数据迁移的信息。

  我们不需要为created_at和updated_at列定义值,因为Symfony知道默认情况下如何填充这些字段。

  创建一个批处理文件来迁移数据。

  下一步是实际迁移数据库,我们希望使用一个可以在命令中调用的PHP脚本来完成这些任务——一个批处理过程。

  春季批次

  在askeet/batch/目录下创建一个名为load_data.php的文件,内容如下:

  ?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

  define(SF_ROOT_DIR),realpath(dirname(__FILE__)。/.));

  定义( SF_APP , frontend );

  define(SF_ENVIRONMENT , dev );

  define(SF_DEBUG ,true);

  需要一次(SF_ROOT_DIR。目录_分隔符。应用程序。目录_分隔符。SF_APP。目录_分隔符。“配置”。目录_分隔符。config . PHP’);

  //初始化数据库管理器

  $ database manager=new sfDatabaseManager();

  $ database manager-initialize();

  ?

  这个脚本什么都不做,或者几乎什么都不做:它定义一个路径、程序和要配置的环境,加载配置,并初始化数据管理器。但这已经很多了:这意味着下面编写的代码将通过使用自动加载的类自动连接到Propel对象和Symfony根类。

  如果我们测试过Symfony的前端控制器(比如askeet/web/index.php),会发现这些代码非常熟悉。这是因为就像批处理请求一样,每个web请求都需要访问相同的对象和配置。

  数据导入

  既然批处理的框架已经准备好了,是时候让它有所成就了。需要完成的批次:

  1读取YAML文件

  2创建一个推进对象实例

  3在链接数据库的数据表中创建相关记录。

  这听起来很复杂,但是在Symfony中,由于sfPropelData对象,我们只需要两行代码就可以做到这一点。在askeet/batch/load_data.php脚本的最后?在之前添加以下代码:

  data=new sfPropelData();

  $ data-load data(SF config:get( SF _ data _ dir )。目录_分隔符。夹具’);

  就是这样。创建一个sfPropelData对象,并通知它将指定目录(我们的fixtures目录)中的所有数据加载到databases.yml配置文件中定义的数据库中。

  这里的DIRECTORY_SEPARATOR常量用于兼容Windows和*nix平台。

  开始批处理

  最后,我们可以检查这些代码是否值得我们讨论,并在命令行输入以下命令:

  $ CD/home/SF projects/askeet/batch

  $ php加载数据

  通过刷新开发主页,我们可以在数据库中检测到这些修改:

  http://askeet/frontend_dev.php

  数据已成功加载。

  默认情况下,sfPropelData对象会在加载新数据之前删除所有数据。我们还可以在当前数据后添加:

  $ data=new sfPropelData();

  $ data-setDeleteCurrentData(false);

  $ data-load data(SF config:get( SF _ data _ dir )。目录_分隔符。夹具’);

  访问模块中的数据

  当请求问题模块的列表操作时,显示的页面是executeList()(可以在Askeet/Frontend/Modules/Question/Actions/action . class . PHP操作文件中找到)方法传递给Askeet/Apps/Frontend/Modules/Question/Templates/list success . PHP模板的结果。这是基于Symfony的控制器一章中解释的名称转换。让我们来看看执行的代码:

  actions.class.php:

  公共函数executeList()

  {

  $ this-questions=question peer:do select(new Criteria());

  }

  listSuccess.php:

  .

  ?PHP foreach($ questions as $ question):

  tr

  td?php echo link_to($question- getId(), question/show?id=。$question- getId())?/td

  td?php echo $question- getTitle()?/td

  td?php echo $question- getBody()?/td

  td?php echo $question- getCreatedAt()?/td

  td?php echo $question- getUpdatedAt()?/td

  /tr

  ?php endforeach?

  一步一步,它的工作如下:

  1该操作请求满足空条件的问题表的记录。

  2记录列表放在一个数组($questions)中,并传递给模板

  3模板在动作传递的问题中循环。

  4模板显示记录中每一列的值。

  在Symfony的proper-build-model命令调用中生成-getId()、- getTitle()、- getBody()和-getBody()等方法,用于获取Id、Title、body等数据字段的值。这些是标准的获取方法,通过在域名前添加一个get前缀来格式化,而Propel也提供了一个带有set前缀的标准设置方法。Propel文档描述了为每个类创建的访问方法。

  我们可能困惑的是question peer:Do Select(new criteria())调用,这也是一个标准的Propel请求。Propel文档会详细解释。

  如果上面写的代码我们没有完全理解和担心,过几天就清楚了。

  修改问题/列表模板

  现在,数据已经包含了对某个问题感兴趣的记录,因此应该很容易找到对某个问题感兴趣的用户。如果我们在askeet/lib/model/om/中查看Propel生成的BaseQuestion.php类,我们会注意到有一个-getInterests()方法。Propel会在兴趣数据表的定义中检测到question_id外键,从而推测会有一些对某个问题感兴趣的用户。这样通过修改listsuccess.php的模板(askeet/frontend/modules/question/templates/)就可以很容易的显示出我们想要的东西。在这个过程中,我们将删除那些难看的表格,并用我们漂亮的div格式替换它们:

  ?php use_helper(Text )?

  h1常见问题/h1

  ?PHP foreach($ questions as $ question):

  差异

  差异

  div id=interested_in_?php echo $question- getId()?

  ?PHP echo count($ question-getInterests())?

  /div

  /div

  h2?PHP echo link _ to($ question-getTitle(), question/show?id=。$question- getId())?/h2

  差异

  ?PHP echo truncate _ text($ question-getBody(),200)?

  /div

  /div

  ?php endforeach?

  在这里,我们可以看到与原始listSuccess.php相同的foreach循环。link_to()和truncate_text()函数是Symfony提供的模板助手。第一个创建了同一个模块的另一个动作的超链接,而第二个将问题的内容缩短到200个字符。link_to()助手是自动加载的,但是如果我们想要使用truncate_Text(),我们必须声明使用该助手的文本组。

  现在我们可以刷新main来测试我们的新模板:

  http://askeet/frontend_dev.php/

  感兴趣的用户数量显示在每个问题附近。要获得上面的显示,请下载main.css样式文件并将其放在askeet/web/css/目录中。

  清楚的

  proper-generate-crud命令将创建一些我们不需要的动作和模板。现在是时候摆脱他们了。

  askeet/apps/frontend/modules/question/actions/actions . class . PHP中要移除的操作:

  *执行索引

  *执行编辑

  *执行更新

  *执行创建

  *执行删除

  askeet/apps/frontend/modules/question/templates/directory中要删除的模板:

  editSuccess.php

  明天见

  今天是我们深入模型-视图-控制器世界的一大步:通过操作Propel对象模型的布局、模板、动作和对象,我们访问了一个MVC结构程序中的所有级别。如果我们不能完全理解这几层之间的桥梁,不要担心:它会一点一点变得更加清晰。

  今天打开了很多文件。如果我们想知道一个项目中的文件是如何组织的,我们可以查看Symfony中关于文件结构的章节。

  明天将是另一个伟大的日子:我们将修改视图,设置更复杂的路由规则,修改模块,深化数据操作和表之间的链接。

mvc的三层架构,mvc三层结构