views:

854

answers:

7

If a view needs to acces data from a model, do you think the controller should:

a) pass the model to the view
b) pass the data of the model to the view
c) neither; it shouldn't be the controllers concern. Let the view access the model directly to retrieve the data. Only let the controller give some parameters the view needs to filter the data from the model.
d) it depends on the situation.
e) none of the above, but [...]

Thanks

After some debate in the comments to an answer that was deleted by the user, maybe this needs clarification. My view of the MCV architecture is biased towards that of the Zend Framework (php) in which an action in a controller by default has a default view assigned to it. So it's not so much the model that dictates which view is approporiate, but rather the controller. Do you feel the model should dictate what view is appropriate? The only way I see fit to let the view be build based on a model, is by letting the controller pass the model to the view. Are there other techniques to let a view access a model without the controller being involved? Or is it perfectly fine to let a controller pass the model to a view, so that the view can be build based on the models attributes?

A: 

uhh b.

i dont really see the difference between a and b other then some technicallity of how you will be passing data.

usually you pass a map of data to the view with some data from the model

mkoryak
It's an SRP issue. The important difference is that if you do a) the View is coupled to the Model, and if you do b) the Controller is coupled to the View. If you use a ViewModel then the ViewModel explicitly gets the responsibility to bridge the gap between the View and the Model, allowing the Model, View, and Controller to go about their jobs without worrying about coupling - especially if you use the Factory pattern to create the ViewModel.
Iain Galloway
+2  A: 

Ideally, it should "pass the data of the model to the view" so the view doesn't need to know any explicit structure of the model and thus be more reusable and designer-friendly.

But practically, "pass the model to the view" works as just fine. Most of the time you will need a new view anyway because clients never share favorite colors (if you know what I mean :-) so views re-usability doesn't justify having a lot of tedious code required to copy data from the model to the view.

What you should concern more about is the modularity of the controller itself, since many websites do share common functionalities (controllers) such as web forums or a news listing but not looks (views)

chakrit
Don't you feel that somewhat violates the Single Responsibility Principle? - if you do a) then the View has to change if the implementation details of the Model change. If you do b) then even worse, the Controller has to change if either the Model or the View change. By confining into a ViewModel the code which translates your domain model into a format suitable for consumption by your View, you isolate your View from changes in the Model, and you isolate your Controller from changes in either.
Iain Galloway
Sure, there are the principles to be worry about... how about the KISS principle? ... ViewModel works in WPF/Silverlight context because you have a super-binding engine moving data around automatically for you, but in this case it's an HTTP environment, data is moved at a lot slower rate (i.e. no live-updating, no shiny animations etc.) -- Putting in so much code just for the sake of printing some paragraphs out as HTML is just making unnecessary maintenance nightmares later. -- I cannot think of an example where an extra ViewModel layer is worth the level of complexity it'll add.
chakrit
On the contrary, I feel that decoupling the view from the model *reduces* your "maintenance nightmares" later. I find objections based on "putting in so much code" to be entirely false. The code *has* to go somewhere. In your solution it goes in the Controller, tangled up with the Controller's responsibilities. In mine, it gets its own home. Same "amount of code". Less coupled. I find objections regarding moving the data around similarly false - the data is moving between the Controller and the View (or between the FormCollection and the Controller on the way back), not between client/server.
Iain Galloway
@lain Galloway I think you miss my point. My code doesn't goes into the controller, I simply reuse the model class without the "ViewModel". Remember "The code has to go somewhere", that somewhere is **already** in the model so most of the time adding a "ViewModel" layer is code duplication/unjustified complexity. Less "amount of code". Less "complexity", and yes, a little more "coupled" trading that off.
chakrit
@lain Galloway What I mean by "HTTP environment" is that you move data only once from the Database to Controller to the View for a single request and that's it. -- unlike in WPF scenarios which data can move just by a user moving his mouse... thus if you do *not* have a ViewModel you will end up with a lot of animation/interaction code that only copies values from places to places just to update the UI -- in which case factoring out those code into a "ViewModel" is not only appropriate but should be proactively done. -- But when you're just outputting HTML, I don't think that is justifiable.
chakrit
@lain Galloway Further more, if *overly* used, you will instead end up with a lot of code duplication between Model and ViewModel leading to eventual maintenance nightmare... See this post from Jeff's for more explanation of what I mean: http://www.codinghorror.com/blog/archives/000878.html ... [The best code is no code at all] ... unjustified complexity = maintenance nightmare
chakrit
@chakrit so the model knows what data the view needs and how to format it, and is responsible for the transformation? or the controller knows what data the view needs, how to format it, and is responsible for the transformation. You're skipping between the two. The code is not already in the model because the model is concerned with modelling the domain and not with how that data is going to be viewed. The code is not already in the controller because the controller is concerned with application flow. There's no duplication because ViewModel is only concerned with bridging the gap to the View.
Iain Galloway
@Iain Galloway Miss my point again... maybe I'll just give up.
chakrit
@chakrit I'm not missing your point. I disagree with it. Using a ViewModel reduces complexity compared to using the Model directly, or having the Controller extract the data. Try a different tack maybe, do you think the same argument applies to DTOs? Are they "unjustified complexity"? Do they lead to a "maintenance nightmare"? I'll tell you from experience that it's the lack of them that leads to the nightmare, and the motivation behind ViewModels is similar.
Iain Galloway
+1  A: 

a) pass the model to the view

Otherwise the controller is manipulating the view via screening the model. This is what would happen in "b) pass the data of the model to the view". The b) option doesn't really even make sense in the pure MVC pattern. After all, the model IS the data. If the model is changed for consumption, a view has been applied, whether you choose to do it in the controller and pass it off as a controller function. What happens when you have a different view? Does the controller screen its data differently? You soon have two views for model, the controller sub-view and the view itself.

dacracot
Oh yeah... As for c), it is the controller's role to control, d) nope, consistency is why we use patterns, and e) is no pattern at all.
dacracot
Here is Reenskaug's article... http://folk.uio.no/trygver/2003/javazone-jaoo/MVC_pattern.pdf ...describing in 1978 his Xerox PARC work regarding MVC.
dacracot
As I've commented on Iain's answer also: I'm a little bit confused. Both your answer's seem to assume that the controller still is responsible for tying the Model to the correct View. Is this correct? Or is your proposal assuming that the View is capable of determining what definite View (or template) it should use to render based on the Model it recieves? (More in line with Zend frameworks ViewRenderer object; like the name suggests: a renderer that you can tell which view it should render, usualy dictated by the Controller's action method).
fireeyedboy
The controller is responsible for tying the model to the correct view. The controller is responsible for the transaction, and therefore depending upon the result of that transaction, the subsequent display by choosing the appropriate view. This is difficult in practice, and I have broken it myself by placing branching logic in the view, but it is to be avoided.
dacracot
Look at my post here too... http://stackoverflow.com/questions/140098/is-mvc-ars-preferable-to-classic-mvc-to-prevent-overloading ...and keep in mind that MVC is a pattern. A pattern is a guide. If you are a smart coder, you will adjust it to best handle your situation. This is ok. If it were a hard fixed rule, the computer wouldn't need you to tell it what to do.
dacracot
+5  A: 

e) None of the above; pass in a view-optimised "ViewModel".

Example in ASP.NET MVC:-

public ActionResult Details(int id)
{
  Product p = ProductService.GetProductById(id);

  if(p == null) { return RedirectToAction("Index"); }

  ProductViewModel model = new ProductViewModel(p);
  return View(model);
}

both a) and b) "will do" subject to d). Never ever c).

Typically, the ViewModel just encapsulates the Model (if nothing complicated is going on, your view could access the model directly via ProductViewModel.Product). If the view needs to do anything complicated with the Model however, it's the ViewModel's responsibility to do that, rather than the responsibility of the Controller, or the View.

This keeps your concerns nice and segregated. Your Controller doesn't care exactly what specific data your View needs (beyond the fact that it's rendering some Details of a Product), or especially what format your View needs that data in. Your View doesn't depend on the implementation details of your Model. Your Model doesn't have to concern itself with how it's being Viewed. If you have two Views rendering Products (e.g. Create, Edit, Summary, MoreDetails etc), those Views can have different ViewModels to expose only the data that each specific View needs, so your Views aren't depending on eachother. Lovely :)

Some further reading from various viewpoints:-

http://www.thoughtclusters.com/2007/12/datamodel-and-viewmodel/

http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx

http://www.nikhilk.net/Silverlight-ViewModel-MVC.aspx

I think ViewModels are a particularly .NET thing, but I see no reason at all why the pattern can't be used in PHP.

Hope this helps.

Iain Galloway
I like this idea a lot. Thank you. I'm going to think about how I could encorporate this in applications based on the Zend Framework.What I'm still worried about (but maybe your View object is different from ZF's View objects) is that the controller still needs to decide what view should be rendered. In a pure MVC sense, shouldn't the Model (or in your case the ViewModel) decide what view it needs to be rendered correctly? In your example it still looks like the controller is responsible for coupling the correct View with the correct ViewModel. Is this assumption correct?
fireeyedboy
If you're going to display a different view depending on some aspect of the Model, or some aspect of the request, the yes, absoloutely, the controller is responsible for choosing a View to render, and for providing that View with some Model object/data. I'm not sure how Zend handles it, if it has a layer inbetween that does the picking, then stick with that. In ASP.NET MVC you just specify the name of the View you'd like to display (e.g. return View("Index");), subject to a few assumptions, conventions, and defaults.
Iain Galloway
+1  A: 

For me that's e).

As already mentioned here, ideally the view and the model are decoupled. The way I prefer to implement this is to have a viewHelper for a model. This has the API the view can use to get the data. Now views are not affected by changes in the model and the view doesn't need to 'get' the internals of the model. These are hidden away by the viewHelper.

example:

class Post {
    public function export(ViewHelper $helper) {} // I try to avoid getters when I can
}

class PostViewHelper {
    public function getTitle($parameters) {} // title of current post in the loop
}

class PostView {
    private $helpers = array();
    public function loadTemplate($path) {}
    public function addHelper(ViewHelper $helper, $name) {}
    public function __get($key) {} // if exists $this->helper[$key] etc
}

in a template

<h1><?php $this->post->getTitle(); ?></h1>

You may want to implement this differently. But my point is in how the view and the model are decoupled, introducing an intermediate viewHelper wich creates the view/template API.

koen
+1  A: 

I don't think it's that complicated. a or b.

The controller's job is to manage the relationship. It finds the model and view and provides the view all the model data it needs to do its job. That's it. MVC doesn't dictate the exact form the data takes.

(a) Start simple. It's pretty natural to pass the model objects directly to the view. If you have a page about a Foo, just pass the Foo.

(b) But at times-- and only at times-- you create a value object / DTO to get the data to the view (called a ViewModel above). Do this when there's a mismatch between the view and the native model, such as summary views. If the view is presenting a summary of 1,000,000 objects, you don't want to hand the view the model objects; you want to hand the view a summary of the 1,000,000 objects.

And the exact implementation really depends on the language and framework you are using. But I think these guidelines are a good start.

ndp
+1, although I'd point out that in many instances it's a boon for maintenance to do b) (I've called it e) but we've basically proposed the same thing) and have your DTO just encapsulate your Foo. It's a simple refactor though so you'd probably just apply YAGNI and get on with it. In addition, a ViewModel in ASP.NET MVC isn't quite a DTO (ViewModels can have behaviour, DTOs are just getter/setter), but that's getting pretty picky :P
Iain Galloway
A: 

Hi,

This is late I know, but I'm having this issue on a project I am working on. I started with a) - for simplicity - and now running into road blocks.

I am coming around to this method:

e) None of the above; pass in a view-optimised "ViewModel".

because it avoid bloating both your model classes (instances of which are "transaction objects") and your views. For example, you may need to render a number with a specific number of decimal places (this is the problem I am having now).

With an intermediate "ViewModel" this is easy - you just write the relevant ViewModel "getXXX" method to return the number formatted how you wish.

If you just pass the model directly into the view, you will need to specify it in the view every time you use this figure (going against DRY - don't repeat yourself), or alternately, add a rendering method to your model classes (which goes against a class being for one purpose only).

Cheers

Paul Hanssen