如何使用Data Mapper模式真正区分对分层数据的关注

时间:2013-03-17 01:59:32

标签: php zend-framework2 datamapper

我对Data Mapper pattern很陌生。我想我错过了一些东西,因为对我来说,它失败了比最基本的例子更复杂的东西。

假设我有一个由网页组成的简单网站:

class Page {
    private $id     = null;
    private $parent = null;
    private $title  = null;
    private $body   = null;

    public function setId($id)              { $this->id     = (int) $id; }
    public function setParent(Page $parent) { $this->parent = $parent;   }
    public function setTitle($title)        { $this->title  = $title;    }
    public function setBody($body)          { $this->body   = $body;     }

    public function getId()     { return $this->id;     }
    public function getParent() { return $this->parent; }
    public function getTitle()  { return $this->title;  }
    public function getBody()   { return $this->body;   }
}

现在我想实例化树中深处的

  • 第1页
    • 第2页
      • 第3页
        • 第4页
          • 第5页
            • 第6页
              • Page 7
使用Data Mapper模式,我将使用以下映射器类:

class PageMapper {
    public function fetch($id) {
        //...
        $data = $db->fetchRow("SELECT * FROM `pages` WHERE `id` = ?", $id);
        $page = new Page();
        $page->setId($data['id']);
        $page->setTitle($data['title']);
        $page->setBody($data['body']);
        if ($data['parent_id'] !== null) {
            $page->setParent(
                $this->fetch($data['parent_id']);
            );
        }
    }

    public function save(Page $page) {
        //...
    }
 }

问题很明显:我必须将所有父母一直实例化到根页面。

现在想象一个页面需要知道它的孩子。这意味着,如果我想要实例化根页面,我将必须加载整个树

解决方案可能是父/子只会按需加载,但这意味着域对象必须知道映射器以便从中提取数据......并且分离将会消失

域模型( Page 类的实例)应该对Data Mapper层(分离)一无所知,但仍然能够执行这些任务(检索父/子)。

在这些条件下是否可以分离关注点?如果是,怎么样?

1 个答案:

答案 0 :(得分:1)

查看Doctrine,一个实现数据映射器模式的orm框架:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-self-referencing

你的方法的问题不是整个树(孩子)的实例化,而是 它将使用的查询量。

看一下教义方法,你会有一个子属性,一次只能用一个查询加载。

我也绝不会建议为一个orm实现一个自制的解决方案。

可能的解决方案也是使用Closure:

class Page {
//...
    public function setParents(Closure $pages)
    {
        $this->parents = $pages;
    } 
}

class PagesMapper {

public function fetch() {
//fetch the page ...
$parents = function($parent) use($id, $db) {
        parents = $db->query(/* select parent... */);
        $pages = array();
        foreach($parents as $parent) {
            $page = new Page(); 
            $page->id = $parent->id;
            //...
            $pages[] = $page;
        }
        return $pages;
    };
    $page->setParents($parents);
    return $page;
}
}

因此页面域不知道持久层。