Design patterns 使用Zend Framework 2将数据库列映射到域模型

Design patterns 使用Zend Framework 2将数据库列映射到域模型,design-patterns,zend-framework2,solid-principles,poeaa,Design Patterns,Zend Framework2,Solid Principles,Poeaa,我已经做了相当多的研究,无法找到这个看似流行的问题的答案 我有一个域模型,它包含一些属性,比如firstName和lastName,但在我的数据库中,我将它们存储为fname和lname 根据good规则,模型应该完全不知道它是如何存储的。所以我的问题是,这些字段的映射到哪里去了 通过查看实现Zend\Stdlib\Hydrator\AbstractHyrdrator接口的现有类的源代码,我没有看到任何提供映射功能的类 有没有人看到一个干净的解决方案,不会污染模型 更新:更好更简单的解决方案 我

我已经做了相当多的研究,无法找到这个看似流行的问题的答案

我有一个域模型,它包含一些属性,比如firstName和lastName,但在我的数据库中,我将它们存储为fname和lname

根据good规则,模型应该完全不知道它是如何存储的。所以我的问题是,这些字段的映射到哪里去了

通过查看实现Zend\Stdlib\Hydrator\AbstractHyrdrator接口的现有类的源代码,我没有看到任何提供映射功能的类

有没有人看到一个干净的解决方案,不会污染模型

更新:更好更简单的解决方案 我问这个问题已经有一段时间了,但这里有一个非常简单的解决方案,可以将列映射到对象,而不需要太多开销。使用ZF2的内置命名策略功能,可以实现所需的效果

使用ORM

我会使用any,它允许您在模型类之外配置映射

就我个人而言,我喜欢。我使用通过映射数据库来映射字段,因为这样更容易,但我同意关于数据存储方式的信息不应该在模型中。幸运的是,您有数据映射的选项和选项

例如,如果模型中有此实体:

<?php
class Message
{
    private $id;
    private $text;
    private $postedAt;
}
然后,在Module.php中配置服务时,将该信息发送给需要它们的类:

class Module
{

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Album\Model\AlbumTable' =>  function($sm) {

                $config = $sm->get('AlbumTableGateway');
                    $tableGateway = $sm->get('AlbumTableGateway');

                                //when you create the AlbumTable class, you send the field mappings
                                $table = new AlbumTable($tableGateway, $config ['mappings']['AlbumTable']['fields']);
                        return $table;
            },

            'AlbumTableGateway' => function ($sm) {

                $config = $sm->get('AlbumTableGateway');
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new Album());

                                 //when you create the TableGateway, you also take the table name from the config.
                return new TableGateway($config ['mappings']['AlbumTable']['table'] , $dbAdapter, null, $resultSetPrototype);
                  },
            ),
    );
}
}
然后,您只需要调整AlbumTable类,以便它接收并使用该映射

class AlbumTable
{
protected $tableGateway, $mappings;

//First, in the constructor, you receive and save the mappings

    public function __construct(TableGateway $tableGateway, $mappings)
{
    $this->tableGateway = $tableGateway;
    $this->mappings = $mappings;
}


//then in every function where you before hardcoded the column names, now you take it from the mappings, for instance:

public function saveAlbum(Album $album)
{

        /*
         here you had
        $data = array(
             'artist'  => $album->artist,
             'title'   => $album->title,
               );

         */
        // now you change it to:
         $data = array(
            $mappings['artist'] => $album->artist,
            $mappings['title']  => $album->title,
    );

   $id = (int) $album->id;
        if ($id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getAlbum($id)) {
                $this->tableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('Album id does not exist');
            }
        }
 }
列名称被编码的地方都是一样的

我认为您可以轻松地将其适应您的系统

使用ORM

我会使用any,它允许您在模型类之外配置映射

就我个人而言,我喜欢。我使用通过映射数据库来映射字段,因为这样更容易,但我同意关于数据存储方式的信息不应该在模型中。幸运的是,您有数据映射的选项和选项

例如,如果模型中有此实体:

<?php
class Message
{
    private $id;
    private $text;
    private $postedAt;
}
然后,在Module.php中配置服务时,将该信息发送给需要它们的类:

class Module
{

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Album\Model\AlbumTable' =>  function($sm) {

                $config = $sm->get('AlbumTableGateway');
                    $tableGateway = $sm->get('AlbumTableGateway');

                                //when you create the AlbumTable class, you send the field mappings
                                $table = new AlbumTable($tableGateway, $config ['mappings']['AlbumTable']['fields']);
                        return $table;
            },

            'AlbumTableGateway' => function ($sm) {

                $config = $sm->get('AlbumTableGateway');
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new Album());

                                 //when you create the TableGateway, you also take the table name from the config.
                return new TableGateway($config ['mappings']['AlbumTable']['table'] , $dbAdapter, null, $resultSetPrototype);
                  },
            ),
    );
}
}
然后,您只需要调整AlbumTable类,以便它接收并使用该映射

class AlbumTable
{
protected $tableGateway, $mappings;

//First, in the constructor, you receive and save the mappings

    public function __construct(TableGateway $tableGateway, $mappings)
{
    $this->tableGateway = $tableGateway;
    $this->mappings = $mappings;
}


//then in every function where you before hardcoded the column names, now you take it from the mappings, for instance:

public function saveAlbum(Album $album)
{

        /*
         here you had
        $data = array(
             'artist'  => $album->artist,
             'title'   => $album->title,
               );

         */
        // now you change it to:
         $data = array(
            $mappings['artist'] => $album->artist,
            $mappings['title']  => $album->title,
    );

   $id = (int) $album->id;
        if ($id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getAlbum($id)) {
                $this->tableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('Album id does not exist');
            }
        }
 }
列名称被编码的地方都是一样的


我认为您可以轻松地将其适应您的系统

您看过数据映射器设计模式吗?我以前在PHP的几个ZF1应用程序中实现过这一点,我认为它满足了您的需求。您将了解数据库的责任交给mapper层,而模型实体对象对此一无所知。它的实现非常简单,并且您不需要使用更复杂的类似ORM的原则

编辑:这里是


这是一个

你看过数据映射器设计模式了吗?我以前在PHP的几个ZF1应用程序中实现过这一点,我认为它满足了您的需求。您将了解数据库的责任交给mapper层,而模型实体对象对此一无所知。它的实现非常简单,并且您不需要使用更复杂的类似ORM的原则

编辑:这里是


这里有一个

我在使用ORM(如Doctrine)时遇到的问题是,它使这样一个简单的任务变得如此复杂。我更希望有一个简单、更高效的系统,在对象或其他对象中使用简单数组。松散耦合,但比类似信条的东西更容易、更快。我必须相信有更好的方法。你是如何访问数据库的?有一个桌面网关?请给我更多的细节,我可以给你一个关于如何创建一个自定义和更简单的映射的线索或一些片段。我目前正在使用一个表网关,它包含SELECTs以及INSERT和UPDATEs中的每个映射。它可以让我保留数据库内容和数据库内容,但如果你有更好的解决方案,我会洗耳恭听。我用一个通用解决方案更新了我的答案,在配置中有一个映射,这是迄今为止我所看到的最好的答案。我使用ORM(如Doctrine)的问题是,它使这样一个简单的任务变得如此复杂。我更希望有一个简单、更高效的系统,在对象或其他对象中使用简单数组。松散耦合,但比类似信条的东西更容易、更快。我必须相信有更好的方法。你是如何访问数据库的?有一个桌面网关?请给我更多的细节,我可以给你一个关于如何创建一个自定义和更简单的映射的线索或一些片段。我目前正在使用一个表网关,它包含SELECTs以及INSERT和UPDATEs中的每个映射。它让我把数据库的东西和数据库的东西放在一起
但如果你有更好的解决方案,我洗耳恭听。我用一个通用解决方案更新了我的答案,在配置中有一个映射,并让你的类使用它。这是我迄今为止看到的最好的答案。我以前使用过数据映射器设计模式,它们工作得很好。活动记录模式也类似。但是,我使用域实体和表网关的常见ZF2模式。在这些模式中,我不能引用实体中的存储。我以前使用过数据映射器设计模式,它们工作得很好。活动记录模式也类似。但是,我使用域实体和表网关的常见ZF2模式。在这些模式中,我不能引用实体中的存储。