Zend框架数据访问层(DAL)


Zend Framework Data Access Layer (DAL)

翻阅几本关于Zend Framework中数据访问的教程和书籍,似乎大多数人都在自己的模型(活动记录模式)甚至控制器中进行数据访问。我强烈反对这种说法。因此,我想有一个数据访问层(DAL),这样我的域层就可以通过没有任何"ZF东西"来保持可移植性。我四处搜索,但并没有真正找到我想要的东西。提醒:我是ZF的新手。

DAL结构

因此,第一个问题是将数据访问层放置在哪里。虽然它当然可以放在library文件夹中,并向自动加载器添加一个名称空间,但这似乎不符合逻辑,因为它是特定于我的应用程序的(因此applications文件夹是合适的)。我使用的是模块化结构。我正在考虑使用以下结构:

/application/modules/default/dal/

但是,我不确定如何包含此文件夹,以便访问控制器中的类(不使用includes/requires)。如果有人知道如何做到这一点,那就太棒了!当然也欢迎任何其他想法。

这个想法是让我的控制器与数据访问对象(DAO)交互。然后,DAO使用可以返回给控制器的模型。通过这样做,我可以保持我的模型完好无损。

实施

在其他语言中,我以前实现过每个模型的DAO,例如DAL_User。这导致了大量的DAO类。有没有更聪明的方法可以做到这一点(使用外键时,使用单个类似乎并不容易)?

对于如何在ZF中实现我的DAO类,我也很感激。我没有花太多时间阅读所有可用于数据库交互的组件,所以任何想法都是非常受欢迎的。我怀疑有比标准PDO更智能的东西可用(不过,它可能在内部使用PDO)。去掉名字就足够了。

很抱歉有这么多问题。我只需要朝着正确的方向推动一下。

在处理Data Access Layer时,首先要考虑的是,这一层也有子层,在现代框架中发现名为"dal"的文件夹是不常见的(我以Zend Framework和Symfony为基础)。

其次,关于ActiveRecord,您必须注意,默认情况下Zend Frameworks不会实现它。大多数教程都采用最简单的方法来教授新概念。通过简单的示例,业务逻辑的数量是最小的,因此它们不添加另一层复杂性(数据库和模型对象之间的映射),而是用两种基本模式组成domain layer(模型):表数据网关和行数据网关。这对于初学者来说已经足够了。

分析后,您将看到ActiveRecord之间的一些相似之处和行数据网关模式。主要区别在于ActiveRecord对象(持久实体)承载业务逻辑和行数据网关仅表示数据库中的一行。如果添加表示数据库行的对象上的业务逻辑,然后它将成为ActiveRecord对象。

此外,遵循ZendFrameworkQuick Start,在域模型部分,您将意识到还有第三个组件,它使用数据映射器模式。

因此,如果DAL的主要目的是在业务对象(模型)和存储之间映射数据,则此任务的职责将委派给数据映射器,如下所示:

class Application_Model_GuestbookMapper
{
    public function save(Application_Model_Guestbook $guestbook);
    public function find($id);
    public function fetchAll();
}

这些方法将与Database Abstraction Layer交互,并用数据填充域对象。大致如下:

public function find($id, Application_Model_Guestbook $guestbook)
{
    $result = $this->getDbTable()->find($id);
    if (0 == count($result)) {
        return;
    }
    $row = $result->current();
    $guestbook->setId($row->id)
              ->setEmail($row->email)
              ->setComment($row->comment)
              ->setCreated($row->created);
}

如您所见,Data Mappers与Zend_Db_Table实例交互,该实例使用表数据网关模式。另一方面,$this->getDbTable->find()返回Zend_Db_Table_Row的实例,该实例实现行数据网关模式(它是表示数据库行的对象)。

提示:domain object本身,guestbook实体,不是由DataMapper上的find()方法创建的,相反,这个想法是对象创建是工厂的任务并且必须注入依赖项才能实现所谓的依赖反转原理(DIP)(SOLID原理的一部分)。但那是问题范围之外的另一个主题。我建议你访问以下链接http://youtu.be/RlfLCWKxHJ0

地图绘制从这里开始:

$guestbook->setId($row->id)
          ->setEmail($row->email)
          ->setComment($row->comment)
          ->setCreated($row->created);

到目前为止,我想我已经回答了你的主要问题,你的结构将如下:

application/models/DbTable/Guestbook.php
application/models/Guestbook.php
application/models/GuestbookMapper.php

因此,正如ZF快速入门:

class GuestbookController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $guestbook = new Application_Model_GuestbookMapper();
        $this->view->entries = $guestbook->fetchAll();
    }
}

也许您想为数据映射器创建一个单独的文件夹。只需更改:

application/models/GuestbookMapper.php

application/models/DataMapper/GuestbookMapper.php

类名将为

class Application_Model_DataMapper_GuestbookMapper

我已经看到您想要将domain model objects分离为多个模块。这也是可能的,您所需要的只是遵循ZF的模块目录和命名空间指南。

最后一点提示:我花了很多时间为最终意识到当您的应用程序随着大量相关实体而增长。(即账户包含对用户对象的引用的对象,包含角色等等)在这种情况下编写映射内容并不容易指向所以我强烈推荐你,如果你真的想要一个真正的对象关系映射器,首先研究遗留框架的执行方式这样的任务,也许可以使用它。所以,花点时间学习条令2迄今为止最好的(IMO)之一,使用DataMapper模式

就是这样。您仍然可以使用/dal目录来存储DataMappers,只需注册名称空间,这样自动加载器就可以找到它。

在我看来,每个模型都应该有一个网关抽象(而不仅仅是数据库访问)。DAO是不够的。如果您需要在某个时刻从云中获取数据,该怎么办?这很快就会成为现实。如果您将网关逻辑抽象为通用逻辑,然后使用数据库实现它,则可以两全其美。

如果您选择的话,特定网关接口的实现可以使用通用数据映射器。我在一家小公司工作,一直使用PDO创建我的实现。这使我能够足够接近数据库,以处理我可能需要的任何有趣的SQL部分,但能够支持一个非常抽象的接口。


我根本没有使用Zend框架。我不知道他们是否有数据映射器工具可以帮助您实现网关接口。