본문 바로가기
FrameWork/ZendFrameWork

Simple Zend_Layout Example

by 백룡화검 2008. 8. 13.

Zend_Layout is in the trunk now, so here's a super simple MVC example that shows it in action:

This example consists of three view files: the outer layout file, the index action view script and a right hand side bar. The remainder of this post describes the key files. If you just want to poke around with the code, then it's at the bottom, so page down now!

Setting up

This is the directory layout:

As you can see, it's the standard layout and we have one controller, Index, with one action (also index). For good measure, I've thrown in a view helper to collect the base URL to reference the CSS file and also render into a sidebar.

Let's look at the bootstrap file, index.php, first:

<?php

define('ROOT_DIR', dirname(dirname(__FILE__)));

// Setup path to the Zend Framework files
set_include_path('.'
. PATH_SEPARATOR . ROOT_DIR.'/lib/'
. PATH_SEPARATOR . get_include_path()
);

// Register the autoloader
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

// Initialise Zend_Layout's MVC helpers
Zend_Layout::startMvc(array('layoutPath' => ROOT_DIR.'/app/views/layouts'));

// Run!
$frontController = Zend_Controller_Front::getInstance();
$frontController->addControllerDirectory(ROOT_DIR.'/app/controllers');
$frontController->throwExceptions(true);
try {
    $frontController->dispatch();
} catch(Exception $e) {
    echo nl2br($e->__toString());
}


This is a standard bootstrap with the exception that we initialise the Zend_Layout using the startMvc() function. This takes an array of options, but the one thing you really need to pass in is the directory to find the layout files. I've chosen app/views/layouts as it makes sense in this case. If you are using modules, then maybe app/layouts would be better.

The controller

The index controller contains two functions: init() to render the sidebar to a named response section for use in the layout and then the indexAction() which just puts some text into the view:

<?php

class IndexController extends Zend_Controller_Action
{
    function init()
    {
        // Render sidebar for every action
        $response = $this->getResponse();
        $response->insert('sidebar', $this->view->render('sidebar.phtml')); 
    }

    function indexAction()
    {
        $this->view->pageTitle = "Zend Layout Example";

        $this->view->bodyTitle = '<h1>Hello World!</h1>';
        $this->view->bodyCopy = "<p>Lorem ipsum dolor etc.</p>";
    }
}

Two-step view

The view is now two-step. This means that we split our HTML between multiple files. The first step is to render the "inner" scripts, such as the sidebar and the action specific scripts. Then we render the "outer", layout script which embeds the rendered "inner" scripts.

The "inner" scripts

The action view script, index/index.phtml is trivial as it just needs to display the text relevant to the index action only:

<?php echo $this->bodyTitle ;?>
<?php echo $this->bodyCopy ;?>

(told you it was simple!)

The sidebar.phtml is similarly, just the HTML required for our sidebar:


<h2>Sidebar</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>

Again, nice and easy HTML, for this example at least!

The layout script

The layout script, layout.phtml, ties it all together. It contains the HTML that is common to all pages on our website and uses the special construct <?php echo $this->layout()->content ?> to render a named response segment. Note that the view renderer will render to "content" for the action controller's script.

The layout script looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8″ />
    <title><?php echo $this->escape($this->pageTitle); ?></title>
    <link rel="stylesheet" href="<?php echo $this->baseUrl(); ?>/main.css" type="text/css">
</head>
<body>
    <div id="content">
        <?php echo $this->layout()->content ?>
    </div>
    <div id="sidebar">
        <?php echo $this->layout()->sidebar; ?>
    </div>
</body>
</html>

For simplicity, we use the baseUrl view helper to retrieve the base URL from the request (via the Front Controller) and we render our two named response segments (content and sidebar) using the view helper layout() which is provide by Zend_Layout.

Conclusion

That's all there is to it. We could have use the partial() view helper to render the sidebar script and coming soon to a svn tree near you is other useful view helpers such as headScript() and headTitle() which will make the <head> section easier to manage.

Here's a zip file of this project: Zend_Layout_Example.zip(It includes a snapshot of the trunk of the Zend Framework which is why it's 3MB big.)

It works for me, at least.

64 Responses to “Simple Zend_Layout Example”

  1. 1 Fercho

    Excelent example !! One question, is it possible to change the extension of the views and the layouts from .phtml to .html ?

  2. 2 Mary

    lol… so easy to understand. Too bad the framework manual won't be so straightforward. Could you consider getting Zend to pay you to rewrite the entire manual?

  3. 3 Dennis

    So, we again have PHP code in the templates… and HTML in the PHP code.

  4. 4 Rob...

    Dennis,

    The HTML in the controller is because it's unimportant for this example. In a "real" application, you would retrieve the data from the model presumably.

    Zend_View is designed to allow PHP in the view templates, so I'm not sure what the problem there is. If you don't want PHP in the view, then you can use Smarty or XSLT or whatever you like really. For the purposes of showing how Zend_Layout works with Zend_View, PHP in the view templates is inevitable.

    Regards,

    Rob…

  5. 5 Greg

    Thanks for putting together an easy to understand example. One thing that would be nice would be to have an example where there is actually some logic in the sidebar - basically having the sidebar being the result of an action in another controller…

  6. 6 sinus

    hi akra,

    what if i wanted to use a different layout? how would i do that? can i change layouts between controllers/actions?

    in post #4, regarding the models; should i do all the SQL-queries in the model and call them from my actions? is this the best practice? or am i just confused :-/

  7. 7 daniel

    @dennis: Maybe you didn't understand the principle of separating html and php (don't ge me wrong, thats no offence!). The idea behind is that you do not use any business logic in your html code. but no problems using php for your output logic in the html files. therefore you can mix php and html code as long as it is just for displaying purposes.

    Regards,
    daniel

  8. 8 jfalvarez

    Hey, I made my own implementation of how to "inject" a rendered view into a template (thx to #zftalk @ freenode), I just make a plugin, then when you render a view into some controller action I get the body of this render and then I send it to the template as a variable, this is the code:

    TemplatePlugin.php

    http://paste2.org/p/10572

    So to disable the template rendering I just set a param into the controller action to the request object:

    
    $this->getRequest()->setParam( 'tplDisable', true );
    
    

    That's it :), is not the best thing but works simple :).

  9. 9 Philip G

    I want to reiterate what sinus asked. My own personal site, which uses ZFW 0.6 and my own extension of Zend_View, has 3 different layouts. The ability to select the layout based on the Controller is extremely important, at least for me.

    Is that option in Zend_Layout? I don't see that ability in your example.

  10. 10 Ken

    Rob,
    Thanks again for another great tutorial.

    Fercho,
    To change suffix the easiest and fastest way I found was to do it in bootstrap.
    Instead of:
    Zend_Layout::startMvc(array('layoutPath' => ROOT_DIR.'/app/views/layouts'));

    Do:
    $layout = new Zend_Layout($config->layout, true);
    $layout->getInflector()->setStaticRule('suffix', 'tpl.php');

    sinus,
    to change layouts in controller/action do:
    $this->_helper->layout->setLayout('new');

  11. 11 Ken

    This is a question about best practice.

    Layout can use the following to render data:
    //View Helper
    $this->content();
    //Placeholder
    $this->placeholder('content');
    //Response Segment
    $this->layout()->content;
    // Render
    $this->render('content.tpl.php');

    When to use each one???

  12. 12 c0d3r

    Thanks a lot for very useful example, Rob. Such examples is best learning practice for me!

  13. 13 Jason Qi

    Thanks Rob.

    I'm wondering if you are a teacher

  14. 14 Rob...

    Jason,

    Nope :) I'm the Technical Director of a small web development company in Gloucestershire.

    I don't have the patience to teach!

    Regards,

    Rob…

  15. 15 c0d3r

    Rob, well, I succesfully removed all header/footer includes from view-scripts - thanks Zend_Layouts and your example - and want more now… maybe dumb.

    I have several actions in controller and have several view-scripts (.phtml) - 1 script for 1 action as usual. Each view-script consist of one line of code, same for all scripts:
    PHP Code:
    txt;?>
    Can I replace several view-scripts with just one? If I can, which code does such miracle?

    Thanks a lot :)

  16. 16 Niko

    Rob,
    I worked it through like "getting started" and "Auth". But I'm still evaluating whether I get all functionallity like with HTML-Frames and JavaScript. I.e I can refresh only one frame :
    <JavaScript with parent.KOM.document){open();writeln(");</ For example on the left side all records, on the rigth side the details of the record I have just parked on. Can I do this with Zend_Layout or do I need JSON ?
    Inspite of this, example was good to understand like all your tutorials.
    Have a peaceful christmas time !
    Niko

  17. 17 Marcos D. Sánchez

    Hi Akrabat, I wanted to know the same than sinus,
    "what if i wanted to use a different layout? how would i do that? can i change layouts between controllers/actions?" Is it possible now? what are the advantages of using this instead of rendering parts of the view like the old behavior?

    Thanks in advance

  18. 18 Marcos D. Sánchez

    I found the answer to my question in Zend_Layout comments thread.

    Here's the link if somebody is interested:

    http://framework.zend.com/wiki/display/ZFPROP/Zend_Layout?focusedCommentId=40139#comment-40139
    (Answer by Matthew Weier O'Phinney)

  19. 19 Vincent

    As for all those wishing to know how to change the used layout, the manual says you can use $this->_helper->layout->setLayout('foobaz'); in your action controller.

    Anyway, I wanted to use Zend_Layout to render the header, sidebard etc., but for now I'm sticking with using placeholders since I can use setPrefix(), setIndent() and setPostfix() with those…

  20. 20 Doc Olson

    @Dennis

    I don't even see a point. Smarty: {$my_variable}… Zend: (or shorter: ). What's the big picture? I agree there should not be any code inside a view/template but what you will always need is a placeholder/variable for your content to be displayed (at least i do).

    @Rob: Great tutorial, thx

  21. 21 Doc Olson

    doh!
    my php examples got cut out…

    1:
    2:

  22. 22 Doc Olson

    …i could cry. Now that i want to be a smartass i fail miserably

  23. 23 Doc Olson

    Sorry for the spam. Now i am the dumbass and have a question. Do i get the idea right, that i need to include the sidebar in every controller i use?
    ($this->getResponse()->insert('sidebar', $this->view->render('sidebar.phtml'));)
    That seems to be redundant to me or is there some idea behind it? I'd love to see some default behaviour which could be overridden on demand. My idea to that would be to extend the Zend_Controller_Action class and inherit all my controllers from that one. In controllers where the sidebar is not needed i would just override the init() function.
    Would that be a good practice?

  24. 24 Rob...

    Doc Olson,

    For this sort of case, I would use an action helper to add sidebar functionality.

    Regards,

    Rob…

  25. 25 ArasName

    Can I disable the layout from an action. example: I have indexAction uses the tayout but I have another action ajaxAddAction this will only return a value.
    I tried this:
    $this->_helper->layout->disableLayout();
    $this->view->pageTitle = "Example";
    $this->view->bodyTitle = 'Add';
    but it rendered the side bar also.

  26. 26 Sr

    Hello.

    Help me please to rewrite this example. I don't want this text in every contrloler:

    function init()
    {
    $response = $this->getResponse();
    $response->insert('navigation', $this->view->render('navigation.phtml'));
    }

  27. 27 Andreas Kompanez

    @Sr
    Just like Rob already said, you have to write your own Action_Helper for this. Here an example:

    
    // The Action Helper Class
    require_once 'Zend/Controller/Action/Helper/Abstract.php';
    
    class My_Controller_Action_Helper_SideBar extends Zend_Controller_Action_Helper_Abstract {
      public function postDispatch() {
        $this->getResponse()
          ->insert('sidebar', $this->getActionController()->view->render('sidebar.phtml'));
      }
    }
    
    

    I've placed this class in lib/my/controller/action/helper/SideBar.php.

    Don't forget to add the new helper in your bootstrap:
    Zend_Controller_Action_HelperBroker::addHelper(new My_Controller_Action_Helper_SideBar);

  28. 28 Rob...

    Good example Andreas!

    I've taken the liberty to format your code nicely.

    Regards,

    Rob…

  29. 29 Mario

    Hi, there is a problem with your RSS feed. The feed is not valid and could not parsed by some feed readers.

    http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fakrabat.com%2Ffeed%2F#l116

  30. 30 Mario

    The problem with the RSS feed results from an invalid character in the paragraph "_This is the directory layout:". See http://validator.w3.org/

    Hope you can fix this.

  31. 31 Rob...

    Hi,

    Should be fixed now.

    Thanks!

    Regards,

    Rob…

  32. 32 weblizzer

    Hi Rob,

    I'm starting to learn now the zend framework. Using the 1.0.3 Zend Framework, im trying separates every module separate in every Controller and i want to include those sub modules into the Index.

    Let say i have the NewsController.php and UserController.php

    i try to use the Layout based on your tutorials but i get the error in displaying those news List.

    Hope you can help me with it. Thanks

  33. 33 moises

    Si utilizo smarty, supongo que en vez de poner layout()->content ?> debo poner {$this->layout()->content}. No me funciona esto.

  34. 34 flo

    I have a lil' problem:

    Basically i have 1 layout for my site that i'm using in all pages, except for the AJAX requests, where i need to return only a JSON object.
    I'm also using a helper for a login box, and that's the problem. Even if i use an empty layout, it still tries to render the loginbox, so my response to browser is messed up.

    Can any1 give me a hint on how to avoid this without having to remove the helper ?

  35. 35 flo

    i'm sorry for the previous post. i spent almost 3 hours trying to work that problem, then after i made the post, i saw the cause was comming from a different place.
    my bad totally, so u can remove this 2 posts for keeping it clear.

    thanks and sorry for the mess.

  36. 36 Dennis

    Same question as Greg:
    How to render a special sidebar with dynamic elements (depends of which user is logged in, etc. etc.) not just a static one?
    Thanks for the nice intro into zend_layout.

    Regards,
    dennis

  37. 37 Rob...

    Dennis,

    The action() view helper is one way. Using an action stack with response sections is another.

    Regards,

    Rob…

  38. 38 Nils

    I've the same problem like Dennis. I want to include a template
    whice contained dynamic gernates content. So I must call the controller of the template but I don't know how I can do this.

    Can give somebody an example using plugins oder action helper, please.

    Regrads,

    Nils

  39. 39 Nils

    Hey Folks,

    I've got it :) … so you can include modules in your Layout.

    Register in Bootstrap

    $front->registerPlugin(new Mein_Controller_Plugin_Broker('modulname','controller','action','PLUGIN_HEADER'));
    

    After that you can use

    <? echo $this->placeholder('PLUGIN_HEADER')->CONTENT ?>
    

    in all of your Templates

     
    <?
    require_once 'Zend/Controller/Plugin/Abstract.php';
    class Mein_Controller_Plugin_Broker extends Zend_Controller_Plugin_Abstract
    {
     //Global Layout Instanz
     private $_layout;
     //Global Layout Instanz
     private $_view;
     
     private $_modulname;
     private $_controller;
     private $_action;
     private $_layout_namespace;
     
     
     public function  __construct($modul,$controller,$action,$layout_namespace)
     {
      $this->_layout = Zend_Layout::getMvcInstance();
      $this->_view = $this->_layout->getView();
      
      $this->_modulname    = $modul;
      $this->_controller    = $controller;
      $this->_action     = $action;
      $this->_layout_namespace  = $layout_namespace;
     }
     function preDispatch(Zend_Controller_Request_Abstract $request) 
     {
      $view = $this->_view;
      $this->_view->placeholder($this->_layout_namespace)->CONTENT = $view->action($this->_controller,$this->_action,$this->_modulname);
     }
     
    }
    
    

    Regards, nice blog

    Nils

  40. 40 sinus

    I got an error in the "baseUrl" part. Since I could not find the code for the BaseUrl.php above, I create something like this:

    <?php
    class My_View_Helper_BaseUrl
    {
        public function baseUrl()
        {
            return Zend_Controller_Front::getInstance()->getBaseUrl();
        }
    }
    
    
  41. 41 Rob...

    sinus,

    That's pretty much what my baseUrl view helper looks like.

    Regards,

    Rob…

  42. 42 bobbydee

    Hi, in this example ,sidebar is static, if I would like to put some dynamic content where should i set the variables?

  43. 43 Justin

    What is the line '$view->addHelperPath('path/to/incubator/library/Zend/View/Helper/');' for? what is the incubator?

  44. 44 Rob...

    Justin,

    That's unnecessary for the latest RCs of v1.5 of Zend Framework.

    Regards,

    Rob…

  45. 45 Justin

    What was it for?

  46. 46 Rob...

    Hi Justin,

    As Zend_Layout was being developed, it was first coded in a separate area called the incubator. This area is to allow testing of components before they are promoted to the core library.

    Regards,

    Rob…

  47. 47 Jack

    "lol… so easy to understand. Too bad the framework manual won't be so straightforward. Could you consider getting Zend to pay you to rewrite the entire manual?"

    That says it all rob. I know I would donate to have you write the manual!

    Compared to Codeigniter (which is amazing, but limiting) Zend's documentation is really hard. Sure, it's great for Zend programmers - but when I need to learn some new functionality it's a pain!

  48. 48 wenbert

    Jack, I agree about the Zend Framework manual… hehe… I am just going to wait for Akra's Book… hopefully everything will be there :P and easy t o understand :)

  49. 49 Rob...

    Jack,

    Have you visited http://www.zendframeworkinaction.com?

    Regards,

    Rob…

  50. 50 Jack

    Yeah your book! I do plan on buying it. Will it be based on 1.5?

  51. 51 Rob...

    Jack,

    Yes.

    Regards,

    Rob…

  52. 52 James

    Here is another way to add dynamic content to the side bar.

    $response->insert('sidebar', $this->view->action('action', 'controller'));

  53. 53 Jack

    I set this up in my existing site structure and it appears to work great.

    I have images in "public->images". "layout.phtml" file has image tags like "".

    I go to "mysite.com/index.php" And it shows up fine, images and all.

    I go to "mysite.com/index.php/index" And it shows only the markup with no images.

    I'm really frustrated and cannot find the problem. Anyone have any ideas?

    Thanks

  54. 54 Rob...

    Jack,

    At a guess, the BaseUrl is changing and so it can't find the CSS/images.

    Regards,

    Rob…

  55. 55 Jack

    Thanks for the reply.

    That does appear to be the problem.

    Is there a way to tell zend to always check that directory? It will be such a pain to have to prepend something to every image source… Sorry to be such a pain, I'm really trying to figure this out..

  56. 56 Jack

    p.s - i'm buying your book I promise :)

  57. 57 Rob...

    Jack,

    Use mod_rewrite to remove index.php from your urls, or set the baseurl directly in your bootstrap.

    You should then write a view helper called baseUrl() and use it in front of all calls to the css/js/img files in your html views.

    Regards,

    Rob…

  58. 58 Jack

    Thanks, I did write that baseUrl() helper. Then I realized that adding a "/" in front of the urls would work too ("/images/image.jpg").

    This works as long as public is always in the complete web root. Which it will be for me - so ill stick with that.

    Sorry for bothering you..

  59. 59 Rob...

    Jack,

    Yeah that works too! You're not bothering me as it's all useful information for others who read this page :)

    Regards,

    Rob..

  60. 60 Giacomo

    Hi! Wonderfull tutorial!

    Just a question: you have set a directory structure where layouts/ is under app/views.

    What if I've differents modules?

    I notice you called startMvc() with an absolute path.

    Could it be relative to the acting controller / module?

    What to gain this?
    Should I use a custom Inflector? But how to know what module the layout is rendering?

    Thanks a lot!

    Giacomo

  61. 61 Rob...

    Giacomo,

    I'm not sure. I suspect not. What I would do is write a Front Controller plugin to set the layout path correctly in the dispatchLoopStartup() function.

    Regards,

    Rob…

  62. 62 Stijn Leenknegt

    Thanks for the information ;-)

  63. 63 Richard Jansen

    Hi Rob

    Thanks for this short tutorial. One question: What is the purpose of the good old view scripts right now? Why do I still have to render a view script? I want to use Zend_Layout and plugin some HTML blocks.

    Regards,
    Richard

  64. 64 David Roelandt

    Hello Rob

    Thanks for this good tutorial!

    Regards,
    David Roelandt