Php Zend数据映射器设计

Php Zend数据映射器设计,php,zend-framework,design-patterns,datamapper,Php,Zend Framework,Design Patterns,Datamapper,我使用Zend框架并遵循将数据层与域层分离的设计模式 在实现数据映射器的方法时会出现问题 因此,我实现了save(),它根据域模型是否包含id属性插入和更新,以及find()它根据id参数返回records域对象 但是如果我需要呢 搜索表中的所有/某些行并返回所有列 搜索相同的行并返回mysql计数值 我应该直接使用继承了Zend_Db_Table_抽象的类来满足这些需求吗 我是否应该为每一个需求实施一种方法 对于如何划分数据映射器的功能以满足我的需要和我未来的需要,我有点困惑您可以添加单独的查

我使用Zend框架并遵循将数据层与域层分离的设计模式 在实现数据映射器的方法时会出现问题 因此,我实现了
save()
,它根据域模型是否包含id属性插入和更新,以及
find()
它根据id参数返回records域对象 但是如果我需要呢

  • 搜索表中的所有/某些行并返回所有列
  • 搜索相同的行并返回mysql计数值
  • 我应该直接使用继承了Zend_Db_Table_抽象的类来满足这些需求吗 我是否应该为每一个需求实施一种方法


    对于如何划分数据映射器的功能以满足我的需要和我未来的需要,我有点困惑

    您可以添加单独的查找方法,例如

    class PersonMapper
    {
        … // other code
    
        public function findByLastName()
        {
            // … fetch rowset and map them
        }
    
        public function countByLastName() 
        {
        …
    
    然而,当您需要查询多个列或希望按任意条件处理CRUD时,这将很快失去控制。你不需要像这样的方法

     public function findByLastNameAndBirthdayAndMaritalStatus()
    
    简单的解决方案是使用
    Zend\u Db\u Table\u Select
    创建查询,然后将这些查询传递给数据映射器以执行并映射它们,例如在数据映射器中

    public function getSelect()
    {
        return $this->personTable->select();
    }
    
    public function findBy(Zend_Db_Table_Select $select)
    {
        $people = $this->personTable->fetchAll($select);
        // map people to People objects
    }
    
    您可以使用映射器返回并接受PersonQueryBuilder来进一步抽象这一点,这将隐藏内部的SQL语义,让我们针对域对象进行指定。不过这需要更多的努力


    还可以查看存储库和规范模式

    虽然Gordon很可能有正确的答案,但就我目前的口味和需求而言,我觉得它过于复杂了

    我为我所有的域映射器使用一个基本映射器类,并且我将尽可能多的功能放入基本类中

    我使用的“按列查找”方法在我所有的映射程序中都非常有效:

    //from abstract class Model_Mapper_Abstract
    
    //The constructor of my base class accepts either a dbtable model
    // or the name of a table stored in the concrete mapper tablename property. 
     public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
        {   
            if (is_null($tableGateway)) {   
                $this->tableGateway = new Zend_Db_Table($this->tableName);
            } else {    
                $this->tableGateway = $tableGateway;
            }
        }
    /**
     * findByColumn() returns an array of entity objects
     * filtered by column name and column value.
     * Optional orderBy value.
     *
     * @param string $column
     * @param string $value
     * @param string $order optional
     * @return array of entity objects
     */
    public function findByColumn($column, $value, $order = null)
        {
            //create select object
            $select = $this->getGateway()->select();
            $select->where("$column = ?", $value);
            //handle order option
            if (!is_null($order)) {
                $select->order($order);
            }
            //get result set from DB
            $result = $this->getGateway()->fetchAll($select);
            //turn DB result into domain objects (entity objects)
            $entities = array();
            foreach ($result as $row) {
                //create entity, handled by concrete mapper classes
                $entity = $this->createEntity($row);
                //assign this entity to identity map for reuse if needed
                $this->setMap($row->id, $entity);
                $entities[] = $entity;
            }
            //return an array of entity objects
            return $entities;
        }
    

    我希望你至少会发现这是一个有用的创意发生器。另外,如果您希望在类似于此的方法中实现
    SQL Count()
    语句,则在构建select()时使用该语句会更容易。

    不会让用户从映射器获取Zend_Db_select的实例,然后将其返回映射器违反whole@Xeus只是在某种程度上。Zend_Db_Table_Select是一个抽象的查询生成器,因此您不需要直接耦合到特定的RDBMS。然而,Zend_Db_Table_Select的API语义当然与Db相关。这就是建议的查询生成器可以解决的问题,因为它允许您根据域模型的结构查询域对象。但是,实现这种查询生成器所需的工作量要高得多。采埃孚不提供开箱即用的服务。这是一个什么足够好的问题。@Gordon,你可以澄清一下:(1)在映射器中执行
    getSelect()
    findBy(Select$Select)
    吗?(2) 我认为
    $this->personTable
    是一个能够很好地处理单个表的表数据网关。但是如果涉及到多个连接呢?将两个
    Select
    s放入映射器可以吗?(3)
    findBy(Select$Select
    仅处理人员。如果我需要传递3个
    Select
    s中的任意一个,比如
    PersonSelect()
    PlaceSelect()
    ValueSelect())
    。我应该将数据映射到相应对象的逻辑放在同一个映射器中,还是使用策略模式创建多个映射器?@DimaDz我现在对此没有强烈的意见。将内容放在对你有意义的地方(考虑这方面的把握原则)但最重要的是让代码在合理的努力范围内工作。@Gordon,非常感谢,Gordon。这总是关于工作代码和花在代码上的时间之间的折衷。你能回顾一下给出的答案,或者接受对你帮助最大/解决了你的问题的答案,或者指出为什么没有一个答案能解决问题吗我帮你解决了问题,谢谢