Zend 框架数据访问层 (DAL)

Posted

技术标签:

【中文标题】Zend 框架数据访问层 (DAL)【英文标题】:Zend Framework Data Access Layer (DAL) 【发布时间】:2012-08-18 02:27:28 【问题描述】:

查看有关 Zend Framework 中数据访问的几本教程和书籍,似乎大多数人都在他们的模型(Active Record 模式)甚至控制器中进行数据访问。我强烈不同意这一点。因此,我想要一个数据访问层(DAL),这样我的域层就可以通过没有任何“ZF 的东西”来保持可移植性。我四处寻找,但并没有真正找到我想要的东西。注意:我是采埃孚的新手。

DAL 结构

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

/application/modules/default/dal/

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

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

实施

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

我也非常感谢有关如何在 ZF 中实现我的 DAO 类的建议。我没有花太多时间阅读所有可用于数据库交互的组件,因此非常欢迎任何想法。我怀疑有比可用的标准 PDO 更智能的东西(不过,它可能在内部使用 PDO)。名字下降就足够了。

很抱歉有很多问题。我只需要朝着正确的方向前进。

【问题讨论】:

我喜欢这个问题,但范围很大。您涉及多个主题,因此您的答案将不完整。 @RockyFord 我同意。我想让它更精确,但我认为一切都是有联系的。但现在想想,关于结构的理论部分和实际实现可能是两个不同的问题。 必须感谢@Keyne,因为他非常勇敢地尝试将其浓缩为一个合理的答案。 【参考方案1】:

嗯,在处理Data Access Layer 时首先要考虑的是,这一层也有子层,在现代很难找到名为“dal”的文件夹框架(我以 Zend Framework 和 Symfony 为基础)。

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

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

此外,按照 Zend Framework 快速入门,on the domain model section,您会发现还有第三个组件,它使用了Data Mapper Pattern。

因此,如果您的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() 方法创建的, 相反,这个想法是对象创建是工厂的任务 并且您必须注入依赖项才能实现所谓的 Dependency Inversion Principle (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的目录和namespace guidelines for modules即可。

最后提示:我花了 很多时间 编写自己的数据映射器 终于意识到维护对象映射是一场噩梦 您的应用程序随着许多相关实体的增长而增长。 (即帐户 包含对用户对象的引用的对象,用户包含 角色,等等)在这写映射的东西并不容易 观点。所以我强烈推荐你,如果你真的想要一个真正的 对象关系映射器,首先研究遗留框架如何执行 这样的任务,也许使用它。 所以,花点时间来Doctrine 2,这是 使用 DataMapper 模式的迄今为止最好的 (IMO) 之一。

就是这样。您仍然可以使用您的/dal 目录来存储DataMappers,只需register the namespace,以便自动加载器可以找到它。

【讨论】:

我的控制器找不到我的映射器类:$userMapper = new Application_Model_DataMappers_UserMapper();。类的路径是:/application/modules/default/models/DataMappers/UserMapper.php。另外,在您给出的映射器示例中,find 方法的$guestbook 参数不应该通过引用传递吗? @andy124 不确定我是否理解你。关于类不加载,需要先用zf命名空间做一些测试,试试把mapper放在同级目录下,先看看能不能用。 @Keyne +1 以获得精彩而详细的文章。注意:ZF 有一个内置映射器类的默认目录结构。\modules\[modulename]\models\Mappers\Guestbook.php 并且应该映射到类名 class [Modulename]_Model_Mapper_Guestbook。我不相信这有很好的记录。 @jmbertucci 谢谢。没有注意到,因为我目前正在使用 Doctrine。也许这就是 Andy124 没有从控制器中获取映射器的原因。 @andy124 映射器目录是我偶然发现的。我记得它没有很好的记录。至于你的问题,文件名应该只是最终类的名称。删除文件名的 Table 部分。 IE。 Default_Model_DbTable_User() => .../models/DbTable/User.php。如果这不是问题,最好就这个特定问题提出一个新问题,这样您就可以发布更多错误代码,让人们更容易看到并帮助解决它。 =)【参考方案2】:

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

如果您愿意,特定网关接口的实现可以使用通用数据映射器。我在一家小公司工作,并且总是使用 PDO 创建我的实现。这让我可以足够接近数据库来处理我可能需要但能够支持非常抽象的接口的任何有趣的 SQL。


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

【讨论】:

我不太清楚你的意思。如果您能详细说明网关抽象的含义,那将不胜感激。我想我是个菜鸟。您提出了一个很好的观点,即不与数据库绑定。但是简单地使用接口不就可以完成这项工作吗? @andy124 不用担心 ZF 中的网关抽象,它在 ZF MVC 中几乎默认完成。当 Quickstart 让您创建 Application_Model_DbTable_Guestbook 时,它是该表的网关并封装了 Sqlite PDO 适配器或您使用的任何适配器。 @andy124 网关基本上是一种获取和检索数据的方法,您完全不知道它是如何获取数据的。它可能来自数据库、云、文件系统。 . .没关系。网关一个接口。

以上是关于Zend 框架数据访问层 (DAL)的主要内容,如果未能解决你的问题,请参考以下文章

Dal(带有实体框架)和模型层到 MVC

Zend 框架中如何设计领域层对象来表示多个对象和单个对象?

1.1 DAL数据访问层

当使用实体框架作为数据访问层时,如何实现业务逻辑层?

数据访问层DAL

业务层 (BLL) 数据访问层 (DAL) 和 UI 之间的通用结构?