2

OK I now basics of the MVC concept, and I know there are similar questions asked but still didn't find clear answer on this. Reading about MVC I found some contradictory examples, so I wanted to find out which concept is better.

Should I use my controller to load data from the model and than pass that data to the view or should I let the view to load data from the model and use controller just to select the appropriate view.

The more natural(right) way to me is that controller should load the model, but than again if I have require the same content that has 2 different views, for example:

  1. view displays simple article text
  2. view displays same article text but also displays box with article author info.

The thing that confuses me is I have single request, show me article with ID 33. In the first case everything is clear, but now my second view renders using different template that shows additional data (about the author), so should I let the view to request data from the model (about author) or that entire logic should be done by controller?

It's confusing because now the controller should request appropriate data from the model based on template the view should render.

Hope I make sense :)

kruno
  • 21
  • 5

2 Answers2

2

Short answer: Pass the model to the controller and the view.

Long answer: In MVC, the controller does not "load data from the model then pass that data to the view". The view has a direct relationship with the model and requests data from it. See: How is MVC supposed to work in CodeIgniter and http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller : "A view requests from the model the information that it needs to generate an output representation."

As such, to enable loose coupling, initiate the model view and controller completely independently and pass them in to eachother.

This allows the strict separation of concerns MVC advocates and allows you to reuse any component with any other as nothing is hardcoded.

Something like:

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

The controller should not select the view, nor should it select the model. By putting this responsibility in the controller, the controller is not reusable with other views or models.

Edit: I've updated this to answer tresko's comment about why the view needs to know about its controller.

The view needs the controller in order to avoid hardcoding controllers into views. This is so that a view knows which controller it's paired with in the current context and can post back to it.

Events (user actions) are fired in the view and need to be handled by controllers.

There are 3 ways of doing it:

1) Hardcode the view:controller relationship, on the web this is achieved by using <a href="/some/hardcoded/route"; or <a href="' . $this->router->create('someController, 'action') . '>' This removes the possibility to use the view with any other controller which isn't desirable.

2) Pass the controller to the view and let the view know which controller its events will be fired to. On the web, using this approach the view will also need a Router which will convert a controller action into a route. e.g. <a href="' . $this->router->getRoute($this->controller, 'action') . '>'

3) Pass the view to the controller and have the controller set actions on the view: (controller code) $this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action'))... (view code) <a href="' . $this->getEvent('buttonClick') . '>'

Of these,

1) Is the least desirable as it heavily impacts flexibility. The view can only ever call actions on a very specific controller.

2) is the least amount of work for the developer but each controller needs a specific interface.

3) This offers the most technical flexibility but there's more work for the developer and the controller needs to know a lot about its view, beyond the API it must know what events are available in the view. If a view is updated and has a new action, each controller will need to be updated to account for it. This applies to 2) as well, but because 2 can easily be handled using interfaces it's far easier to track down every class which uses it.

In my opinion, 2 and 3 are both good approaches but 2 is superior because it allows for a much more robust system and allows the most re-use, the downside is that controllers must implement a specific interface. 3 allows the controller to have any interface but it must know quite a lot about its view.

CakePHP and other popular frameworks tend to hardcode the relationship (e.g. http://book.cakephp.org/2.0/en/views.html ) here in their example, echo $this->Html->link('edit', array( 'action' => 'edit', $post['Post']['id'])); ?> the link can only go to the "Edit" controller. This severely impacts reuse.

Community
  • 1
  • 1
Tom B
  • 2,735
  • 2
  • 24
  • 30
  • Thanks. But looking it that way I ask myself who needs controller? I mean after application start I could generally call appropriate view based on request parameters, that will load the view, view would ask data from model and output it :) – kruno Feb 04 '13 at 18:33
  • Why is view controlling the controller? If controllers are not reusable, why do you inject it in a class which you expect to be reusable? Is view expecting a controller with strictly defined footprint? Where in the definition of MVC is said that View executes command on the Controller? – tereško Feb 04 '13 at 21:09
  • 1
    http://upload.wikimedia.org/wikipedia/commons/f/fd/MVC-Process.png Here's the "MVC process" graphic from Wikipedia. It shows the user "uses" the controller. However, a "controller" is meaningless to the user, they "use" the view. From Java Blueprints, model-view-controller: http://briggs.myweb.port.ac.uk/WEBP/notes/images/mvc-structure-generic.gif "View - Sends user gestures to controller". The controller gets called from the view, the only thing the user truely interacts with. – Tom B Feb 04 '13 at 23:22
  • The "user" in context of web is the browser. Which, as shown in "progress" image, interacts with the controller. Controller handles the user input. Controller is not meaningless, unless you intend to get rid of the controller and merge it's responsibilities in the view (which you advocate). – tereško Feb 05 '13 at 09:29
  • 1
    http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html "A view's instance variable controller points at its controller, and a controller's instance variable view points at its associated view" Whether the user input comes from a function in the view to the controller or via a HTTP request is an irrelevant implementation detail, the architecture is the same. Simple example: user clicks a button. The user interacts withe the view, the button is part of the view not the controller. What happens when that button is clicked is dealt with by the controller-but the event is fired by the view. – Tom B Feb 05 '13 at 10:18
  • 1
    @TomB The links you provided in your other post where really useful. And the simple statement there: "Controller receives user input, updates the model if necessary and informs the view that model has changed." Makes things much clearer. – kruno Feb 06 '13 at 11:35
  • 1
    Just keep in mind that the last part about informing the view if the model has changed is irrelevant on the web as the view has to always be refreshed anyway, as such it will need to request the current state of the model. – Tom B Feb 06 '13 at 12:13
-1

My suggestion is that the logic for combining data sources with views should happen entirely in the controller. Views should not be bound to specific data sources.

For example, if you had a view that used the Smarty syntax (or similar) with named placeholders, then you could use any data source, text, model, etc to provide information to render into the template. If the view is tied to a model, you'd need to modify the model and view with an awareness of the impact on the other.

Tight coupling like that leads to more problems by accidentally overlooking something than looser coupling, which gives you fewer chances of breaking something by accident.

EXAMPLE:

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 );
  }

}

Here, you're using a view, without tightly coupling it to the output. Your controller can modify the output based on whatever business rules are in play when it's run, but the data source is not tied to the view and the output isn't tied to the view.

I'd suggest 'some' implementation that separates in a way that follows similar principles. YMMV depending on what you're doing and how you want to implement it, but try to keep each element separated in MVC.

In some implementations you'll see the logic for 'replacing' things in views done without mentioning 'what' view. This is commonly done in Smarty. The view can then be determined by the Controller's flow. Data can be pulled from multiple models or other sources, which may, or may not, affect which View is appropriate.

So, you should definitely separate loading of data from the view. Keep it in the controller, which is where decisions should be made. Views shouldn't connect with models unless you have a specific use case in mind, such as a theme model with a tightly coupled theme view where there's no additional business logic involved (unlikely but possible?).

MyStream
  • 2,533
  • 1
  • 16
  • 33
  • Down votes should come with explanations so posters can either remove or revise to be more useful, rather than leaving them here with no way to improve this for others. – MyStream Feb 05 '13 at 02:35
  • I didn't down-vote, but this is obviously because you implement something that is close to `MVP` and breaking the `SRP` – Yang Jul 23 '13 at 22:03
  • @DaveJust - what do you mean by breaking SRP rules? – MyStream Aug 15 '13 at 20:38