MVC概念 - 其职责是加载模型?

时间:2013-02-04 16:57:41

标签: php model-view-controller model

好的我现在是MVC概念的基础知识,我知道有类似的问题,但仍然没有找到明确的答案。阅读MVC我发现了一些相互矛盾的例子,所以我想找出哪个概念更好。

我是否应该使用我的控制器从模型加载数据并将数据传递给视图,或者我应该让视图从模型加载数据并使用控制器来选择适当的视图。

对我来说,更自然(正确)的方法是控制器应该加载模型,但是如果我需要具有2个不同视图的相同内容,则会再次加载,例如:

  1. 视图显示简单的文章文字
  2. 视图显示相同的文章文本,但也会显示包含文章作者信息的框。
  3. 令我困惑的是我有单一请求,请给我看一下ID为33的文章。在第一种情况下,一切都很清楚,但现在我的第二个视图呈现使用不同的模板显示其他数据(关于作者),所以应该我让视图从模型(关于作者)请求数据,或者整个逻辑应该由控制器完成?

    这令人困惑,因为现在控制器应根据视图应呈现的模板从模型中请求适当的数据。

    希望我有道理:)

2 个答案:

答案 0 :(得分:2)

简短回答:将模型传递给控制器​​和视图。

长答案:在MVC中,控制器不会“从模型加载数据然后将该数据传递给视图”。视图与模型有直接关系,并从模型请求数据。请参阅:How is MVC supposed to work in CodeIgniterhttp://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller:“视图请求模型生成输出表示所需的信息。”

因此,要启用松耦合,请完全独立地启动模型视图和控制器,并将它们传递给彼此。

这允许MVC倡导者严格分离关注点,并允许您重用任何其他组件,因为没有任何硬编码。

类似的东西:

$model = new Model;
$controller = new Controller($model);
$view = new View($model, $controller);
echo $view->output();

控制器不应选择视图,也不应选择模型。通过将此职责放在控制器中,控制器无法与其他视图或模型重复使用。

编辑:我已更新此内容,以回答tresko关于视图为何需要了解其控制器的评论。

视图需要控制器以避免将控制器硬编码到视图中。这样一来,视图就知道它在当前上下文中与哪个控制器配对,并且可以回发给它。

事件(用户操作)在视图中触发,需要由控制器处理。

有三种方法:

1)硬编码视图:控制器关系,在网络上这是通过使用<a href="/some/hardcoded/route"实现的;或<a href="' . $this->router->create('someController, 'action') . '>'这消除了将视图与任何其他不可取的控制器一起使用的可能性。

2)将控制器传递给视图,让视图知道将触发其事件的控制器。在Web上,使用此方法视图还需要一个路由器,它将控制器操作转换为路由。例如<a href="' . $this->router->getRoute($this->controller, 'action') . '>'

3)将视图传递给控制器​​并让控制器在视图上设置操作:(控制器代码)$this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action')) ...(查看代码)<a href="' . $this->getEvent('buttonClick') . '>'

其中,

1)最不可取,因为它会严重影响灵活性。该视图只能在非常特定的控制器上调用操作。

2)是开发人员的最少工作量,但每个控制器都需要一个特定的接口。

3)这提供了最大的技术灵活性,但是开发人员需要做更多的工作,控制器需要了解很多关于它的视图,除了API之外,它必须知道视图中可用的事件。如果视图已更新并具有新操作,则需要更新每个控制器以对其进行说明。这也适用于2),但由于2可以使用界面轻松处理,因此更容易追踪使用它的每个类。

在我看来,2和3都是很好的方法,但2是优越的,因为它允许更强大的系统并允许最多次使用,缺点是控制器必须实现特定的接口。 3允许控制器具有任何接口,但它必须对其视图有很多了解。

CakePHP和其他流行的框架倾向于硬编码关系(例如http://book.cakephp.org/2.0/en/views.html)这里的示例,echo $this->Html->link('edit', array( 'action' => 'edit', $post['Post']['id'])); ?>链接只能转到“编辑”控制器。这严重影响了重用。

答案 1 :(得分:-1)

我的建议是,将数据源与视图结合起来的逻辑应完全在控制器中完成。视图不应绑定到特定数据源。

例如,如果您有一个使用Smarty语法(或类似)与命名占位符的视图,那么您可以使用任何数据源,文本,模型等来提供信息以呈现到模板中。如果视图与模型相关联,则需要修改模型和视图,并了解对另一个模型的影响。

这样的紧耦合会因疏忽而忽略某些东西而导致更多问题,这会让您减少意外破坏的机会。

实施例

class Page_Controller extends Controller {

  // __construct/__destruct/__callStatic/__call/etc, whatever you need in your implementation

  // -------------------------------------------------------
  // Adjust to suit your situation for passing data
  // This controller doesn't care where objSource comes from
  // -------------------------------------------------------
  private function pageSpecificImplementation($objSource = null){

    // using a factory class - but assume a view is created in whatever way works for you
    // the key thing here is that the view could be anything that can be returned as a string - but use whatever works for you
    $tplMain = make::view( 'template-url-or-path' )->assign(array(
       'placeholder1' => $objSource->value1,
       'placeholder2' => $objSource->value2
    ));

    $tplSub = make::view( 'template-url-or-path' )->assign( $objSource );

    $tplMain->assign('sub',$tplSub->render())->render();

    // $tpl is some form of html? csv?, who knows - not relevant at THIS stage

    // okay - now I know what I want to do!
    // decide what to do with it here - output headers for html
    // save to a file
    // output and cache the output, whatever works for you here
    // output to pdf?
    // send as an email?
    output::html( $tplMain, $cacheable, $cachetime... );
    // output::email( $tplMain, $extra_params );
    // output::pdf( $tplMain, $extra_params );
  }

}

在这里,您使用的是视图,而不是将其与输出紧密耦合。您的控制器可以根据运行时正在运行的业务规则修改输出,但数据源不依赖于视图,输出不依赖于视图。

我建议'某些'实现以一种遵循类似原则的方式分离。 YMMV取决于你正在做什么以及你想如何实现它,但尝试在MVC中保持每个元素分开。

在某些实现中,您将看到“替换”视图中的内容的逻辑,而不提及“什么”视图。这通常在Smarty中完成。然后可以通过Controller的流程确定视图。可以从多个模型或其他来源提取数据,这可能会或可能不会影响哪个视图是合适的。

因此,您绝对应该从视图中分离数据加载。将其保留在控制器中,这是决策的地方。视图不应该与模型连接,除非您考虑到特定的用例,例如主题模型与主题视图紧密耦合,其中不涉及额外的业务逻辑(不太可能但可能?)。