【问题标题】:Using ORM classes directly from the controller in MVC, bad practice?直接从 MVC 中的控制器使用 ORM 类,不好的做法?
【发布时间】:2011-06-19 15:40:21
【问题描述】:

我最近深入研究了在我的 CodeIgniter 应用程序中使用 ORM,而我选择的一个是 Propel。现在这使我能够基本上使用 Propels 类作为“模型”,但这是不好的做法吗?

所以我的控制器代码如下:

<?php
    class Page extends Controller {
        function __construct() {
            parent::__construct();  
        }   

        function index() {
            $foo = FooQuery::create()->limit(10)->find();
            $data['content'] = array('foo'=>$foo);
            $this->load->view('home', $foo);    
        }
    }
?>

我想在继续开发我的应用程序之前解决这个问题。如果您认为这是不好的做法,请举例说明我应该如何执行此操作。

提前致谢

【问题讨论】:

标签: php orm doctrine propel


【解决方案1】:

是的,这是不好的做法。

模型应该包含您的所有数据逻辑,并将其从程序的其余部分中抽象出来。对于应用程序的其余部分,模型应该看起来像从中获取数据的黑匣子。如果您使用 ORM 作为模型,那么您就是 leaking the abstraction 并将您的控制器与数据层紧密耦合。

相反,创建您的模型,并在其中处理 ORM。这样一来,如果您需要调整数据模型,只需在一个地方(模型层)进行更改,就可以知道抽象会成立。

【讨论】:

    【解决方案2】:

    使用 Propel 现在使用的 Query 类,我认为与更“正式”模型的差异变得越来越小。如果这将成为您发布到世界上的库,那么拥有一个抽象层将是一个优势,这样您就可以拥有不同的后端,但如果它是一个内部应用程序,我只会使用 Query 类作为您的模型.

    但请记住,Query 类的创建感觉就像一个实际对象,并且它们尽可能隐藏了关系部分。你可以利用它来发挥你的优势。查看this article about rewriting your SQL queries with Query methods,尤其是第三个答案:越来越多地移入您的Query 类,这样您的控制器就不会觉得它使用数据库。

    // Instead of this code in your controller,
    // tightly coupled to your database logic
    $books = BookQuery::create()
       ->filterByTitle('%war%')
       ->filterByPrice(array('max' => 10)
       ->filterByPublishedAt(array('max' => time()))
       ->leftJoin('Book.Author')
         ->where('Author.Name > ?', $fameTreshold);
    
    // You would use this code in your controller
    // and create small methods with the business logic in the BookQuery class
    $books = BookQuery::create()
      ->titleContainsWord('war')
      ->cheap()
      ->published()
      ->writtenByFamousAuthors();
    

    【讨论】:

      【解决方案3】:

      当您的 ORM 遵循 Active Row 模式时,我发现这是偶尔的必要邪恶。

      我经常遇到的问题是模型只表示数据结构的单个实例。在模型中添加集合检索方法是没有意义的。

      这是我历史上使用服务层来处理模型集合的拉入的地方。虽然说实话,最近我只是简单地编写了一个控制器帮助器对象,它只是抽象了我的表对象。

      【讨论】:

      【解决方案4】:

      这在很大程度上取决于您在做什么以及为什么。在此示例中,您在查询中放置了一个限制子句 - 是业务逻辑还是显示逻辑?从我的角度来看,很难说这是业务逻辑——我得到的 10 个元素与模型无关——这就是我认为在一页中使用多少是有意义的。如果您希望该规则在控制器之间保持一致,您可以设置一些配置值来强制一致性。但是放在模型中只会让模型不必要的大(胖模型和肥胖模型之间存在差异)

      我会说限制、订单和偏移通常不是业务逻辑。甚至一个简单的地方可能会或可能不会视情况而定。如果那里有连接,则表明有问题。

      Jan Fabry 的例子非常好。 filterByTitle 在我看来和 titleContainsWord 差不多。 filterByPublishedAt(array('max' => time())) 比 ->published() 差很多。一般来说,控制器需要了解的内部数据结构越少越好。

      【讨论】:

        猜你喜欢
        • 2011-11-15
        • 2011-04-24
        • 1970-01-01
        • 1970-01-01
        • 2015-12-11
        • 2014-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多