Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: MVC View Integration Component Proposal

Proposed Component Name MVC View Integration
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/MVC View Integration
Proposers Matthew Weier O'Phinney
Revision 1.0 - 7 March 2007: Original proposal creation (wiki revision: 5)

Table of Contents

1. Overview

The MVC components consist of the Zend_Controller and Zend_View families (and, nominally, Zend_Db_Table). However, there is no current integration of these components; a simple patch would enable this.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • View instantation will be lazy-loaded and optional
  • View instantation will be overrideable to allow for custom view objects or loading view objects from alternate sources (e.g. registry)
  • View script suffixes will be configurable via a controller property
  • View rendering will not require an argument, and will use the controller and action to determine the view script by default
  • View rendering will accept an optional view script name

4. Dependencies on Other Framework Components

  • Zend_Exception
  • Zend_View_Interface
  • Zend_Controller_Action

5. Theory of Operation

Two new methods will be added to Zend_Controller_Action, initView() and render(), and two new properties, $view and $viewSuffix. When called the first time, render() will check to see if $view has been populated, and if not, call initView() to initialize the property.

render() will by default render the script <controller>/<action>.$viewSuffix in the view object's script path. If an argument is passed in, it will render $action.$viewSuffix. All rendered views are appended to the response object.

The default implementation of initView() will instantiate a Zend_View object and set the script, filter, and helper paths based on the following directory structure:

Thus, the script path will be set to ../views/scripts, helpers to ../views/helpers, etc, relative to the controller class file.

6. Milestones / Tasks

  • Milestone 1: initial proposal accepted
  • Milestone 2: working and tested code checked into core
  • Milestone 3: documentation exists

7. Class Index

  • Zend_Controller_Action

8. Use Cases

UC-01

This example illustrates the default usage.

UC-02

The following example illustrates two concepts:

  • Initializing the view to allow assigning data to it
  • Rendering an alternate view script (i.e., something other than controller/action.phtml)
UC-03

This example illustrates using a different suffix

UC-04

This example illustrates overriding initView() and render().

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 07, 2007

    <p>Hi Matthew,</p>

    <p>have you considered the use case where you have your views split up into a global section that remains constant for the whole application (e.g. a common page header), a controller-specific view (e.g. a navigation sidebar) and, finally, an action view that is embedded into the other two view outputs?</p>

    <p>I have described in a past blog post what I mean - the implementation presented there is far from perfect, and it was based on a much older version of the framework (about 0.6 or even before, I think), but I think you'll get the idea.</p>

    <p>Link:
    <a class="external-link" href="http://blog.wolff-hamburg.de/archives/5-Extending-Zend_Controller_Action.html">http://blog.wolff-hamburg.de/archives/5-Extending-Zend_Controller_Action.html</a></p>

    <p>Any chance we might see support for something like this? Or how would you propose to tackle that problem?</p>

    <p>CU<br />
    Markus</p>

    1. Mar 09, 2007

      <p>Forgot to 'watch' the page!</p>

      <p>The cool thing about Zend_View is that you can add multiple script paths. Now, one potential issue with render() using the controller to determine the subdirectory is the difficulty of using a 'sitewide' or 'application-wide' area. This could easily be overcome by allowing a second flag to render() that would disable the controller subdirectory:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      public function render($action = null, $noControllerDir = false)
      {
      // .. same...
      if (!$noControllerDir)

      Unknown macro: { $script = $request->getControllerName() . DIRECTORY_SEPARATOR . $script; }

      // same...
      }
      ]]></ac:plain-text-body></ac:macro>

  2. Mar 07, 2007

    <p>Only two small quibbles:-</p>

    <ul class="alternate">
    <li>Is '.phtml' a good default? I would have thought '.php' would be the best for Zend_Views in 90% of cases? '.tpl' would be good for Smarty... Perhaps instead the suffix is best determined by the Zend_View so if you provided a Smarty view to as $this->view then you don't need to override the property in the controller? E.g.
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $script = $controller . DIRECTORY_SEPARATOR . $action . '.' . $this->view->getSuffix();
    ]]></ac:plain-text-body></ac:macro></li>
    <li>Perhaps render could have a second boolean flag which determines if the response adds or sets the view output. In some cases you may wish to completely clear all existing content from the response.</li>
    </ul>

    <p>Otherwise I can't see any major problems and it would indeed be convenient.</p>

    1. Mar 09, 2007

      <p>Suffixes are a developer preference, really; you don't <strong>need</strong> to use .tpl with Smarty, nor .php with Zend_View. I actually chose .phtml as (a) most apache configurations specify it as an alternate extension associated with the PHP engine, (b) most IDEs and text editors will identify .phtml as PHP + HTML for syntax highlighting, and (c) it visually separates template scripts from other PHP files in the directory tree.</p>

      <p>I've already mentioned a second flag for determining if the script should be searched for in the controller subdirectory.. I'll consider this, as it makes sense as well, but I don't want a ton of options to pass to render(). It should be quick and dirty in most cases.</p>

  3. Mar 08, 2007

    <p>This is a good idea. I extend Zend_Controller_Abstract for every project to do something very similar.</p>

    <p>I want to echo Markus though and ask about how the common elements on all templates across the application would be handled. </p>

    <p>From what I've seen there are two common approaches:<br />
    1. include header.php/footer.php to the top/bottom of every single action view template.<br />
    2. have a master.php that includes the action view template.</p>

    <p>Some sort of support for handling the commonalities would make this proposal more useful IMO.</p>

    <p>Regards,</p>

    <p>Rob...</p>

  4. Mar 08, 2007

    <p>Hi all,</p>

    <p>maybe it's a stupid question or at least out of topic <ac:emoticon ac:name="smile" /> but :</p>

    <p>does it mean that one action = one template ?</p>

    <p>What's happened if one action should trigger two separate templates rendering ? Should I create another action and then use the forward method ?</p>

    <p>I mean, let's consider I'm in the newItemAction, so I create the item in the database then I want to display it. The action calls the editItem template, but meanwhile I need to update the pager because the total items has changed. Should I for example create a displayPagerAction in my controller so that I could forward it ? Then I could render the two distinct part of my page.</p>

    <p>I'm almost sure I didn't understand something here...Could you enlighten me ?</p>

    <p>regards,</p>

    <p>fred</p>

    1. Mar 09, 2007

      <p>It <strong>suggests</strong> one action == one template, but you could call render() any number of times in the action method. The method's first argument is optional, and by default it will use the current controller and action to determine the view script to utilize. However, if you pass an argument in, it will use that instead:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      public function listAction()
      {
      // .. do some processing...
      $this->render();
      $this->render('searchForm'); // append <controller>/searchForm.phtml to response
      }
      ]]></ac:plain-text-body></ac:macro>
      <p>You could also do as you suggest in your comment: simply forward to another action when done with processing the current action. Since render() appends to the response object by default, this would aggregate sequentially. However, it's more expensive to dispatch another action than it is to call render() on another view script.</p>

  5. Mar 08, 2007

    <p>Hi,<br />
    view part of mvc is a little bit omitted, this is very good news that somebody what to improve this part. I think very important is what Markus has written, There is a need of some kind of view inheritance, where you can exchange only some parts of view (header, footer, etc.) and skeleton would be always the same, also please consider that methods like initView(), render() in controller class don't introduce much functionality, these methods are very simple. I think we should think about some kind of mappings between (module)/controller/action and view. When you dispatch action, view Controller choose proper view, and you don't have to think about it, you just write view, actions and set mappings. I've already done something like this, with use of plugins architecture of f. Controller and mappings in xml (mappings for module can be overwritten in controller mappings), works well with a few problems of inheritance.</p>

    <p>regards,</p>

    <p>Maciek</p>

    1. Mar 09, 2007

      <p>Maciek – render() <strong>does</strong> perform mapping between controller/action and view, and it works automagically. The idea is that if you have something like this:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      class FooController extends Zend_Controller_Action
      {
      public function listAction()

      Unknown macro: { $this->render(); }

      }
      ]]></ac:plain-text-body></ac:macro>
      <p>then render() will load foo/list.phtml in the current view script path. Additionally, the assumption is that the view script path is per-module.</p>

  6. Mar 08, 2007

    <p>I don't feel that this proposal should necessarily tackle the problem of common templates (or 'layouts' as I name them in my apps). That is more the domain of the developer, who can choose their approach as necessary.</p>

    <p>I'm starting to favour the former direction suggested by Rob Allen whereby each view fragment has a header/footer that relates to either a common layout or a special-case layout as appropriate. The hassle I found with the latter option was that I needed to set a view property to tell the script which page to include, which seemed a bit convoluted.</p>

    <p>E.g.</p>
    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    $view = $this->view;
    $view->news = $news->fetchAll();
    $view->template = 'news/index.tpl';
    $view->render('layout/common.tpl');
    ]]></ac:plain-text-body></ac:macro>

    <p>But I guess what I'm trying to say is that this is my design strategy, not Zend_View's nor Zend_Controller_Action's, and I think that allowing Zend_Controller_Action more responsibility in making those choices would be a poor design decision.</p>

    <p>It would be cleaner to write a Zend_View_Layout class yourself with a setTemplate() / getTemplate() method so that within your layout script you could simply call:-</p>
    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    <?php echo 'Generic Header' ?>
    <?php include $this->getTemplate() ?>
    <?php echo 'Generic footer' ?>
    ]]></ac:plain-text-body></ac:macro>

    1. Mar 08, 2007

      <blockquote><p>"But I guess what I'm trying to say is that this is my design strategy, not Zend_View's nor Zend_Controller_Action's, and I think that allowing Zend_Controller_Action more responsibility in making those choices would be a poor design decision."</p></blockquote>

      <p>I will second this.</p>

      <p>Although I can see the convenience of the shortcuts offered by this proposal, I dislike the degree of "magic" pre-integrated (perhaps simply a matter of personal taste). I would prefer this functionality remained the pervue of the developer, who is free to add this (or alternatives) in userland. Yes, I can simply ignore the new methods, but some overhead is still there , and I don't the changes proposed above helping provide a clean solution to the problem below:</p>

      <p>I also prefer the more classical style of MVC, where a ZF action controller can delegate to sub-controllers, and then assemble the results as they come back, passing the final result to its parent controller, and so on, with ZF views making up the "leaf" nodes. In classical MVC, events help coordinate between updates to the model and updates to views. Since this is a web environment, events can be processed until activity subsides. So what does this all mean? Well, I wish for a clean way to assemble views resulting from multiple actions, and keep track of which fragments belong to which logical views (e.g. the "friends online box" vs. the "recent posts box" on my personalized portal page). Currently, the parameters set from the front controller are shared with all actions dispatched, unless manually added or removed by the actions.</p>

      <p>As a workaround, I have suggested the idea of named segments in the response:
      <a class="external-link" href="http://framework.zend.com/issues/browse/ZF-1024">http://framework.zend.com/issues/browse/ZF-1024</a></p>

      1. Mar 09, 2007

        <p>To me, the problem is standardisation for the most common case. Yes everyone can roll their own code, but if they do, then I can't use someone else's module without reworking their controller-to-view code to match my way of doing it.</p>

        <p>Providing a standardised way of rendering the view from controller will make it more likely that third party ZF modules will exist and be used by people.</p>

  7. Mar 08, 2007

    <p>I think both the render function and easy access to a view object is a good idea. </p>

    <p>I, like many others, have implemented my own solution to this problem. My render method does exactly the same as yours. </p>

    <p>I also have a renderIn() method that renders the current action into a variable, adds this to the view and renders a predefined layout template, where the action content can be inserted from a predefined variable name.</p>

    <p>The most important: For easy access to the view script i have made a magic __get method that returns objects from the static registry. I find that this works rather good, as it gives me convenient access to both my config, db and view objects from my action controllers where they are used often. <br />
    I know that there are currently very active discussions about the registry, but it looks like a static version of it will remain in some form.</p>

    <p>Just my ideas.</p>

    <p>All in all, a very good proposal</p>

  8. Mar 09, 2007

    <ac:macro ac:name="note"><ac:parameter ac:name="title">"Official Zend Comment"</ac:parameter><ac:rich-text-body>
    <p>This enhancement is approved for development in the incubator. You may also do the implementation in the core directory, in a svn branch off of the trunk.</p>

    <p>The value of View integration and mapping to filesystems represents a popular idiom in web development, and it adds value to Zend Framework to support this kind of mechanism. Though it's very nice that the behavior is optional and it is easy to use the MVC without this style of View integration.</p>

    <p>The issue of layouts / composite views, etc. is clearly an important one, but this proposal does not appear to be intended to address it. That topic should be addressed in a different proposal. One problem at a time. <ac:emoticon ac:name="smile" /></p></ac:rich-text-body></ac:macro>

  9. Mar 24, 2007

    <p>Hi</p>

    <p>I think it is easy to do by using Zend_Controller_Front_Plugin_* capabilities. In my opinion this should be a proper way of integrating Zend Framework components.</p>

    <p>Developers should take that under their consideration.</p>

    <p> Cheers, Alan "LBO" Bem</p>