33

您在 Zend 框架中实现模型的方式有哪些?

我已经看到了基本的class User extends Zend_Db_Table_Abstract,然后在你的控制器中调用它:

$foo = new User;

$foo->fetchAll()

但是更复杂的用途呢?文档的快速入门部分提供了这样一个示例,但我仍然觉得我没有得到 Zend Framework 中模型的“最佳使用”示例。有什么有趣的实现吗?


编辑:我应该澄清(回应CMS的评论)......我知道做更复杂的选择。我对模型概念的整体方法和其他人如何实现它们的具体示例感兴趣(基本上,手册遗漏的内容以及基本操作方法的内容)

4

11 回答 11

61

我为 Zend 工作,并在 Zend_Db_Table 组件上做了很多工作。

Zend Framework 没有就域模型模式的“模型”概念提供很多指导。Model 没有基类,因为 Model 封装了特定于您的应用程序的业务逻辑的某些部分。我更详细地写了一篇关于这个主题的博客。

对数据库的持久性应该是模型的内部实现细节。该模型通常使用一个或多个表。将模型视为表的扩展是一种常见但不恰当的面向对象设计。换句话说,我们应该说 Model HAS-A Table——而不是 Model IS-A Table。

这是一个 IS-A 的例子:

class MyModel extends Zend_Db_Table_Abstract
{
} 

这是一个 HAS-A 的例子:

class MyModel // extends nothing
{
    protected $some_table;
}

在真实的领域模型中,您将在 MyModel 的方法中使用$some_table。

您还可以阅读 Martin Fowler 对域模型设计模式的看法,以及他对贫血域模型反模式的描述,即不幸的是有多少开发人员使用了 OO 编程。

于 2008-11-17T07:23:03.157 回答
23

我个人将 和 子类Zend_Db_Table_AbstractZend_Db_Table_Row_Abstract。我的代码和你的代码之间的主要区别在于,明确地将子类Zend_Db_Table_Abstract视为“表”和Zend_Db_Table_Row_Abstract“行”。我很少看到直接调用选择对象、SQL 或控制器中内置的 ZF 数据库方法。我尝试隐藏请求特定记录以调用后面的逻辑,Zend_Db_Table_Abstract如下所示:

class Users extends Zend_Db_Table_Abstract {

    protected $_name = 'users';

    protected $_rowClass = 'User'; // <== THIS IS REALLY HELPFUL

    public function getById($id) {
        // RETURNS ONE INSTANCE OF 'User'
    }

    public function getActiveUsers() {
        // RETURNS MULTIPLE 'User' OBJECTS            
    }

}

class User extends Zend_Db_Table_Row_Abstract {

    public function setPassword() {
        // SET THE PASSWORD FOR A SINGLE ROW
    }

}

/* CONTROLLER */
public function setPasswordAction() {

    /* GET YOUR PARAMS */

    $users = new Users();

    $user = $users->getById($id);

    $user->setPassword($password);

    $user->save();
}

有很多方法可以解决这个问题。不要认为这是唯一的,但我尝试遵循 ZF 的设计意图。(这里有更多关于这个主题的想法和链接。)这种方法确实有点重,但我觉得它让控制器专注于处理输入和与视图协调;让模型去做特定于应用程序的工作。

于 2008-11-17T05:22:02.620 回答
7

永远不要使用 Zend_Db_Table 作为模型。它只会让你陷入困境。您可以编写自己的模型类来使用 Zend_Db_Table 与您的数据库对话,或者您可以阅读我的博客文章了解允许您在某种程度上结合“模型”类和 Zend_Db_Table 的技巧。

最重要的是,当您直接在控制器中使用 Zend_Db_Table 时,您最终会在多个地方执行相同的操作。如果您必须对某些逻辑进行更改,则必须在多个地方进行更改。不好。我的第一个专业项目是这样完成的,因为我是公司里必须学习如何使用 ZF 的人,现在完全一团糟。

我还倾向于将辅助函数写入我的类中以进行复杂的提取。类似于 $table->doNameFetchAll() 或 $table->doOrderFetchAll() 之类的东西。

于 2008-11-17T08:43:22.887 回答
7

我一直在对 ZF 模型进行一些研究,并偶然发现了 Matthew Weier O'Phinney 撰写的一系列有趣的文章,这些文章非常值得一看:

它不是“生产代码”,很多东西都留给想象,但它是一本很好的阅读书,对我有很大帮助。

于 2009-01-26T21:40:16.440 回答
5

模型与数据库无关。如果我从 RSS 提要或 SOAP 服务获取数据或从 FS 读取文件怎么办?

我把所有这些东西放在模型中。在这种情况下,我的模型类可能不会扩展任何东西。我即将编写一个使用其他模型方法的模型。

于 2010-10-29T11:41:16.667 回答
3

跳过模型部分的 ZF,有更好的解决方案。ZF 的“MVC”中的“M”几乎没有。阅读他们的文档,他们根本没有真正提到模型——这是一件好事,这意味着您可以使用几乎任何您想要的东西,而无需编写大量适配器代码。

改为查看Doctrine模型。它正在迅速成为 PHP 的事实上的 ORM。

于 2008-11-17T05:07:14.943 回答
1

您可以进行更复杂的查询,请查看手册页中的高级用法部分。Zend_Db_Table

$select = $table->select();
$select->from($table,
              array('COUNT(reported_by) as `count`', 'reported_by'))
       ->where('bug_status = ?', 'NEW')
       ->group('reported_by');
于 2008-11-17T04:39:22.317 回答
1

您可以扩展 Zend_Db_Table_Abstract 类并向其添加一些有用的方法。例如,您可以将 changePassword() 方法添加到您的用户类并操作它的数据。或者您可以更改类的默认 __toString() 方法,因此您将拥有一个自定义的 __toString() 方法,假设以格式良好的字符串返回用户的整个联系信息(姓名、地址、电话号码) . 在您的构造函数中,您可以将数据填充到对象的属性中。然后像这样使用它们:

public function __toString() {
   $data = $this->_name . ', ' . $this->_adderss . ', call: ' . $this->_phone;
   return $data;
}

您的模型扩展 Zend_Db_Table_Abstract 只是为了简化访问其数据的过程,但是您可以对这些数据拥有的功能完全取决于您的创造力和需求。我向你推荐 Cal Evans 的书“php|architect's guide to Programming with zend framework”。这本书内容丰富,易于阅读。第 4 章和第 6 章将有助于解决这个问题。

于 2008-11-17T05:00:45.847 回答
1

数据库实体不是唯一一种模型组件。因此,谈论模型(复数形式)并没有真正意义——您的应用程序有一个模型,其中包含大量组件。其中一些组件可能是表网关(因此扩展自Zend_Db),而其他组件则不是。

我建议您阅读 Eric Evans 的《领域驱动设计》一书,该书在解释如何构建对象模型方面做得非常出色。

于 2008-11-17T20:55:55.403 回答
1

我使用 Propel 1.3 而不是 Zend_Db_Table。设置起来很棘手,但很棒。它可以检查您的数据库并自动生成所有模型。它实际上生成了 2 个级别和 2 种类型的模型。

“用户”表的示例:

第 1 级:BaseModel 和 BasePeer:每次重新生成 ORM 时,这些都会被覆盖。即 BaseUser.php & BaseUserPeer.php

第 2 级:StubModel 和 StubPeer:这些不会被覆盖。它们是您自定义的。即 User.php & UserPeer.php

类型 1:模型 - 用于基本 CRUD 操作,而不是查询,即 User.php 类型 2:对等 - 用于查询。这些是静态对象。即UserPeer.php

所以要创建一个用户:

$derek = new User();
$derek->setFirstName('Derek');
$derek->save();

要找到所有 dereks:

$c = new Criteria();
$c->add(UserPeer::FIRST_NAME, 'Derek');
$dereks = UserPeer::doSelect($c);
于 2009-01-30T14:52:16.023 回答
1

http://zfsite.andreinikolov.com/2008/08/zend_db_table-time-overhead-about-25-percents/

有点问题 22,Zend_Table 原则上很好,但会产生一些性能开销(没有缓存)......

于 2010-04-06T14:58:55.967 回答