直接从MVC中的控制器使用ORM类,不好的做法?

时间:2011-02-01 23:51:53

标签: php orm doctrine propel

我最近在我的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);    
        }
    }
?>

我想在继续开发我的应用程序之前解决这个问题。如果你认为这是一个不好的做法,我应该如何做到这一点非常有用。

提前致谢

4 个答案:

答案 0 :(得分:7)

是的,这是不好的做法。

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

相反,创建模型,并在那里处理ORM。这样,如果您需要调整数据模型,您可以在一个地方(模型层)更改它,并知道抽象将保留。

答案 1 :(得分:4)

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

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

// 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();

答案 2 :(得分:0)

当你的ORM遵循Active Row模式时,我发现这是偶然的必然之恶。

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

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

答案 3 :(得分:0)

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

我会说限制,订单和抵消通常不是业务逻辑。即使是一个简单的地方可能会或可能不会取决于具体情况。如果那里有一个连接,那就表明出现了问题。

Jan Fabry的例子非常好。 filterByTitle看起来和titleContainsWord一样。 filterByPublishedAt(array('max'=&gt; time()))比 - &gt; published()差得多。通常,控制器需要了解内部数据结构越少越好。