如果你想学习模型和超级模型的最新技术,本章将无法对你有所帮助。但如果你仅仅只是想学习一个模型,你应用程序中元数据的层,那么请阅读本章内容。本章所描述的模型用于构建MVC应用程序。
MVC(模型-视图-控制)最初由Trygve Reenskaug在Smalltalk平台上提出的应用程序设计模式。MVC的主要思路就是将展示从数据中分离出来,把控制器从展示中分离出来。这种分离让应用程序的各个部分都只关注一个目标。控制器关注模型数据的改变,模型将其数据向视图开放,而视图则关注创建模型的展示(如HTML页面展示博客博文)。
举个例子,当用户访问你博客首页时,用户的浏览器发送一个请求,该请求被发给控制器要求渲染博文列表。控制器计算要显示的博文列表,从数据库检索Post模型,并将Post数组发送给视图,视图渲染HTML以便在浏览器中显示。
到底什么是模型
模型在MVC中用M表示。它是MVC应用程序中三大部件之一。模型负责根据来自控制器的请求改变其内部状态,并将其当前状态信息传递给视图。它是应用程序主逻辑容器。
举个例子,如果你正在构建一个博客,那么你将拥有一个Post模型。如果你正在构建一个内容管理系统,那么你需要一个Page模型。
- <?php
- namespace Blog;
- class Post
- {
- private $title;
- private $body;
- private $createdAt;
- private $updatedAt;
- public function __construct($title, $body)
- {
- $this->title = $title;
- $this->body = $body;
- $this->createdAt = new \DateTime();
- }
- public function setTitle($title)
- {
- $this->title = $title;
- $this->updatedAt = new \DateTime();
- }
- public function setBody($body)
- {
- $this->body = $body;
- $this->updatedAt = new \DateTime();
- }
- public function getTitle()
- {
- return $this->title;
- }
- public function getBody()
- {
- return $this->body;
- }
- }
很明显,上述类非常简单也易于测试,除了一个简单的博客引擎外它几乎完成了一切。
就是这样,现在你知道在Symfony2中模型是什么:它是你想将其保存在某种顺序数据存储机制中并随后可以检索的类。本章节的其它部分将专门讲述它是怎么与数据库交互的。
数据库和Symfony2
Symfony2自己并没有实现ORM(对象关系映射)或DBAL(数据库抽象层),Symfony2要解决它并没有什么问题,但这没有任何意义。Symfony2提供了与类似Doctrine或Propel这样库的深度集成,这些库提供了ORM和DBAL包,可以让你使用你最喜欢的库。
ORM是对象关系映射的缩写,它代表一种在不兼容类型系统之间转换数据的编程技术。我们有一个Post,它被做为一条记录被保存在数据库里,但在应用程序中它又要做为Post类的一个实例来展现。将数据库的数据表转换成对象称之为对象关系映射。我们将发现这个术语有点过时,因为它只能在处理关系性数据库时使用。现在存在着大量的非关系性数据存储机制,有一种面向文档的数据库(如MongoDB),它所使用的术语是ODM(对象文档映射)。
接下来,你将学习关于Doctrine2 ORM和Doctrine2 ModgoDB ODM(为当下流行的文档存储:MongoDB所提供的ODM服务),这两者与Symfony2有着最深层次的集成。
模型不是数据表
模型类感觉就象是数据库的数据表,每个对象实例表示单个记录,这样的概念随着Ruby on Rails框架和Active Record设计模式的流行而广为人知。在应用程序模型层设计之初这样考虑是很好的,特别是在你正为修改模型数据而提供简单的CRUD(增删改查)时。
但这种想法其实会引起一个问题,一旦你完成应用程序的增删改查而要去添加更多的业务逻辑时,上述想法会引发 下面的限制:
- 在软件实际使用前先设计一个模式,就好象在知道你要埋什么之前先挖个坑。可能你埋的东西正好适合你所挖的洞,但如果你要埋辆大型的消防车呢?要想有效工作的话,你需要完全不同的思路;
- 数据库针对性地去适应你应用程序的需要,而不是反过来;
- 有些数据存储引擎(如文档数据库)并没有数据表、记录甚至是模式的概念,如果你认为模型就是数据表的话,你将很难使用它;
- 在你设计应用程序域的时候脑海中浮现的却是数据库模式,那么接下来在两者之间的最小公约数原则会让你焦头烂额的。
想象一起,脑子里想着数据库的结构,然后集中注意力去编写干净的模型以满足你业务需求是多么地痛苦,好在Doctrine2 ORM已经解决了这个问题。在要求你去考虑如何持久化数据之前,它会先让你设计你的类和相关的交互。
范式转换
随着Doctrine2的介绍,一些核心范式被转换。领域驱动设计(DDD)告诉我们对象是对真实世界原型建模的最好模型。例如Car对象是最好地建模,它包含Engine、4个Tire实例等,并且应该被CarFactory(知道如何将部件组装起来)生产出来。领域驱动设计本身就可以写一本书,因为它相当广泛。然而,考虑到本章的目的,我们需要知道的是汽车自己是无法启动的,它需要一个外部作用来启动它。与此相似,模型没有外部作用也是无法保存自己的,因此下面这段代码违反了DDD,并为重新设计一个干净、易测代码带来麻烦 。
- $post->save();
Doctrine2并不是传统的Active Record的实现。Doctrine2使用一个不同的模式集,几乎完全实现了Data Mapper和 Unit Of Work模式,下面是如何使用Doctrine2来保存实体的示例:
- $manager = //... 得到对象管理器实例
- $manager->persist($post);
- $manager->flush();
“对象管理器”是Doctrine提供的核心对象,它的作用是持久化对象。你不久将学到这个对象的更多内容。这个范式转换让我们摆脱了所有的基类(如Post不需要继承基类)和静态依赖。任何对象都可以保存到数据库并随后进行检索。更有甚者,一旦被持久化,该对象就可以通过对象管理器进行管理,直到管理器明确进行清理。这意味着所有对象的交互都发生在内存,直到调用$manager->flush()方法才发往数据库。不用说与大多数其它对象持久化模式相比,这个机制提供了一个即时数据库和优化查询,因为持久化尽可能地“懒”(它们的执行总是延迟到最后一刻)。
Active Record模式最重要的方面就是性能,或者说,构建一个高性能的系统是困难的。通过使用事务和内存对象改变跟踪,Doctrine2最大限度地减少与数据库的通信,从而节省数据库执行时间和昂贵的网络通信。
结论
感谢Doctrine2,使得Symfony2的模型现在也许已经是最简单的概念:它置于你的完全控制之下,而且不会受到持久化细节的限制。
通过与Doctrine2联合,你可以对你在持久化细节方面的代码感到放心,Symfony2使构建数据库方面的应用程序变得十分简单。应用程序代码保持干净,这将缩短开发时间并提高代码的可读性。
本文转自 firehare 51CTO博客,原文链接:http://blog.51cto.com/firehare/585426,如需转载请自行联系原作者