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

时间:2011-07-08 12:53:47

标签: php design-patterns zend-framework datamapper

我在Zend Framework中唱出数据映射器模式。到目前为止,这种方法效果很好,但现在我需要你的帮助/意见。那么让我们从代码开始:

我们有几个人的桌子:

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循环。


我的问题:

您将如何在Data Mapper模式中执行此操作?如果我执行本地SQL查询,如$ serviceLayer-&gt; mapper-&gt; table-&gt; qry('SELECT ...'),这会打破数据映射器模式吗? 我不喜欢那些额外的foreach循环,感觉我做错了,所以我写了这个问题。

2 个答案:

答案 0 :(得分:6)

实际上,对于两个条件,不建议在一个条件上查询,然后在迭代时过滤另一个条件。对于两个以上的条件,它没有明确的方法。并且实现分页适配器变得相当混乱。

在我看来,问题是您的映射器fetch()方法仅支持允许一个条件。所以:

  1. 修改签名以支持一系列条件。

  2. 或者,您可以为每个增强的提取方法创建单独的mapper方法,例如:fetchByHairAndAge($hair, $age)等。

答案 1 :(得分:1)

由于我对数据映射器的经验有限,我发现以下方法对于我目前遇到的情况非常有效:

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;
}

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

对我而言,与使用多个返回域对象的mapper方法相比,这是迄今为止的优秀方法。