Naked Zend_Layout and Zend_View

By , Tuesday 10th August 2010 11:47 pm

In this article I look at using Zend_Layout and Zend_View along with a simple front controller to show how it is possible to start separating business logic and presentation within your application. All code is available on github:
Naked Zend_Layout and Zend_View on GitHub.

MVC

A common design pattern for modern web applications is the MVC pattern. The Zend Framework in ‘full stack’ mode is one implementation of MVC in PHP and consists of three parts:

  • Model (M)
  • View (V)
  • Controller (C)

The pattern is designed such that business and presentation logic are completely separated from one another (with business logic in the model, and presentation in the view) and the controller sitting in the middle conducting the “orchestra”.

Presentation and Logic

In the Zend Framework the view  is handled by two main components: Zend_View and Zend_Layout. Zend_Layout as the name suggests looks after the layout  aspect of the site (generally headers, footers, sidebars, etc). Zend_View focusses on presenting the data that your model has been working to produce or derive.

As developers, and their applications, evolve we tend to move through various stages, generally each an improvement on the previous, improving maintainability and extensibility. One of the main issues is that presentation and logic still get intermingled and its not simple to start separating the two.

What’s wrong with mixing the two?

OstrichThere’s several reasons why mixing different parts of the application, for example a designer working on your site may not want to (or have the knowledge) to scan around in code trying to work out where to make presentation changes. In the same way a developer (if you’re like me who has the design skills of an ostrich) may break out in a cold sweat when you mention design or UI work.

Additionally what if later you would like to present your sites on different media, such as mobile telephones, tablet PCs, or expose the data via web services (XML/JSON/etc)? Having mixed presentation and logic you stand almost no hope without some very ugly hacks to pull the presentation back out of your code, before injecting something new. If data and presentation has been separated making these changes are almost trivial, create a new view script for the new format and direct requests as appropriate.

Separating the two

In an evolving application its not always economical to start implementing a full MVC solution and the application needs to be migrated slowly – sometimes running old code in parallel with new. It maybe that there are masses of logic (such as database connection setup, authentication, cookie handling, etc) that aren’t ready for moulding to your chosen frameworks setup, therefore old and known-to-be-working code can continue to be used until such time it can be rewritten/refactored.

Note: Using Zend_Layout and Zend_View like this is perfectly acceptable within the Zend Framework landscape and the framework has been designed such that individual components can be used without the rest of the framework. A great advantage in evolving applications and probably one of the major reasons for its high uptake in enterprise applications.

Front Controller

Below I create a front controller  – a single file designed to pick up any requests which are not matched to a file on the file-system. This is often achieved using a .htaccess file such as the one used in the default Zend Framework install. Within the front controller I will be setting up our layout and view and showing where the different parts of the application slip into it.

define('APP_PATH', dirname(__FILE__). '/..');
// Start buffering output
ob_start();

// Create a Zend_View instance
Zend_Layout::startMvc();
$layout = Zend_Layout::getMvcInstance();
$layout->setLayoutPath(APP_PATH . '/layout/scripts')
    ->setViewSuffix('phtml')
    ->setLayout('index');

$view = $layout->getView()
    ->setScriptPath(APP_PATH . '/view/scripts')
    ->addHelperPath(APP_PATH . '/library/Zend/View/Helper', 'Zend_View_Helper');

// Set Base URL - ok *almost* naked, but you don't need this!
Zend_Controller_Front::getInstance()->setBaseUrl($_SERVER['HTTP_HOST']);

try {
    /**
     * Perform some application routing...
     *  - Could be using this as a front controller and directing all requests
     *    through this one file (provided file does not exist in file system
     *  - Note the method below is only really for demonstration, it would be
     *    horrible with a large site
     */
    switch ($_GET['page']) {
    	case 'index':
    	case 'exception':
    		$pageName = $_GET['page'];
    		break;
    	default:
    		$pageName = false;
    		break;
    }
    // Example of a page not being found...
    if (false === $pageName) {
        $responseHeader = 'HTTP/1.1 404 Page Not Found';
        throw new Exception('Page not Found');
    }

    /**
     * Add data to your view object here
     *   You may have your own controller implementation or some includes files
     *   where business logic is partly separated from view logic
     */
    $view->displayText = 'Hello from Lloyd';
    $view->buttonText  = 'I\'m not active!';

	$layout->content = $view->render("{$pageName}.phtml");
    echo $layout->render();
} catch (Exception $e) {
	// Clean out already buffered content - we don't want to display that!
	ob_clean();
    if (!isset($responseHeader)) {
    	$responseHeader = 'HTTP/1.1 500 Internal Server Error';
    }
    header($responseHeader);
    $view->exception = $e;
    $layout->content = $view->render('error.phtml');
    echo $layout->render();
}

Firstly we start output buffering, by doing this we can set our headers at any point in the request and know that it is possible to send them. Should an exception be thrown at any stage of the code execution we clean this buffer and write out or error message content and layout. This ensures that we do not deliver part rendered content containing errors to the end user.

Next a new MVC instance of Zend_Layout is generated and we tell it that out layout scripts have the extension phtml, are to be found in a directory outside of the public path, and that our default layout is called index(.phtml). From the layout we then extract the view object (to which we set our data to be presented) and apply similar setup.

Next we setup the view object with a reference to the default Zend_View helpers. View helpers are sets of additional convenience functionality. For example, writing out a float in monetary format, or creating a zebra striped table (they can be read about here). By extending Zend_View_Helper_Abstract and adding your own library at this point its possible to use your own application view helpers.

The rest of the application code is now wrapped in a try {} catch {} block. Should anything throw an uncaught exception we can catch it and display a nice error message to the end user.

Our first task within the try {} catch {} is to route our request, what does the user want to see? Here I’ve implemented some very simple demonstration code where I check the value of the ‘page’ get variable. Your routing can be very much more complex. The routing is used to call what ever code needs to be executed to get/handle data provided by the user and to tell the system what view (and possibly layout script) to use.

Ultimately if our router does not match any page it sets a 404 response code and displays a nice page not found message to the end user. Here, we throw and catch our own exception (and a very generic exception at that) but probably you’d be throwing your own exception from within the router code.

Once we’ve successfully routed our request we can begin to do something with the code. It might be that you have your own controllers/models implemented or you include some code that’s already been separated somewhat. Here I set a couple of simple variables to the view object.

Once this is completed we simply render the views with our data. If the code throws an uncaught exception for any reason this is trapped near the bottom of the script. Here we clear already buffered output, set a 500 response header, and tell our application to render the ‘error’ view script (which is generally a much stripped down version of the normal layout/view and logs the error for checking later).

As the view is rendered first and injected into the layout it is possible to change the layout from within the view, and indeed set required extras, for example,

  • Page title
  • Meta tags
  • Scripts (URLs or code) into the <head> section
  • Add additional styles, etc

Additionally its even possible to change the entire layout from within the view by using…

<?php $this->layout()->setLayout('alternativeLayout') ?>

…as and when required.

Finally…

I hope this has been a useful introduction to Zend_Layout and Zend_View and it will enable you to start implementing your own basic MVC and improve the maintainibility/extensibility of your code. Please take a look at the source code for examples of usage (see the README file for instructions).

The code assumes that you’ve already got autoloading working (or you have included the required classes).  In addition, I would not recommend that you implement the routing or data setting as above, this is very much simplified for demonstration. To see the full code take a look at the source code linked at the top of this article.

Zend Framework version: 1.10.6

Liked this post? Follow this blog to get more. 

One Response to “Naked Zend_Layout and Zend_View”

  1. Andy says:

    Well written and most informative, thanks!

Leave a Reply

You must be logged in to post a comment.

Panorama Theme by Themocracy

4 visitors online now
1 guests, 3 bots, 0 members
Max visitors today: 4 at 12:32 am UTC
This month: 15 at 10-10-2017 02:55 pm UTC
This year: 45 at 02-01-2017 10:28 pm UTC
All time: 130 at 28-03-2011 10:40 pm UTC