好的我现在是MVC概念的基础知识,我知道有类似的问题,但仍然没有找到明确的答案。阅读MVC我发现了一些相互矛盾的例子,所以我想找出哪个概念更好。
我是否应该使用我的控制器从模型加载数据并将数据传递给视图,或者我应该让视图从模型加载数据并使用控制器来选择适当的视图。
对我来说,更自然(正确)的方法是控制器应该加载模型,但是如果我需要具有2个不同视图的相同内容,则会再次加载,例如:
令我困惑的是我有单一请求,请给我看一下ID为33的文章。在第一种情况下,一切都很清楚,但现在我的第二个视图呈现使用不同的模板显示其他数据(关于作者),所以应该我让视图从模型(关于作者)请求数据,或者整个逻辑应该由控制器完成?
这令人困惑,因为现在控制器应根据视图应呈现的模板从模型中请求适当的数据。
希望我有道理:)
答案 0 :(得分:2)
简短回答:将模型传递给控制器和视图。
长答案:在MVC中,控制器不会“从模型加载数据然后将该数据传递给视图”。视图与模型有直接关系,并从模型请求数据。请参阅:How is MVC supposed to work in CodeIgniter和http://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的流程确定视图。可以从多个模型或其他来源提取数据,这可能会或可能不会影响哪个视图是合适的。
因此,您绝对应该从视图中分离数据加载。将其保留在控制器中,这是决策的地方。视图不应该与模型连接,除非您考虑到特定的用例,例如主题模型与主题视图紧密耦合,其中不涉及额外的业务逻辑(不太可能但可能?)。