Zend Framework View Notes
I’ve been working a lot lately with the Zend Framework for a project at work, and in a recent upgrade from 0.8.0 Preview to 0.9.1 Beta, I made a few discoveries that I’d like to share, especially since the manual for the Zend Framework is sorely out of date, and many of the examples are either deprecated or no longer work.
Most notably, I’ve started using the “new way” of using views, which is still undocumented in the manual. Rather than create a new Zend_View object, tell it where my views are, and echo a call to its render() method, I’m letting the controller’s render() method do it all for me. To do this, you need to follow a specific directory structure. For example, if your application is set up like this:
application/ controllers/ models/ views/ library/ Zend/ Zend.php webroot/ index.php
Then, to make use of the controller’s default render() behavior, add a scripts/ directory under the application/views/ directory. Then, inside the scripts/ directory, create a directory for every controller. The directory must have an all-lowercase version of the controller name without the word “Controller.” So, if you have a CustomerController class, then the directory would simply be customer/.
Inside this directory, create a view file for every action you will render following the same naming conventions. Thus, if you have an indexAction() and an addressAction() you would have the files index.phtml and address.phtml in application/views/scripts/customer/. The .phtml extension is the default for views in the Zend Framework; see Rob Allen’s discussion on the use of the .phtml extension.
Finally, to use the views, you’ll need to initialize them in your controller. Do this by creating an init() method and calling $this->initView() from within it. This sets up the default view for your controller. From within any action, you may now set properties on your view as normal with $this->view->propertyName and you can render the view with $this->render() (there is no longer a need to echo).
So, to recap, with a directory structure like this…
application/
controllers/
CustomerController.php
models/
views/
scripts/
customer/
index.phtml
address.phtml
library/
Zend/
Zend.php
webroot/
index.php
…and a controller like this…
class CustomerController extends Zend_Controller_Action
{
public function init()
{
$this->initView();
}
public function indexAction()
{
$this->render();
}
public function addressAction()
{
$this->render();
}
}
…you can much more easily work with views in the Zend Framework.
Note that Zend_Controller_Action::initView() determines the location of the views directory on its own, so you don’t have to tell the application where your views are stored. It determines the location based on the controller directory specified for the current module in use. In this case, we’re using the “default” module, and I’ve specified the controllers directory in my front controller as /path/to/application/controllers/. The Zend Framework also supports the use of different modules using different controller directories, but I’ll talk more about that later as I share more of my Zend Framework discoveries.
18 Comments
Funny, Solar has been working this way for months now. I suppose if you want to see the future of Zend Framework, watch Solar. ;-)
http://solarphp.com/
Uh, nice. Thank you!
Hello Ben,
I would like to note that the *wikifized* manual for the Zend Framework, is much more up to date. A recently added feature is that pages now include direct links to JIRA issues at the bottom of the page.
There are plans for improving the visibility of the documentation (wiki), but at the moment, everybody's focussing on the 1.0 release.
Thanks Ben, this article has given me the appetite to finally try ZF for myself.
I have only ever used CodeIgniter up to now - this looks an awful lot cleaner.
State of documentation has been a deciding factor up to now, but if you keep up producing nice intros like this, it will ease a lot more ppl into using ZF.
Thanks
Andries:
While the wiki manual may be more up to date, the Zend_View section still does not explain what I described in this post. Instead, it continues to illustrate the use of views by instantiating a new Zend_View object, specifying the location of the views directory for it, and echoing a call to
$view->render().Does anyone else find the amount of setup rigid and tedious?
I've always liked the Velocity-like nature of the Zend View (and others), but it seems that way too much code was tacked on to reduce the amount of work/discipline on developer's part.
This seems like an awefully strict structure to impose in the name of organization...one that would quickly breakdown if a need arose outside of what View was designed for.
Hi Ben,
you don't have to call $this->initView(); explicitly in your init method as the Zend_Controller_Action::render method does this automatically for you.
This way you can skip the instantiation in cases where you redirect or output via other mechanisms :-)
Happy hacking,
Sascha
Alex:
Please note that I said this is the "default" behavior. You are allowed to customize and extend things as much as you want, so you are not locked into a rigid way of doing things. You can also specify a different location for your views or even a different named view than that of your action. It's very flexible; what I've discussed in this post is not the only way to do things.
If you want to see rigid, try using a framework like Cake or Symfony (or Rails). I like Zend's efforts because they are so much more flexible than what else is out there.
Great, Thank you for your great info on Zend. Will be back soon, as i am new to Zend.
Many thanks once again.
I'm all for auto-rendering. Great idea. If only it had been implemented as gracefully as in RubyOnRails...
Having to call initView() is clumsy. Having ->render() echo instead of return is also asking for trouble (it means you have to output-buffer in order to nest templates).
.phtml isn't always enabled, so you're cutting out people on some shared-hosts. Stick to standards.
I also dislike having a pointless 'scripts' directory. It's just one more thing I have to drill-down into[sigh]. Furthermore, it's anti-semantic! The name 'scripts' directly contradicts one of the main reasons for using the .phtml extension -- to make it easy to distinguish between 'scripts' and 'views'. Putting non-script views in a scripts directory is nonsensical.
Of course, these are all critiques of the View object, and not your writing, Ben. Very handy & well-written tutorial.
Good article, thanks.
Hopefully this will get covered in the manual soon. It seems to be most pertinent to the Model part of MVC, which doesn't have its own manual section. Maybe that's why it's not there yet.
Just to clarify, $this->initView() needs to be called before you can assign data to the view.
If you hadn't initialized the view, the following action would throw a fatal error (for attempting to call a method on a non-object $this->view):
function indexAction()
{
$this->view->assign ( 'a' , 'b' );
$this->render();
}
I would favour creating an abstract class which extends Zend_Controller_Action, and defining the init() method in this class (as Ben has done in the concrete controller): all your controllers can then just inherit your abstract class, and you won't need to worry about initView() any more.
I wonder if they'll alter Zend_Controller_Action to do this by default for us ...
Cheers, Amir
Actually, I just re-read Sacha's post, and I think he's right - some actions do not need the view at all.
It's probably best just to use $this->initView() as & when you need to.
e.g.
...
function indexAction()
{
$this->initView();
$this->view->assign ( 'a' , 'b' );
$this->render();
}
...
initView() and render() are no longer required by default. You can have an empty conroller class and it will still work with the view file by default.
Fatal error: Uncaught exception 'Zend_Loader_PluginLoader_Exception' with message 'Plugin by name GetViewSuffix was not found in the registry.' in D:\Amit\phpprojects\flagship\library\Zend\Loader\PluginLoader.php:370 Stack trace: #0 D:\Amit\phpprojects\flagship\library\Zend\View\Abstract.php(1114): Zend_Loader_PluginLoader->load('GetViewSuffix') #1 D:\Amit\phpprojects\flagship\library\Zend\View\Abstract.php(545): Zend_View_Abstract->_getPlugin('helper', 'getViewSuffix') #2 D:\Amit\phpprojects\flagship\library\Zend\View\Abstract.php(312): Zend_View_Abstract->getHelper('getViewSuffix') #3 [internal function]: Zend_View_Abstract->__call('getViewSuffix', Array) #4 D:\Amit\phpprojects\flagship\library\GTL\Controller\Action.php(43): Zend_View->getViewSuffix() #5 D:\Amit\phpprojects\flagship\library\Zend\Controller\Action.php(118): GTL_Controller_Action->init() #6 D:\Amit\phpprojects\flagship\library\Zend\Controller\Dispatcher\Standard.php(261): Zend_Controller_Action->__construct(Object(Zend_Controller_Request_Http), Object(Zen in D:\Amit\phpprojects\flagship\library\Zend\Loader\PluginLoader.php on line 370
I'm getting above error. Could you please explain me where is the problem?
Would be appreciated your help.
Personally I feel Zends default View is, lack of a better term, crap. I have incorporated Smarty into my ZF App and couldn't be more pleased!
This is in response to michaels comment...
"initView() and render() are no longer required by default. You can have an empty conroller class and it will still work with the view file by default."
It's true that once an action function meets the end if no render() is called it will automatically render the template..however, it's still GOOD programming practice to include it. Personally I will always use it just to remind myself (and anyone else viewing the code) what to expect next.
i have similar issue:
i have a controller "abc" and action "xyz"
In action "xyz" , i have the following code:
$view = new Zend_View();
$script_path = APPLICATION_PATH.'/views/scripts/';
$view->setScriptPath($script_path);
$view->render('xyz.phtml');
when i call http://demoapp/abc/xyz , it is giving an application error. If i remove the $view->render() it works. If i just use $view->render() alone with out the argument, it is working.
If the action not having any of the above lines like below, it is working fine.
public function xyzAction() {
}
How Do i make manual rendering in controller's action, instead of using default view of the Zend Controller?