Skip navigation

Sign up | Lost password? | Help

Hello World

Practical programming... and stuff...

A problem with the Zend MVC pattern

If you consider how the MVC pattern works in the Zend Framework, it first seems just fine. And yes, it is actually very good, but there's one problem:

It isn't designed to let you access your Models from the Views


What exactly does that mean? It means that the controller and the view (ie. the template) are very dependant on each other in some situations.

The problem



You have a page which displays a list of products. The products are fetched from the database and assigned to the template in the controller.

Now, say you wanted to display the product list in an another page. You need to combine the product list template to the other template and combine code from the product list controller to the other controller.


This causes some extra work when you want to reorganize a page. It's not necessarily a bad problem, but a problem is a problem. In the optimal case you would only need to combine the template. For example like this:

You have a template that just displays a list of products and nothing else. There is no other HTML code in the template. This would be easy to re-use on multiple pages, right?

It would - but the problem is that you would need to assign the required template variables on all the pages where you want to use this small piece of templating.




There are some problems with this approach, though. The problem arises when you need to access your models from the templates. As you probably know, the parent template doesn't necessarily know about the other models than the one it needs, so you need some kind of a method to instantiate the models inside the template. Sure, you could probably go for some kind of global variable that holds it, but that's not a very good approach as it wouldn't be very reusable etc.


Solutions?


Let the template access the model/db.

Instead of always accessing the model in the controller, you could let the view access the model and therefore the view would be more "pluggable" to other pieces of views.

There are some things that you need to consider on this though: The parent view does not necessarily know about the other models than it needs so you need a method to pass the other views the models they need.


One approach with the current version of Zend Framework is using the view helpers. You can make a view helper, grab the database from the front controller in the helper, instantiate the model and instantiate a new view.

Something like this:
class Zend_View_Helper_MyHelper
{
  public function myHelper()
  {
    //Get the db parameter from the front controller
    $db = Zend_Controller_Front::getInstance()->getParam('db');
    
    //Fetch data from the model
    $model = new MyModel($db);
    $data = $model->GetData();

    //Display the data with a new view
    $view = new Zend_View();
    $view->assign('data',$data);
    $view->render('template.phtml');
  }
}


There's one thing here though... The creation of the view. If you need to pass the view some configuration, for example if you're using Smarty as the template engine you'd need to pass it the compiled template dir as a parameter, you'll run into problems.

You would have to put the configuration you want to every view helper you create like this... or you could create a view factory. The view factory should just create the view always with the same parameters. This way you can just edit the factory class in case you need to change some configuration settings. I'm not going to go into details about the implementation of that here, but you can go read about the Factory pattern at Patterns For PHP for some guidance.


I will return to this topic on an another post where I will show you how you can use view helpers from Smarty templates and how you could implement the view factory.

Common crossbrowser CSS issuesSmarty + Zend_View, take three

Comments

Anonymous 7. August 2007, 19:03

Anonymous writes:

I like the ZF a lot, but Zend_View is pretty much my least favourite part of it. I often feel like I'm doing double work with it, pretty much for the reasons you describe. It *would* be a lot easier to just let the View access the DB, but once you do that it's far too easy to dump all your code into the View, which is counterproductive, of course.

Truth to be told, I'll never like MCV. Hell, I'll never like object oriented programming, but here we are anyway.

zomg 7. August 2007, 19:31

Yeah which is why I use Smarty. Well, it doesn't solve the problem as it doesn't have the ability to do that "properly" either. I might post later about a new feature I wrote for Smarty which helps a bit in certain things.


If you say you don't like OOP, you probably just never have ran into a situation where it's actually useful and much better than the "traditional" approach.

Anonymous 8. August 2007, 22:29

Anonymous writes:

I suppose I haven't, at that. I'm also of the frame of mind that everything has to be as efficient as possible. If you break things up into tiny objects (post, tag, comment, etc) and you use a database, you'll end up either doing bucketloads of useless object-related queries, or construction a data layer that's so complicated you want to shoot yourself.

No sir, my mind will never get with the OOP. My mind things OOP is poop, and that's that.

zomg 9. August 2007, 00:01

You have a quite twisted view of OOP. =)

What you say about efficiency might've been true back in the day, but if you consider PHP itself - it's far from efficient. Add a class or two... you won't even notice it.

Personally I use arrays to store most of the data such as posts, comments etc.... Of course they are fetched from the database first. I usually just use objects to create classes which can perform actions on the database.

For example, add news, remove news, get all news, get one news item and things like that. Compare that to the traditional approach where you build a function for each of those... it doesn't differ much except for the syntax that you use. There's one advantage in the class-based approach in this I think... that is the fact that if you have a lot of different functions, you'd have to do something like news_add, news_list, post_add, post_list, comment_add, comment_list and things like that to avoid name conflicts... with classes you can just put the related functions inside a single class such as NewsHandler, PostsHandler, CommentsHandler etc., which works kinda like namespaces at the very least.


I'm not trying to "convert" you to OOP or anything, it's your choice. Just thought it could make for an intresting discussion.


Fun fact: my comments on my own blog are sometimes much longer than some of the actual posts :D

Anonymous 17. August 2007, 09:33

Anonymous writes:

I'm trying to convert myself, but I'm not having much luck with it, sadly :P.

Anonymous 7. November 2007, 02:42

Vov writes:

Hmmm I think a main point of the MVC framework is that you *should't* access a model from the view (imagine being able to do an DB insert [*model*] from a template [*view*]... )



The best solution is to change the current *mindset* and be really good at discerning between what's a model task and what's a view task. And that's precisely what the Controller should do.



Yeah, It's easy to tell, difficult to do. But with practice we can get better ;)



BTW, I got here because of your "Smarty + Zend_View" post. You saved my day!

zomg 7. November 2007, 04:15

They are working on improving this issue with a component called Zend_Layout. I've heard it's currently in the incubator, so it shouldn't be too long from being implemented in the stable release of the framework.

BTW, I got here because of your "Smarty + Zend_View" post. You saved my day!


Glad you like it :smile:

Anonymous 12. November 2007, 12:37

Xavi Vidal writes:

I Agree with your point of view, but i feel what Zend Framework needs is another 'level' of call in the chaining process.



I mean, the controller is tied to the view, being the last one the template at the same time, so, what we need is another level:



Controller (extends Zend_Controller_Action) -->

View (but PHP code only, not HTML output) -->

Template (choose smarty, patTemplate, Sigma, etc..)



So, if two controllers wants to output the "products list", both can call the ProductsList View, and this view will render the correspondent Template.

zomg 13. November 2007, 14:27

As far as I've understood, Zend_Layout provides you with a mechanism called sub-requests which might answer that. For example, you can make a subrequest in your controller to a productListAction which sole purprose is to fetch the products and render them. The subrequest will then assign the rendered view to a template variable for you to use in the "main" view.

Anonymous 8. March 2008, 21:15

Anonymous writes:

I don't think you have a very good grasp on the MCV design pattern...

The WHOLE POINT of MCV is that the data and presentation layers are separate. Controllers add any logic necessarily to combine the data and the presentation in the right way.

http://sitepointstatic.com/graphics/rails-revealed_mvc-diagram.png

zomg 8. March 2008, 21:59

Please learn the proper acronym before you start telling people that they don't know anything about it.


However, the problem I talked about in this post has been dealt with quite nicely in ZF by adding the action view helper, as I mentioned in my comment above. (subrequest was changed to action)

Anonymous 5. February 2009, 04:18

Anonymous writes:

You're exactly right I have just read surviving the deep end Zend framework and the author brings up the point that view and controllers should be as small as possible with fat models.
because from my point of view

Models control all data (static, db-backend, soap, xml-rpc, etc.)
Views present the data.
Controllers tell what needs to go where (url-wise).

Half of the tutorials out their are just quick and Dirty. What happens when php6 drops open short tags? That ought to be a fun regex to change everyone's copy paste jobs to normal php tags.

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies