Table of contents for Zend Framework
This example focuses on 3 aspects of the Zend Framework (v1.6):
the Zend_Layout mechanism, modules and helpers, including the ActionStack helper and a custom helper. (Please note that there is no Smarty involved in this example).
The main objective of this post is to demonstrate how components of ZF work together to produce a simple application, for this reason I will focus on the code that holds things together rather than going through line by line.
If you have any questions or things are not clear please leave a comment.
As in the previous posts in the series you can download the full working example here: zend_layout_example.zip (3.36 MB). (Note: the compressed file includes the ZF library hence about 3MB)
Please glance at the previous post on this series for hints on how to set up this example on your working server.
Lets start where all begins: bootstrap.php
22 23 24 25 26 | // Initialise Zend_Layout's MVC helpers Zend_Layout::startMvc(array('layoutPath' => SITE_ROOT.'/application/views/layouts', 'layout' => 'default')); $view = Zend_Layout::getMvcInstance()->getView(); $view->doctype('XHTML1_TRANSITIONAL'); |
In the above code the Zend_Layout is initialized to work together with the MVC architecture, also 2 config params are passed: the layoutPath points to the directory where our layouts are kept, and layout specifies the name of our default layout, so the full path of the default layout (on my pc) is: /var/www/zend/application/views/layouts/default.phtml
Next we see how modules are set up to work on the bootstrap.php file
32 33 34 35 | $vr = new Zend_Controller_Action_Helper_ViewRenderer(); $vr->setViewBasePathSpec(SITE_ROOT.'/application/views'); $vr->setViewScriptPathSpec(":module/:controller/:action.:suffix"); Zend_Controller_Action_HelperBroker::addHelper($vr); |
Note line 34 is quite important without that line modules will not work. What we are saying is: URL of the format www.example.com/admin/category/add should map to: /application/views/scripts/admin/category/add.phtml and this is the view script of the addAction() function of the CategoryController.php in the /application/modules/admin/ directory.
Next our helpers directory is set up:
37 38 | // add view helpers path Zend_Controller_Action_HelperBroker::addPath(SITE_ROOT.'/application/helpers', 'Helper'); |
The second parameter is important, we are saying that our helpers classes are prefixed with Helper so although the file is called MainMenu.php the actual class name is: Helper_MainMenu.
The default value for this parameter is Zend_Controller_Action_Helper which means that without the second parameter our helper will never be found as the class will be assumed to be called Zend_Controller_Action_Helper_MainMenu.
at the end of the bootstrap.php file the MVC architecture is put together:
44 45 46 47 48 49 50 | // Set the singleton instance of the front controller $front = Zend_Controller_Front::getInstance(); // setting controllers $front->setModuleControllerDirectoryName(''); $front->addModuleDirectory(SITE_ROOT.'/application/modules'); // dispatch now ! $front->dispatch(); |
Line 48 is the important one, it tells to our front controller where to find our modules directories, line 47 is saying that there is no subdirectory (inside our modules directory) to hold the Controllers files/classes.
In this examples there are 2 layouts default.phtml and admin.phtml and 2 modules default and admin
I will now focus on the default module and layout as the admin module and layout are just a simplified version of the default one.
here is the code for default.phtml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?= $this->doctype() ?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <?php $this->headMeta()->appendName("keywords", "all,keywords,go,here") ?> <?= $this->headMeta()->appendName("description", "Good for SEO, nice description here") ?> <?= $this->headTitle("Page Title")->setSeparator(' - ') ?> <?= $this->headScript() ?> <?= $this->headLink()->appendStylesheet("/css/style.css","screen") ?> <?= $this->headStyle() ?> </head> <body> <div id="wrapper"> <h1 id="head-block">Zend Framework Layout Example</h1> <div id="page"> <div id="sidenav"> <?= $this->layout()->sidenav ?> </div> <div id="content"> <?= $this->layout()->content ?> </div> </div><?php // <!-- close content --> ?> </div><?php // <!-- close wrapper --> ?> </body> </html> |
Interesting parts in the above code are the head section (from line 5 to 10) and line 17.
In the head section you find some of the very useful default helpers like Zend_View_Helper_HeadLink very useful to append css files at run time, or the Zend_View_Helper_HeadTitle where is possible to modify the title of the document at run time from within a controller action, here for more info.
Line 1 will output the doctype we set in our bootstrap.php file.
Line 17, in my opinion, is not explained well on the ZF manual and is the main reason for this example, in fact while output is automatically assigned to line 20, we need to programmatically assign content to line 17 and in the next 2 code blocks I will show you how.
First lets look at the main default controller application/modules/default/IndexController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php class IndexController extends CustomControllerAction { public function init() { parent::init(); $this->view->headTitle()->append('Home'); } public function indexAction() { $page = $this->_getParam('page'); if (empty($page)) { $this->view->msg = 'Landing Page'; } else { $this->view->msg = "Page {$page}"; } $this->_helper->actionStack('mainmenu', 'sidenav','default',array('active' => $page)); } } |
Interesting in the above code is line 7 and line 19.
On line 7 we append “Home” to the title already set on our default.phtml layout file.
Line 19 is great, the parameter mainmenu is an action, sidenav is the controller: SidenavController.php, default is the module and in the array we are just passing some parameters along.
The ActionStack (built-in action helper) allows us to trigger a series of actions (controllers/actions), each of this actions’ output can be assigned to a different section of our layout, in the next code block you will see how we assign the output of the mainmenuAction to our sidenav layout block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php class SidenavController extends CustomControllerAction { public function init() { parent::init(); $this->_helper->viewRenderer->setResponseSegment('sidenav'); } public function mainmenuAction() { $active_page = $this->_getParam('active'); if (empty($active_page)) { $this->view->home = 'active'; } $this->view->sidenav = $this->_helper->mainMenu($active_page); } } |
Finally line 7 is where we assigned the output generated by the mainmenuAction() to the line $this->layout()->sidenav in our default.phtml layout file.
Don’t forget that the mainmenuAction will still need an associated mainmenu.phtml file and is this parsed file that will actually take the right place in the layout file.
On line 16 I am assigning the output of the custom build action helper MainMenu.php to the sidenav variable that is going to be used in the mainmenu.phtml template script.
Below is the code for the custom action helper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php class Helper_MainMenu extends Zend_Controller_Action_Helper_Abstract { public function init() { parent::init(); } public function mainMenu($active_page) { // in real situation this probably is pulled from a database // or better an object is instantiate that loads data from a database $menu = array(); for ($i = 1; $i < 10; $i++) { $menu[] = array('link' => "/index/index/page/{$i}", 'title' => "Page {$i}", 'name' => "Link {$i}", 'class' => ($i == $active_page) ? 'active' : ''); } return $menu; } public function direct($active_page) { return $this->mainMenu($active_page); } } |
The last thing I like to show on this post is the index controller in the admin module:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php class Admin_IndexController extends CustomControllerAction { public function init() { parent::init(); $this->view->headTitle()->append('Admin'); $this->_helper->layout->setLayout('admin'); } public function indexAction() { $request = $this->getRequest(); $this->view->msg = $request->getModuleName(); } } |
The following 2 things should be noted on the above controller:
- the class name starts with
Admin_this catches out all the ZF beginners including me - line 8 is how we switch layout from the
default.phtmlto theadmin.phtml
Conclusion:
I hope you find this post useful, please download (zend_layout_example.zip (3.36 MB)) the working example of this post as many things will be clearer as you see the actual application working.
Thank you for taking the time to read up to here and please don’t hesitate to leave a comment.
Andrea
Leave a Comment or Trackback from your own site.
I am unable to use different action for a controller with Smarty templates.
For eg:-
application/modules folder contains admin/IndexController.php
admin/IndexController.php contains indexAction and signAction
if i am viewing admin/index/index.tpl containing a link “sign up”, on click of this i need action signAction of IndexController to be executed.
How do i do this? need your help.
hi Andreas,
I could find a solution for my query above. So, please dont bother. It seems like i get a solution only after i post it here. :-)
It would be helpful if you could tell me how i can do my form validation at client side using javascript with zend framework. If i am using smarty i dont think i need to use zend_form, so please guide me.
Thanks & Regards,
Rej
Hope I will see more of your posts soon
Thanks for this post !Just one question .What does it mean when you use {$1} in this code below :
$menu[] = array('link' => "/index/index/page/{$i}", 'title' => "Page {$i}", 'name' => "Link {$i}", 'class' => ($i == $active_page) ? 'active' : '');Hey goosy,
that is not the number 1 (one) but the letter i, so in the for loop the variable $i will be substituted by the page number.
Hi Andrea! Congratulations for the post! When reading your post, do not quite understand the code of the “index controller” module “admin”. Specifically the line: <php class Admin_IndexController extends CustomControllerAction What is “CustomControllerAction”? Where is this class? Where is it defined?
Hello Adriano, the CustomControllerAction class is in the include folder.
I usually make all my controllers inherit from a common controller where I keep code that is useful to all controllers that inherit it.
Hello Andrea, I understand the use of class “CustomControllerAction.” Really, it makes perfect sense! When I read your post, I did not download your Archiving “zend_layout_example.zip” because the frameword Zend in my machine already installed. Even so, I’ll download the file “zend_layout_example.zip” and then to have access to “include” directory where the class “CustomControllerAction” is defined. .