Hi,
It’s been a long time since I wanted to ask this question…
As far as I understand, and if this hasn’t become obsolete, it is a general rule of good practice in the MVC paradigm to “keep the view stupid”, that is, let the controller take decisions and manipulate data (by calling model logic, as in “fat model, thin controller”, another rule of good practice) rather than the view. Right?
So, a typical super-simplified way of showing a page with some data would be:
Controller code:
public function actionViewSomething(...) {
$someCriteria=.....
$items=SomeModel::model()->findAll($someCriteria);
$this->render("someView", array('items'=>$items));
}
View code:
foreach ($items as $item) {
//output pretty html with the properties of $item
}
So far so good.
Now, [size="5"]enter fragment caching.[/size]
The way fragment caching is conceived in Yii, you do it mainly in the view, right?
So the code should look like this:
Controller code:
same as before
View code:
if ($this->beginCache(/*some dependencies*/)) {
foreach ($items as $item) {
//output pretty html with the properties of $item
}
$this->endCache()
}
Now, the problem here is that you get only half (or less) of the benefit of fragment caching.
When the view is being cached, you are still doing useless database queries to gather the data, which you then don’t use.
Now you could do query caching in the controller, but that seems stupid to me, because you would have to duplicate the caching dependency logic, which would be error prone.
So, the only reasonable solution I’ve been able to come up with is the following:
Controller code:
public function actionViewSomething(...) {
$someCriteria=.....
$this->render("someView", array('criteria'=>$comeCriteria));
}
View code:
if ($this->beginCache(/*some dependencies*/)) {
$items=SomeModel::model()->findAll($criteria);
foreach ($items as $item) {
//output pretty html with the properties of $item
}
$this->endCache()
}
That is, instead of having the controller gather the data, and pass it to the view, I let the controller decide the criteria, and pass them to the view. The view then uses the criteria to get the data, unless the fragment turns out to be available from cache, in which case the data doesn’t need to be retrieved.
This doesn’t sound too bad to me, but it is certainly strongly against the “keep the view stupid” phylosophy.
In the oversimplified example above it’s just a matter of moving a find() call from the controller to the view, but in real-life scenario this means moving a lot of logic from the controller to the view which doesn’t seem fair. But it’s the only way (that I can see) to exploit the efficiency advantage of fragment caching.
So the question is:
-
is this a weakness of the MVC paradigm itself? (in that it’s all about elegance but becomes weak when it comes to efficiency)?
-
or is it a weakness in the way caching is conceived in Yii (in that it is inherently incompatible with the principles of MVC good practice)?
-
or am I missing the right way of doing stuff, which would allow to use all the good of fragment caching while maintaining the view stupid (i.e. keeping the data retrieval logic in the controller)?
And if the latter, then what is that right way I’m missing?
Or perhaps somebody can point me to some resources where this is discussed in a general context (not necessarily in the case of Yii)?
Thanks in advance
m.