我在Zend框架中使用数据映射器模式。到目前为止这还行,但现在我需要你的帮助/意见。让我们从代码开始:
我们订了一张有几个人的桌子:
CREATE TABLE `persons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`age` int(3) NOT NULL,
`haircolor` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id``),
);
现在我试着选择所有棕色头发的人。我在ServiceLayer
中使用以下方法public function getPeopleByHaircolor($hair) {
return $this->getMapper()->fetch('haircolor = ?', $hair);
}
Mapper中的方法是这样的:
public function fetch($condition, $value) {
$resultSet = $this->getTable()->fetchAll($this->getTable()->select()->where($cond, $value));
$entries = array();
foreach($resultSet as $row) {
$entry = new Default_Model_Person();
$entry->id = $row->id;
$entry->name = $row->name;
[...]
}
return $entries;
}
我想我用这个方法遵循数据映射器模式…
现在的问题:
我想选择的人,有棕色头发,年龄小于20岁。怎么做呢?我的尝试:
public function getTeens($hair) {
$rows = $this->getMapper()->fetch('haircolor = ?', $hair);
$return = array();
foreach($rows as $row) {
if((int)$row->age < 20) $return[] = $row;
}
return $return;
}
但是如果你有更多的变量,比如"棕色头发的人,年龄小于20岁,名字为'Foo Bar'",我需要越来越多的方法和/或foreach循环。
我的问题:
如何在数据映射器模式中做到这一点?如果我做一个本地SQL查询,如$serviceLayer->mapper->table-> query ('SELECT…'),这是打破数据映射模式吗?我不喜欢那些额外的foreach循环,感觉我做错了什么,所以我写了这个问题。
实际上,对于两个条件,不建议在一个条件上查询,然后在迭代时对另一个条件进行过滤。在两种以上的情况下,没有明确的方法。而且实现分页适配器变得相当混乱。
在我看来,问题是你的映射器fetch()
方法只支持一个条件。所以:
-
修改签名以支持一组条件
-
或者,您可以为每个增强的获取方法创建一个单独的映射器方法,例如:
fetchByHairAndAge($hair, $age)
等
根据我使用数据映射器的有限经验,我发现以下方法非常适合我目前遇到的场景:
public function getPeopleByHaircolorAndAge($haircolor, $age, $limit=null, $offset=null)
{
$people = new PersonCollection;
$people->filterByHaircolor($haircolor);
$people->filterByAge($age);
$people->setLimit($limit);
$people->setOffset($offset);
$personCollectionMapper = new PersonCollectionMapper;
$personCollectionMapper->fetch($people);
return $people;
}
通过首先实例化域对象,我可以选择设置过滤器和其他变量,当数据映射器被注入到映射器中时,数据映射器可以从对象中读取。
对我来说,与使用多个返回域对象的映射器方法相比,这是迄今为止最好的方法。