Zend Framework - Reusing view header information across Controller - php

In Zend Framework, I have a common use case where I need to propagate the same information in the top section of a view across a particular controller.
For example, if I have a "Book" controller, I want to display the summary book information at the top of the page, and have a tabbed interface below the book to display comments, detailed info, etc. Each tab is an action in the books controller. What is the recommended way to propagate the summary information across the views in the controller such that:
I am not continually fetching the summary book information in each action.
I am not repeating information in my views.
I though of using a Zend View Helper, a placeholder, or the action helper ($this->action...) from within the view.
Any suggestions?

Sounds like you'd want to fetch the book information in an init() method on the controller:
class MyController extends Zend_Controller_Action
{
protected $_book;
public function init()
{
// get the book data/model, etc
$book = $this->_getBook();
// if necessary, store the book for use in the actions
$this->_book = $book;
// store the book in the view
$this->view->book = $book;
}
}
If an action only renders the book info, then you can probably get away with empty action methods, letting the view scripts do their thing.
The only downside to this is that it gets the book data on every action. So if there are some actions that do not require the book data, then you'd be eating the overhead of fetching it.

I would load the tabs' contents dynamically (should be easy to integrate with your current solution via the action helper AjaxContent. Just load the action's response into your tab container.
If you decide to stick with a non-ajax solution, the code is forced to be repetitive since you need the same piece information on more than one page. A partial should be better suited for your needs since a view helper performs some kind of logic (or proxies for logic) while you only need it for presentation & markup.
The information fetched should not be that hard on your system, assuming you are using some smart cache method (perhaps one cache entry for each section/tab).

Related

Controllers and pages without "actions"? MVC

As I understand it the "MVC" came before the web and is often used in Desktop software for example.
If I understand correctly, the Controller runs at the time that the user will click a button and this will trigger an action.
But if we talk about web pages, the scenario is a little different, assuming the user clicks a link then it triggers an action.
But then, came me the doubt, is the home page part of a Controller?
What I mean is, the homepage is not usually performed by a user action within the website is just the home, but noticed that many PHP frameworks use a Controller for the home, is that correct?
Another doubt is in my "home" I have several items, for example:
banners
featured posts
recent posts
Each of these items would have a different Model, can I call more than one Model and a View into the Controller?
Would these be the correct steps? Or most of php frameworks are not strict?
You are completely right and I understand the confusion.
In a pure MVC approach, the Controller only listens to user actions and updates the Model accordingly. The Model then notifies the View (through the Observer design pattern) and the View updates itself, accessing the data it needs from the Model.
This is how it was done before the web, in desktop application, where the Model and the View are running concurrently, and where the Model can notify the View. The Controller doesn't set up the View.
In this pure MVC model, the example you mentioned about the homepage doesn't need a Controller indeed. The View would just render itself, accessing the data it needs through the Model. Controllers are very thin and only listen to user actions and update the Model. That's all they do.
In the web, this model is not possible, and thus there are alternative approaches. The Model can't notify the View as in the pure model, and thus what popular frameworks require you to do, is to set up the View in your Controller. That's why for your example of the homepage you need a Controller, as you will set up your view there with all the data it requires.
However, there is another approach I have been personally writing about, where Controllers don't set up the View which allow you to keep tiny Controllers. You can read about it here: A better OOP approach to building MVC applications
Thus I believe that the homepage shouldn't need a controller action at all. The View should just render itself and access the data it needs to render. The Controller's role is to handle user actions and update the model accordingly, as you said. If it does more than that, it probably violates SRP. The Controller shouldn't set up the View, instead, the View should get its own data from the Model.

Mvc and php: passing variables from controller to the view

I'm trying to implement mvc design pattern to my existing dating-web-app project. I believe I understood the concepts and created a login model and controller without any problems. Basically, I have a base controller which initiates a view object on construct. Than I use that object to send information to the view from within the controllers as method parameters. However, I couldn't decide how to send variables to the top menu view. Since this menu displays dynamic information (request count, notification count,etc) and included in every page of the application, only two options come to my mind:
Send information to the view from every controller, which seemed like reuse of code.
Put a seperate action in the base controller and make it called automatically when other controllers extend base controller.
Which one should I choose? Or, is there a better way to do this?

MVC: How to run some custom dependant actions before/after main action

The following code is in my FrontController. The run method should call a controller action which belongs to a given url. For example http://localhost/admin/index should point to AdminController and indexAction.
This works already, but what's the best way to call additional controller actions, for example a action for building a navigation of my site or a aside box (is not in the main section of the site) with some information. A navigation is needed at every request, so this would be no problem to implement, but when I have to call some actions which depends on the main action, how to structure this?
My first approach was to call other controller actions in two methods like runBeforeMainController or runAfterMainController. A global config holds the info for main controllers which sub controller (actions) needs to be called before or after the main controllers call.
My second approach was to think about a hook / event system. But I didn't come to good theoretical solutions. Do you have some tips or suggestions for this approach?
// in FrontController
public function run() {
$strController = static::getControllerNameFromUrl();
$strAction = static::getActionNameFromUrl();
// call actions before main controller
$this->template->main = $this->callMainControllerAction($strController, $strAction);
// call actions after main controller
}
I think HMVC is what you're looking for. The H stands for hierarchical. Basically you are using multiple mvc-constructs. Your site gets more modular and one request may result in different actions.
Afaik there are already some PHP frameworks using this approach.

Show/Hide elements in Zend views based on User Role?

I'm new to Zend and PHP and I'm getting ready to start work on a portal type application that will house multiple internal applications. I've already setup Zend_Auth and can now login via Active Directory.
We've been discussing using Zend_Acl to setup resources, one for each application within the portal. On the surface Zend_Acl seems like it would handle what we need for authorization and hierarchical access to resources.
After some research I've found that it's common to combine Zend_Acl with Zend_Navigation but there are sometimes issues with this.
What has been requested is that apart from* utilizing a front controller plugin to check resource access/privileges on each request, that we instead control the elements shown in the view (HTML) to the user. For example if user 'Bob' doesn't have access to the blog application, we don't want Bob to see that on his nav menu.
To me, introducing all this logic and if checks in the views is wrong; I think they should remain as stupid as possible. Is there a better way of handling this? Conditionally showing or hiding elements based on user role in your view code feels wrong to me.
If you want to remove the logic from the view, I would suggest using view helpers. That way you can abstract the ACL logic away from the view.
In your controler you would need to pass the ACL object to the view for use:-
$this->view->acl = $acl;//instance of Zend_Acl
Then you have a view helper for rendering some element:-
class Zend_View_Helper_SomeElement extends Zend_View_Helper_Abstract
{
public function someElement()
{
$html = '';
if($this->view->acl->isAllowed('guest', null, 'view'){
$html .= "<div>Top secret content</div>\n";
}
return $html;
}
}
Then your view is as simple as:-
echo $this->someElement();
That keeps your view simple and easy to read, while your logic is nicely hidden. Not ideal, but in your situation, I think this is the route I would take.
Your view helper can, of course, be made a bit more general purpose than this by passing in parameters.

Data from multiple models in one view (web page)

I'm new to the MVC pattern but have been trying to grasp it, for example by reading the documentation for the CakePHP framework that I want to try out. However, now I have stumbled upon a scenario that I'm not really sure how to handle.
The web site I'm working on consists of nine fixed pages, that is, there will never exist any other page than those. Each page contains something specific, like the Guest book page holds guest book notes. However, in addition, every page holds a small news box and a short fact box that an admin should be able to edit. From my point of view, those should be considered as models, e.g. NewsPost and ShortFact with belonging controls NewsPostController and ShortFactController. Notice that they are completely unrelated to each other.
Now, my question is, how do I create a single view (web page) containing the guest book notes as well as the news post box and the short fact? Do I:
Set up a unique controller GuestBookController (with an index() action) for the guest book, so that visiting www.domain.com/guest_book lets the index action fetch the latest news post and a random short fact?
Put static pages in /pages/ and in let the PagesController do the fetching?
< Please fill in the proper way here. >
Thanks in advance!
It sounds like you need to look into elements, or else you may be able to embed this into the layout - but its neater to use an element if you ask me, keep the things separate.
http://book.cakephp.org/2.0/en/views.html#elements
These allow you to have create small views that you are able to embed into other views.
You may also need to put some logic into the AppController (remember all other controllers extend the app controller) to load the data required for these views. The beforeRender function should be useful for this - its one of the hook functions cakephp provides, so if you define it on a controller, its always called after the action is finished before the view is rendered.
Something like this in your AppController should help:
function beforeRender() {
$this->dostuff();
}
function doStuff() {
// do what you need to do here - eg: load some data.
$shortfacts = $this->ShortFact->findAll();
$news = $this->NewsPost->findAll();
// news and shortfacts will be available within the $shortfacts and $news variables in the view.
$this->set('shortfacts', $shortfacts);
$this->set('news', $news);
}
If there are models you need in the app controller for use within this doStuff method, then you need to define them within uses at the top of the AppController
class AppController {
var $uses = array('NewsPost', 'ShortFact');
}

Categories