PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

PHP设计模式介绍 第十六章 数据映射模式

PHP设计模式介绍 第十六章 数据映射模式

来源:互联网  作者:  发布时间:2010-05-22
前两章――动态数据模式与表数据网关模式各自展示对记录与每个

你现在可以开始操作更多的finder方法,包括收集Bookmark实例的方法。

class BookmarkMapperTestCase extends BaseTestCase {
// ... 
function testFindByGroup() {
$mapper = new BookmarkMapper($this->conn);
$this->addSeveralBookmarks($mapper);
$this->assertIsA(
$php_links = $mapper->findByGroup(‘php’)
,’array’);
$this->assertEqual(3, count($php_links));
foreach($php_links as $link) {
$this->assertIsA($link, ‘Bookmark’);
}
}
}

寻找特殊组的bookmarks 可以操作如下:

class BookmarkMapper {
// ...
public function findByGroup($group) {
$rs = $this->conn->execute(
‘select * from bookmark where tag like ?’
,array($group.’%’));
if ($rs) {
$ret = array();
foreach($rs->getArray() as $row) {
$ret[] = $this->createBookmarkFromRow($row);
}
return $ret;
}
}
}

ADOConnection::execute()方法返回的时一个ADOResultSet 对象。所以返回的结果有一个getArray() 方法来进行处理,返回的一个联合数组 (field => value)。数组包含了每一行的数据。

接着,这些数据行形成的数组传递给createBookmarkFromRow()方法进行处理并创建Bookmark类的实例。

怎么更新数据映射呢?更新的操作通用需要用到Bookmark和BookmarkMapper。确保bookmarks有没有更新最好的方法是使用BookmarkTestCase。测试数据库访问的部分则由测试BookmarkMapper的代码负责。

class BookmarkTestCase extends BaseTestCase {
// ...
function testSaveUpdatesDatabase() {
$mapper = new BookmarkMapper($this->conn);
$this->addSeveralBookmarks($mapper);
$bookmark = $mapper->findById(1);
$this->assertEqual(
‘http://blog.casey-sweat.us/’
,$bookmark->getUrl());
$bookmark->setUrl(
‘http://blog.casey-sweat.us/wp-rss2.php’);
$mapper->save($bookmark);
$bookmark2 = $mapper->findById(1);
$this->assertEqual(
‘http://blog.casey-sweat.us/wp-rss2.php’
,$bookmark2->getUrl());
}
}

现在,save()方法通过INSERT把新的bookmards插入到数据库。但是,就像这个测试用例涵盖的一样,save()现在必须确定Bookmark参数是新的或者已经增加到数据库里面了。对于前者,INSERT就可以操作了;对于后者,就需要用UPDATE了。

就目前的情况,让我们重构下操作INSERT语句的代码(这个原来是涵盖在save()方法里面的),成为一个新的私有的方法,命名为insert()。

class BookmarkMapper {
//...
protected function insert($bookmark) {
$rs = $this->conn->execute(
self::INSERT_SQL
,array(
$bookmark->getUrl()
,$bookmark->getName()
,$bookmark->getDesc()
,$bookmark->getGroup()));
if ($rs) {
$inserted = $this->findById($this->conn->Insert_ID());
// clean up database related fields in parameter instance
if (method_exists($inserted,’setId’)) {
$bookmark->setId($inserted->getId());
$bookmark->setCrtTime($inserted->getCrtTime());
$bookmark->setModTime($inserted->getModTime());


}
} else {
throw new Exception(‘DB Error: ‘.$this->conn->errorMsg());
}
}
}

在把现有的save()方法的一部分重新命名为insert()的同时,新的save()方法必须用getId()确认它的属性$id是否被设置。

class BookmarkMapper {
//...
public function save($bookmark) {
if ($bookmark->getId()) {
$this->update($bookmark);
} else {
$this->insert($bookmark);
}
}
}

现在,你还需要一个update() 方法,它和insert()方法很类似。回想一下,insert()方法按照固定的模式来编写代码从属性到域名进行数据映射。那么对于update(),让我们用一个更加动态的方法,从bookmark.xml里面获得信息并进行更改。

class BookmarkMapper {
//...
const UPDATE_SQL = “
update bookmark set
url = ?,
name = ?,
description = ?,
tag = ?,
updated = now()
where id = ?
“;
protected function update($bookmark) {
$binds = array();
foreach(array(‘url’,’name’,
‘description’,’tag’,’id’) as $fieldname) {
$field = $this->map[$fieldname];
$getprop = (string)$field->accessor;
$binds[] = $bookmark->$getprop();
}
$this->conn->execute(
self::UPDATE_SQL
,$binds);
}
}

值得注意的是数组里面元素的排列顺序和我们SQL语句需要的顺序是一致的。这个update()方法从数据映射里面捕捉到基础的内容:它建立起属性和域(列)的关系。

最后,让我们看下“删除”的操作。我们为BookmarkMapper类写一个方法来接受一个Bookmark并把它从数据库删掉。

首先,写一个测试代码:

class BookmarkMapperTestCase extends BaseTestCase {
// ...
function testDelete() {
$mapper = new BookmarkMapper($this->conn);
$this->addSeveralBookmarks($mapper);
$this->assertEqual(5, $this->countBookmarks());
$delete_me = $mapper->findById(3);
$mapper->delete($delete_me);
$this->assertEqual(4, $this->countBookmarks());
}
function countBookmarks() {
return $this->conn->getOne(
‘select count(1) from bookmark’);
}
}

代码本身:

class BookmarkMapper {
// ...
public function delete($bookmark) {
$this->conn->execute(
‘delete from bookmark where id = ?’
,array((int)$bookmark->getId()));
}
}

现在,你可以通过数据映射模式来完整第进行操作了。

如果你的域对象创建起来比较繁琐,你可能需要写一个BookmarkMapper::deleteById()方法,它不需要加载域对象就能删除数据。

总结

很明显,在数据库和域对象之间增加一个转换层会造成一定的复杂性。但是,这个复杂性可以给你的代码带来巨大的灵活性,因为你可以不管数据库的表结构自由地升级你的类。

另外,你还需要记住的是所有这些例子还只是一个非常简单的转换机制。如果你需要对这个简单的机制进行升级,你可以参考holy grail of ORM—ObjectRelational Mapping—那里面会进行详细的阐述。


延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式
PHP设计模式介绍 第七章 策略模式
PHP设计模式介绍 第八章 迭代器模式
PHP设计模式介绍 第九章 观测模式
PHP设计模式介绍 第十章 规范模式
PHP设计模式介绍 第十一章 代理模式
PHP设计模式介绍 第十二章 装饰器模式
PHP设计模式介绍 第十三章 适配器模式
PHP设计模式介绍 第十四章 动态记录模式
PHP设计模式介绍 第十五章 表数据网关模式
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号