在Zend Framework中查看有关数据访问的几本教程和书籍,似乎大多数人在他们的模型(Active Record Pattern)甚至控制器中进行数据访问。我非常不同意这一点。因此,我希望有一个数据访问层(DAL),以便我的域层保持可移植性,因为其中没有任何“ZF内容”。我一直在寻找,但还没找到我想要的。抬头:我是ZF的新手。
DAL结构
因此,第一个问题是放置数据访问层的位置。虽然它当然可以放在library
文件夹中并为自动加载器添加命名空间,但这似乎不合逻辑,因为它特定于我的应用程序(因此applications
文件夹是合适的)。我使用的是模块化结构。我正在考虑使用以下结构:
/application/modules/default/dal/
但是,我不确定如何包含此文件夹,以便我可以访问控制器中的类(不使用includes / requires)。如果有人知道如何实现这一点,那将是超级的!当然也欢迎任何其他想法。
我的想法是让我的控制器与数据访问对象(DAO)进行交互。然后DAO使用可以返回控制器的模型。通过这样做,我可以完整地保留我的模型。
实施
在其他语言中,我之前已经为每个模型实现了DAO,例如DAL_User
。这导致了大量的DAO类。是否有更聪明的方法(使用外键使用单个类似乎不容易)?
我也很感激如何在ZF中实现我的DAO类的建议。我没有花太多时间阅读可用于数据库交互的所有组件,因此非常欢迎任何想法。我怀疑有一些比标准PDO更聪明的东西(虽然可能在内部使用PDO)。名称下降就足够了。
很抱歉这个问题很多。我只需要朝着正确的方向努力。
答案 0 :(得分:4)
那么,在处理Data Access Layer
时你必须首先考虑的是,这个层也有子层,找到名为“dal”的文件夹是不常见的在现代框架中(我将Zend Framework和Symfony作为基础)。
其次,关于ActiveRecord
,您必须注意,默认情况下,Zend Frameworks 不会实现它。大多数教程都采用最简单的方法来教授新概念。通过简单的示例,业务逻辑的数量是最小的,因此它们不是添加另一层复杂性(数据库和模型的对象之间的映射),而是使用两个基本模式组成domain layer
(模型) :Table Data Gateway和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进行比较 目前为止最好的之一(IMO)使用 DataMapper模式。
就是这样。您仍然可以使用/dal
目录存储DataMappers,只需register the namespace,以便自动加载程序可以找到它。
答案 1 :(得分:0)
在我看来,应该每个模型都有一个网关抽象(不仅仅是数据库访问)。 DAO还不够。如果您需要在某个时刻从云端获取数据,该怎么办?这很快就会成为现实。如果您将网关逻辑抽象为通用的,然后使用数据库实现它,那么您可以充分利用这两个世界。
如果您愿意,特定网关接口的实现可以使用通用数据映射器。我在一家小公司工作,并且总是使用PDO创建我的实现。这让我足够接近数据库来处理我可能需要的任何有趣的SQL,但能够支持非常抽象的接口。
我根本没有使用过Zend Framework。我不知道他们是否有可以帮助您实现网关接口的数据映射工具。