【问题标题】:Models in the Zend FrameworkZend 框架中的模型
【发布时间】:2010-09-22 15:11:10
【问题描述】:

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

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

$foo = new User;

$foo->fetchAll()

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


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

【问题讨论】:

    标签: php model-view-controller zend-framework model


    【解决方案1】:

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

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

    对数据库的持久性应该是模型的内部实现细节。该模型通常使用一个或多个表。将模型视为表的扩展是一种常见但不恰当的面向对象设计。换句话说,我们应该说 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 对 Domain Model 设计模式的看法,以及他对 Anemic Domain Model 反模式的描述,这是不幸地接近 OO 编程的开发人员。

    【讨论】:

    • "...在 Zend_Db_Table 上做了很多工作..." 我知道你做了,Bill。老实说,我有点喜欢你的 php 工作。
    • FWIW,我没有开始这个项目,我只是在原来的人继续前进时才接手的。 Paul M. Jones (paul-m-jones.com) 值得称赞为 Zend_Db 组件的架构师。
    • 解释:胖模型和瘦控制器是好的。瘦模型和胖控制器很糟糕。
    • @Benedict:是的,但值得准确描述一下我们所说的这些术语的含义,以及为什么一个是好的,另一个是坏的。
    • Bill 你的博客很棒,但为什么不把它放在 ZF 文档中!?当我第一次做快速入门时,我没有理解“模型/映射器/Zend_Db_Table”的东西。
    【解决方案2】:

    我个人是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 的设计意图。 (这里有更多我的thoughts and links on the subject。)这种方法确实有点重,但我觉得它让控制器专注于处理输入和与视图协调;让模型去做特定于应用程序的工作。

    【讨论】:

    • 应该“受保护的 $_rowClass = 'Users';”已被“保护 $_rowClass = 'User';”?
    • $users->getById($id) 可以替换为内置的查找方法 $users->find($id)->current();
    【解决方案3】:

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

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

    【讨论】:

    • 完全同意!虽然这是一个过时的问题,但仍有很多人来这里看,所以我将发布我的解决方案。我写过文章我是如何在 zend 框架中实现模型和 ORM 的。希望对很多人有所帮助。它在:havl.net/devnotes/2010/10/zendframework-model-orm
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      我使用 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:Peer——用于查询。这些是静态对象。即 UserPeer.php

      所以要创建一个用户:

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

      要找到所有的derek:

      $c = new Criteria();
      $c->add(UserPeer::FIRST_NAME, 'Derek');
      $dereks = UserPeer::doSelect($c);
      

      【讨论】:

        【解决方案6】:

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

        这不是“生产代码”,还有很多东西可以想象,但它是一本很好的读物,对我有很大帮助。

        【讨论】:

          【解决方案7】:

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

          我建议您阅读 Eric Evans 的《Domain Driven Design》一书,这本书很好地解释了如何构建对象模型。

          【讨论】:

            【解决方案8】:

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

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

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

            【讨论】:

            【解决方案9】:

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

            请查看 Doctrine 以获取模型。它正在迅速成为 PHP 的事实 ORM。

            【讨论】:

            • Doctrine 会很棒,但我不能确定是否可以访问足够满足教义要求的最新 PHP 版本。
            • Doctrine 说它需要 PHP 5.2.3,而 ZF 需要 PHP 5.1.4,但也强烈推荐 5.2.3,因为它具有安全性和性能优势。
            【解决方案10】:

            您可以扩展 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 章将有助于解决这个问题。

            【讨论】:

              【解决方案11】:

              您可以进行更复杂的查询,请查看Zend_Db_Table 手册页中的Advanced usage 部分。

              $select = $table->select();
              $select->from($table,
                            array('COUNT(reported_by) as `count`', 'reported_by'))
                     ->where('bug_status = ?', 'NEW')
                     ->group('reported_by');
              

              【讨论】:

                猜你喜欢
                • 2010-11-15
                • 1970-01-01
                • 2012-03-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-02-28
                相关资源
                最近更新 更多