So far I’ve been used to work in a View part with what I call „push template“, where a view at first runs all needed actions and afterwards injects collected content into template. This system works fine but I sometimes have issues with inner templates for tables etc. Working solution looks a bit ugly for me. Nothing serious but eventually these issues point me to the other way how to do things – „pull templates“.
Here a view simply includes template with wrapper functions providing content. All data fetching starts from these functions, after include. You surely know what I am talking about:
<?php if (have_posts()) : while (have_posts()) : the_post();?>
Of course pull templates could contain method calls but from designer’s point of view the procedural functions look likely better.
I tried to google some experiences and comparisons for these approaches two but was not lucky. Personally I think the second way is better, but I’d welcome any remarks to this stuff.
How it’s written is irrelevant here. It’s the repetition of logic that’s the problem. When the requirements change (e.g. is logged in and is an admin) you potentially need to modify the code in multiple places.
Well quite, it was a trivial example to demonstrate a basic idea. In the real world the logic becomes more complex. For example, “Each forum has a minimum registration date, the user can only see the posts when they have been registered long enough” this would involve sending the $topic variable to the user->canView() method so it can read $topic->minimumRegistrationDate
By leaving the logic out of the template, it doesn’t matter how absurd the client’s ideas are much the system needs to change, it can easily cater for it because everything is fully separated.
I disagree with the way most MVC web frameworks do things (see the first link in my signature ) but still believe there is a benefit to be had in separating templates and the logic behind them.
Good topic. I’m sure a great discussion will come out of this.
From an MVC perspective, “pull” templates (as you call them) actually fit within the concepts of traditional MVC better than “push” templates that get their data injected in them from a controller, but for some reason most of the web-MVC frameworks and implementations use the “push” method. There is absolutely nothing wrong with the view reading data or requesting it directly from the model without an intermediary. This, in fact, leads to views and templates are are decoupled from controllers, which is a good thing if you need to re-use the same view template in multiple places. Good testability only requires that the dependencies are exposed, so you can hand off instantiated datamappers/activerecords/gateways/whatever to your view and let it pull all the data it needs if that is an important goal in your development.
I agree with your general assertion that logic should not be in templates, but in this example you provided, I think it’s really just a matter of organizing and naming your functions better. Regardless of whether or not you “push” or “pull” the user information, that conditional statement is still going to have to be there. Another option using role-based ACL might be something like this:
<?php
if ($user->canView('topics')):
foreach ($topics as $topic): ?>
<a href="/topic/view/<?php echo $topic->id; ?>"><?php echo $topic->name; ?></a>
<?php endforeach;
endif;
?>
That way you never have to change that conditional logic (which is okay for presentation in limited amounts), but you can still alter the behavior of the role for that user at any time elsewhere in your application.
I’m not one for including logic in templates I think it’s messy and generally limits reusability of both the template and the logic running it. By separating it out you can use the same looping logic on multiple templates, or the same template with different looping logic.
To give a practical example, consider this inside a template:
It’s part of a forum, or similar. The HTML here is bound to the logic. It cannot be substuited/reused. If there was another forum which had different rules such as only admins can see (if ($user->isLoggedIn() && $user->isAdmin())) the whole thing needs to change.
Trivial example but the point is valid . I’d rather keep them separate to keep high reusability