数据映射器模式:来自服务层的复杂查询


Data Mapper Pattern: Complexe query from Service Layer

我在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()方法只支持一个条件。所以:

  1. 修改签名以支持一组条件

  2. 或者,您可以为每个增强的获取方法创建一个单独的映射器方法,例如: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;
}

通过首先实例化域对象,我可以选择设置过滤器和其他变量,当数据映射器被注入到映射器中时,数据映射器可以从对象中读取。

对我来说,与使用多个返回域对象的映射器方法相比,这是迄今为止最好的方法。