Zend Framework 1.8 Web Application Development

By Keith Pope
    Advance your knowledge in tech with a Packt subscription

  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Creating a Basic MVC Application

About this book

The Zend Framework has a flexible architecture that lets you build modern web applications and web services easily. The MVC components make the maintenance and testing of your applications easier. However, it is not only an MVC framework for developers. It also provides an easy-to-use high-quality component library that is designed to be used the way you want, picking up specific components without requiring the use of whole framework.

It's easy to get started and produce a powerful and professional looking web site when you've got this book to hand. Taking you through a real-life application, it covers the major Zend Framework components, as well as throwing light on the best practices and design issues faced when building complex MVC applications.

This book takes you through detailed examples as well as covering the foundations you will need to get the most out of the Zend Framework. From humble beginnings you will progress through the book and slowly build upon what you have learned previously. By the end, you should have a good understanding of the Zend Framework, its components, and the issues involved in implementing a Zend Framework based application.

Publication date:
September 2009
Publisher
Packt
Pages
380
ISBN
9781847194220

 

Chapter 1. Creating a Basic MVC Application

In this chapter, we will take our first steps into using the Zend Framework. This provides us with a very quick run-through of using the Model-View-Controller (MVC) components by creating a simple web page. We will look at the following aspects:

  • What MVC is

  • Setting up your environment

  • Installing Zend Framework

  • Creating a Project with Zend_Tool

  • Bootstrapping and Configuration

  • Creating Controllers

  • Creating Views

  • Handling Errors

By the end of this chapter, you should be comfortable with the general concepts and be ready to move on to creating more advanced functionalities.

 

Overview of MVC architecture


As we are going to be using MVC extensively throughout this book, it is important that you have an understanding of what MVC is and what its goals are.

Trygve Reenskaug first devised MVC in the late 1970s for Smalltalk. Since then, it has evolved and has many different implementations, and much debate surrounds them. Even with the great amount of debate surrounding MVC, it still retains its basic goal of separating user interface code into three separate areas. This basic concept is fairly easy to understand. However, the details of an MVC implementation can be very complex.

The three areas that MVC defines are Model, View, and Controller. These are responsible for domain logic, user interface, and control logic respectively. By separating application responsibilities in this way, we gain the following benefits:

  • The addition, editing, and removal of interfaces is simple

  • The ability to have multiple separate views of the same data

  • Changes made to the logic control are easy

  • Helps developers avoid repeating common code

  • Helps developers to work together in segregation

There are, of course, disadvantages to MVC and situations where it should not be used. For example, the application we are about to create is very simple. Therefore, if it always stays this way, then there would be no point in using MVC, as the overhead created by the MVC implementation outweighs the benefit.

We will be looking at how the Zend Framework implements MVC in Chapter 2. For now, we will stick with this brief explanation of what MVC is and move on to creating our Hello Zend application. I hope this gives you an idea of the main aspects involved and the benefits you can get by using it.

 

Setting up the environment


First, we need to set up our environment and get a copy of the Zend Framework.

You can download the source package from http://framework.zend.com/download. For the purposes of the book, get version 1.8.0.

Note

You may also wish to familiarize yourself with the projects Subversion repository. This is useful if you want to use any functionality that is still in development. Information on the Subversion layout can be found at http://framework.zend.com/wiki/display/ZFDEV/Subversion+Standards.

The minimum PHP version to run the Zend Framework is 5.2.4; Redhat users that are stuck at 5.1 should consider using Zend Server (http://www.zend.com/products/server) to easily upgrade your PHP version.

For the examples in this book, you will also need a web server that has URL Rewrite support such as Apache (http://httpd.apache.org/).

 

Installation


Once we have downloaded the Zend Framework release package, we need to do some basic installation before we can start creating our application. First, create a new directory within your web server's document root, from which the application will be served. The examples in this chapter use the directory name of helloZend. Next, copy the library and bin directories from the release package into the newly created directory. The library directory contains all of the Zend Frameworks source files, and the bin directory contains the command line interface for the Zend Framework. The Zend Framework is now installed and ready for use!

 

Creating the project structure


We are now ready to start creating the directory structure for our project. In order to do this, we are going to use the command line interface provided by the Zend Framework. This interface uses the Zend_Tool component that provides a whole host of commands that makes it very easy to get up and running with the Zend Framework in just a few minutes.

In order to create the project structure, open up your command line and change into the hellozend directory, and then run the following command:

For Windows users:

bin\zf.bat create project

For Linux and Mac users:

bin/zf.sh create project

This command creates a Zend Framework project in the specified location. In our case, this is the current directory (.). We could specify another location for our project like this:

bin/zf.sh create project /my/other/path

When we run our create project command, Zend_Tool creates the basic application skeleton for us. The output of the command should look something like this:

Zend_Tool not only creates directories, but it also creates some basic elements that form a very basic MVC application for us. In order to see what it created, point your web server to the newly created public folder within our hellozend directory.

For Apache users, a basic virtual hosts setting for this would be something like:

Listen 8080
<VirtualHost *:8080>
   DocumentRoot /Users/keithpope/Sites/hellozend/public
</VirtualHost>

Once you have your web server configured, open your browser and browse to the hellozend site. In this case, it will be http://localhost:8080/. We should now see the Zend Framework start page, as shown in the following screenshot:

Wow, that was easy wasn't it! We are now ready to start looking at what Zend_Tool created and try out some of the basic Zend Framework features.

 

Application directory structure


When we create our project using Zend_Tool, it creates the basic directory structure for us. If we open our hellozend directory, we can see the folders that are shown in the following screenshot:

This structure has four main areas, application, library, public, and tests. These directories are probably common to most Zend Framework applications, though they may be named differently.

The application directory is responsible for holding our application-specific files such as configs, models, controllers, and views.

Inside the application directory, we have our main MVC folders—controllers, models, and views, which hold controller, model, and view files respectively. In other Zend Framework applications, you may also see modules, which are used to split controllers, models, and views into manageable groups. We will be using modules later in our storefront application.

The library directory is responsible for holding our supporting classes such as the Zend Framework components or our own components that do not come into the scope of a model.

Inside the library directory, we have the Zend directory that contains the Zend Framework source files.

Tip

The Zend directory

It is important to remember that you are not forced into placing the Zend directory in the library folder. For example, if you use the Zend Framework for multiple sites, then you can simply place it in a folder that is part of your PHP include path. By doing this, you will have access to the Zend Framework components in all PHP scripts.

The tests directory stores our tests for our application. We will be using this later when we use PHPUnit to test the Storefront.

The public directory is responsible for holding all of our publicly accessible assets such as images, CSS, and JavaScript.

 

Bootstrapping


Another aspect Zend_Tool took care of during installation is bootstrapping. This refers to the process of application initialization where we configure, and startup, the MVC process when someone requests a page. Zend_Tool did a lot for us here, so let's break it down and see exactly what it did.

The index file

Inside the public directory, Zend_Tool created the file index.php, which is the main entry point for all of the requests to our application. Inside this file we have the following code:

public/index.php

<?php

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) .'/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ?getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(realpath(APPLICATION_PATH . '/../library'),get_include_path(),)));
/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(APPLICATION_ENV,APPLICATION_PATH . '/configs/application.ini');
$application->bootstrap()->run();

The index file is responsible for handling a user's request for a page of the application. All requests to the application are routed through the index file. If we look at what is happening within this file, then we see that the first code block defines the constant APPLICATION_PATH. This constant defines the path to the application directory. This is used throughout the application to access files stored within that directory.

Next, we set the APPLICATION_ENV constant. This is used by the application to change certain behaviors depending on how the application is being used. For example, we may want full error messages in a development environment. However, in a production environment, we may just want to log these messages and not display them to the user. Also, notice that this code block uses the getenv() PHP function that checks the system environment variables for the APPLICATION_ENV constant. This is one way of easily setting the environment for our applications. We will cover more on this later.

After our constants are set, we then configure PHP's include path for the Zend Framework to function. The library folder must be on the include path so that the component classes can be loaded.

After this, we initialize the application using Zend_Application. First, we include the Zend_Application file, and then create a new instance of this class. When instantiating Zend_Application, we pass the environment constant and the path of the configuration file to its constructor. We then call the bootstrap() method (which initializes the application) and the run() method (which starts the MVC process). We will look at Zend_Application in detail later.

As we mentioned before, all requests are routed through the index file. In order to make all requests do this, we need to configure Apache to rewrite all the requests to index.php. In order to do this, Zend_Tool has created a .htaccess file for us inside the public directory.

public/.htaccess

SetEnv APPLICATION_ENV development

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

The rewrite rule will route all requests to index.php, unless a file actually exists and if the file does exist, it will serve that file. This is because we can have images, CSS, and other assets accessible to the public. We also set the application APPLICATION_ENV environment variable using SetEnv, currently we are using development. If we were in another environment, then we would change that here.

The .htaccess is actually missing one important directive, that is to turn PHP short tags on. As we will be using short tags later in our Views, we can add this to our .htaccess.

php_value "short_open_tag" "on"

This can also be done in the php.ini. However, the .htaccess is better if you don't want short tags to be global.

Why route everything to index.php? In Zend Framework, we route all requests to index.php, as we are going to be utilizing Zend Framework's MVC architecture, the basis of which uses the Front Controller design pattern. This pattern is defined as:

The Front Controller consolidates all request handling by channeling requests through a single handler object. This object can carry out common behavior, which can be modified at runtime with decorators. The handler then dispatches to command objects for behavior particular to a request.

Martin Fowler—Patterns of Enterprise Application Architecture http://martinfowler.com/eaaCatalog/frontController.html

On its most basic level, the Front Controller in Zend Framework decides what controller/action to call when a request is made and stops us from the need to have multiple PHP files in the public directory like about.php.

Application configuration

Although Zend_Application is taking care of the bootstrapping for us, it requires some configuration. Zend_Tool again creates the basic configuration for us, which is stored in the configs directory.

application/configs/application.ini

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH"/controllers"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

The default config file contains four sections that match the environment types that are available in our application. Zend_Application has many configuration options that we won't look at in detail yet. The three important ones for now are boostrap.path, boostrap.class, and resources.frontController.controllerDirectory. These tell Zend_Application where the main bootstrap file is located, tell Zend_Application the class name of the bootstrap class, and tell the Front Controller where its controller files are located respectively.

The bootstrap file

The final part of the bootstrapping process is the Bootstrap class. All Zend Framework applications that use Zend_Application must have at least one Bootstrap class. Zend_Tool must have created this for us, so let's look at what it did.

application/Bootstrap.php

<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{}

We can see that the Bootstrap class is just an empty class that subclasses the Zend_Application_Bootstrap_Bootstrap class. Now, in most applications, this would not be the case, and the Bootstrap class would contain methods that initialize various parts of the application such as logging and so on.

We will come back to this later and add in some of our own initialization code. For now though, let's get on and look at some controllers.

 

Your first controller


At this point, we already have a fully working web page. However, to understand a bit more about what we have done, let's look at the controllers created by Zend_Tool. This controller is called an Action Con troller, and Zend_Tool creates two controllers by default (indexController.php and ErrorController.php). These are located in the application/controllers directory. The Action Controller is concerned with our application's control logic and is part of the 3-tier separation that Model-View-Controller offers.

If we start by opening the indexController.php file, then we see the following:

application/controllers/indexController.php

<?php
class IndexController extends Zend_Controller_Action
{
    public function init()
    {
        /* Initialize action controller here */
    }

    public function indexAction()
    {
        // action body
    }
}

The first thing to note about Action Controllers is their naming. Naming needs to take a consistent form so that the Front Controller can find the file and execute its Actions. In case of IndexController, we name the file as IndexController.php, which defines this as the index controller. Inside the file, we name the controller class IndexController, which matches the filename. The matching of the filename and class name is very important. If we don't do this, then it will cause the Front Controller to throw a not found exception.

Now, when we edit the index controller we are going to change the default controller so that we can test out some of the MVC features.

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{    
    public function init()    
    {
        $this->_helper->viewRenderer->setNoRender();
    }
    
    public function indexAction()
    {
        $this->getResponse()
             ->appendBody('Hello from indexAction');
    }
}

Open your browser and browse to http://127.0.0.1:8080/.

You should now see the following screenshot in your browser:

Let's break this down and have a look at the Action Controller's functionality in more detail.

The Action Controller

Zend Framework provides the Zend_Controller_Action abstract class, which gives us the base functionality for our controllers. This includes view integration, data accessors, and utility methods.

Subclassing

In order to create a new controller, we have to subclass the Zend_Controller_Action while providing a concrete implementation for our controller. This can then be called by the Front Controllers dispatch process. We do this in our IndexController:

class IndexController extends Zend_Controller_Action

We could also create another abstract class that subclasses Zend_Controller_Action to create our own base action controller. This is useful if you have code that is common to all of your controllers. For example, if we needed to regularly access a logging object to add log messages for our controllers, then we could move the instantiation code into our own base controller. By doing this, we can remove repeated code in our controllers.

abstract class My_Controller_Action extends Zend_Controller_Action
{
    public $logger;
    public function getLog()
    {
        /* Returns a log instance */
    }
}

Once we have our own base controller, we can then use it to create our controllers.

class IndexController extends My_Controller_Action
{
...

We will now have access to the log instance in all of our controllers through the getLog() method. As you can see, Zend Framework provides a great deal of flexibility in the way we can work with our controllers. However, we should use the above controller sparingly, as we will have problems with inheritance down the line. A better approach for this would be to create an Action Helper. We will address these later.

Initialization

Zend_Controller_Action also provides us with an easy way to add controller initialization code through the init() method. This is called when the controller is instantiated by the Front Controller during the dispatch process. We can see this by looking at the constructor of Zend_Controller_Action.

Zend_Controller_Action

public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array$invokeArgs = array())
{
    $this->setRequest($request)
         ->setResponse($response)
         ->_setInvokeArgs($invokeArgs);
    $this->_helper = new Zend_Controller_Action_HelperBroker($this);
    $this->init();

}

We use this in our IndexController by overriding the init() method. It is important that we do not override the constructor, as this will cause errors later on if we forget to call the parent constructor. Therefore, we always use the init() for constructing time code.

application/controllers/IndexController.php

public function init()    
{
    $this->_helper->viewRenderer->setNoRender();
}

The actions we perform in the init() method are controller wide, as init() is called every time the controller is instantiated. In IndexController, we are using the viewRenderer Action Helper to turn off automatic view rendering for all of the actions in our controller. We will look at Action Helpers in more detail shortly.

Actions

Some of the most important parts of our controllers are the actions they contain. Without actions, our controllers wouldn't do anything. In order to create an action, we add a new method that has Action appended to its name. The Front Controller will then automatically recognize them as actions. We can have as many actions as we like in our controllers, and we can also have other methods that are not actions. Non-action methods must not have Action appended to them. In our controller, you can see that we have the init() method, and that it does not have Action. This means that it is not publicly accessible.

If we look at IndexController, we have one Action method called indexAction. If we want to add another action, then we simply create a new method. So, if we wanted an action called about, then we would create a method called aboutAction.

Zend_Tool can create actions for us. In order to create a new action within a controller, we can run the following command:

For Windows users:

bin\zf.bat create action about index

For Linux and Mac users:

bin/zf.sh create action about index

This command will create a new action within the IndexController and a view script for this action. Once this is done, edit the IndexController and add the following to the aboutAction:

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{    
    public function init()    
    {
        $this->_helper->viewRenderer->setNoRender();
    }
    
    public function indexAction()    
    {
        $this->getResponse()
             ->appendBody('Hello from indexAction');
    }

    public function aboutAction()
    {
        $this->getResponse()
             ->appendBody('Hello from aboutAction');
    }
}

Easy, isn't it? Now, if we browse to http://127.0.0.1:8080/index/about, we should see the following screenshot:

If we try deleting the Action from aboutAction, so that the method is now called about, and visit the above URL again you will see that an error saying that the action could not be found is displayed:

We can also add another method to handle undefined actions. This method is given below:

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{    
    public function init()    
    {
        $this->_helper->viewRenderer->setNoRender();
    }

    public function indexAction()    
    {
        $this->getResponse()
             ->appendBody('Hello from indexAction');
    }

    public function aboutAction()
    {
        $this->getResponse()
             ->appendBody('Hello from aboutAction');
    }
    
    public function __call( $method, $args )
    {
        if('Action' == substr($method, -6)) {
            $this->_forward('index');
        }
    }
}

Adding the PHP magic method __call(), will invoke this method when an undefined action is called. We can then check if it is an action call and then do something like display an error or call a different action. In our example, we use the _forward() utility method to call indexAction. By doing this, if we try to call an undefined action, we will get the indexAction.

The standard router

As we have mentioned before, Zend Framework uses a Front Controller that takes our request and processes it. An important part of this is the standard router. The router is responsible for taking a request and translating it to decide what module, controller, and action is being requested. The translation is based on predefined rules or routes. The standard router defines a default route, which we have already been using in our application. We will look more closely at routes and the dispatch process when we look at the Zend Framework's Architecture. For now, let's take a look at the default route.

The default route needs to determine the following elements from the request:

  • Module

  • Controller

  • Action

In the Standard Router, this information is taken from the URI endpoint of the HTTP request. The endpoint is the part after the base URI. Therefore, the URI is broken down like this:

http://domain.com/moduleName/controllerName/actionName

As you can see, it's pretty straightforward. We simply give the names of the module, controller, and action that we want to call. You may be wondering where the module has come from, as it does not fit into our example. Zend Framework supports modules, which are used to group controller files into directories. This is so that we don't get directories full of more controllers than we can manage. Since our example does not use modules, our controllers are associated with the default module, imaginatively named default. For the default modules (and controllers), we are not required to enter their identifiers in the URI.

If we look at our IndexController, we can see that when we browse to http://127.0.0.1:8080/index/about, we are telling the Front Controller we want IndexController and aboutAction. You can also see that we have not set up a module, as the module part is not required.

In order to clarify a bit more, here is a table of the active routes in our application:

URI

Module / Controller / Action Called

 

http://127.0.0.1:8080/

Default / IndexController / indexAction

 

http://127.0.0.1:8080/index

Default / IndexController / indexAction

 

http://127.0.0.1:8080/index/index

Default / IndexController / indexAction

 

http://127.0.0.1:8080/index/about

Default / IndexController / aboutAction

 

In addition to being able to call the controller and action we want, we can also send extra data with the request through the URI. In order to send extra data or user parameters, we simply add them to the URI. For example, if we want to send a user parameter called name to the aboutAction, then we would create a URI like:

http://127.0.0.1:8080/index/about/name/keith

This would then create a new user parameter called name with the value of keith. The parameter would then be set in the request object and is available to our application. This behavior does not affect the standard HTTP GET, so you can still use GET in your URIs.

Therefore, this is valid, and you have access to all of the data passed here at:

http://127.0.0.1:8080/index/about/name/keith?age=26&country=England

Let's try some of this out on our IndexController. Edit the indexAction to this:

application/controllers/IndexController.php

public function indexAction()
{
    $name = $this->_getParam('name','guest');
    $this->getResponse()
         ->appendBody('hello ' . $name . ' from indexAction');
}

Now, browse to http://127.0.0.1:8080/index/index/name/keith, and you should now see hello keith from indexAction displayed in your browser as follows:

In indexAction, we use the accessor method _getParam() to retrieve our passed in username parameter value, and store it in $name. The _getParam() takes two arguments:

  • the name of the parameter you want to retrieve

  • default value if it is not set, which is optional

The data returned is retrieved from the request object. The request object is a value object that contains information about the request. When using _getParam(), it is important to note that the request object aggregates request data. This means that when we use _getParam(), the request object will look for data in user parameters GET and then POST. Therefore, the above example will still work if we send the name as a GET parameter. This behavior can be customized using the setParamSources() method of the request object.

Finally, we pass the $name into the response object's body so that it will be rendered at the end of the dispatch process. You may have noticed that we haven't escaped the data we are outputting. In a normal situation, we would have to escape the $name variable before outputting it to the browser to stop Cross Site Scripting attacks, this has been left out simply for brevity.

Utility methods

The Zend_Controller_Action abstract class provides utility methods that help us with some common tasks when using the MVC functionality.

_forward utility method

The _forward() utility method is used to call actions. This helps us to easily move from action to action if we need to.

_forward($action, $controller = null, $module = null, array $params = null)

Looking at the _forward definition, we can see that it takes up to four arguments, three of which are optional:

  • $action (string required): The action to call.

  • $controller (string optional): The controller the action is in.

  • $module (string optional): The module the controller is in.

  • $params (array optional): User parameters to send with the request.

If you only supply $action _forward(), then it will look for the action within the current controller. We can try this out by using our basic application.

We first need to create a new controller. We can do this by using Zend_Tool with the following command.

For Windows users:

bin\zf.bat create controller Contact

For Linux and Mac users:

bin/zf.sh create controller Contact

Running this command will create a new controller for us and create the related View directories for this controller. Once the controller is created, edit it so that it looks like the example that follows:

application/controllers/ContactController.php

<?php
class ContactController extends Zend_Controller_Action 
{
    public function init()
    {
        $this->_helper->viewRenderer->setNoRender();
    }    

    public function indexAction()
    {
        $this->getResponse()
             ->appendBody(' You can contact me @ ' . $this->_getParam( 'email', '' ) );
    }
}

Edit IndexController and add the following code:

application/controllers/IndexController.php

public function aboutAction()
{
    $this->getResponse()
         ->appendBody('hello from aboutAction');
    $this->_forward( 'index', 'contact', null, array( 'email' => '[email protected]' ) );
}

Now, if we browse to http://127.0.0.1:8080/index/about, then we should see the following screenshot:

In IndexController, we have forwarded the request to our new controller's index action and passed with it a new user parameter called email. Then in ContactController, we have added some text and the new email user parameter to the response object. You should also notice that the URL does not change, and we are still in /index/about. This is important because when we forward, we forward internally, which means we are still using one request.

_redirect utility method

The _redirect() utility method is in a way the opposite to _forward(). Where _forward() calls an action within the same request, _redirect() performs an HTTP redirect creating a new request.

redirect() accepts the following arguments:

  • $url (string required): The URL to redirect to

  • $options (Array Optional)

And the $options can be:

  • exit (Boolean): Whether to exit straight away, or not

  • prependBase (Boolean): Prepend the base URL, or not

  • code (String): The HTTP code to use

By default, _redirect() will do a 302 redirect.

Action Helpers

Action Helpers are used to provide extra functionality to Action Controllers, without the need to extend the abstract Action Controller. They are very useful when we need common functionality between controllers. We have already used one of the default Action Helpers in our own controllers to turn off view rendering.

application/controllers/IndexController.php

public function init()    
{
    $this->_helper->viewRenderer->setNoRender();
}

During the initialization of IndexController and ContactController, we call the viewRenderer Action Helper and set the noRender flag on the view object. By doing this, we stop the default behavior of the viewRenderer from automatically rendering the view object for each action within our controller. If we did not do this for our examples, then we would get errors from the view object saying it could not find the view script. This is because we have not created any yet. The Action Controller Abstract contains the _helper property, which contains the Action Helper Broker. The broker is responsible for managing the registration and retrieval of helper objects. Therefore, we use $this->_helper to access our registered helpers. We can also use the getHelper() or getHelperCopy() methods, define our own helpers, and register them with the broker.

Zend Framework provides the following Action Helpers:

  • ActionStack: Enables a stack of actions to be called

  • AutoComplete: Ajax auto completion

  • ContextSwitch: Switch response formats based on a context

  • AjaxContext: Same as ContextSwitch, but for Ajax specifically

  • FlashMessenger: Handles messages for the user between requests

  • JSON: Easy JSON output

  • Redirector: HTTP redirector

  • ViewRenderer: View initialization and rendering

As you can see, there are many default Action Helpers defined. We will try and use many of these as we progress through the book. For now, let's move on and make our application actually output some HTML.

 

Your first view


Now that we have our basic application structure and our controllers working, let's look at views. Views obviously form the V part of MVC, and are responsible for the display. This display could be the user interface HTML, JSON output, and so on. By using views instead of writing directly to the response object like we have done so far in our examples, we achieve the MVC goal of separating view from control logic. Let's go ahead and create our first view.

View directories

When Zend_Tool created our project and as we added more Controllers and Actions to our application, various View-related folders and files were created. If we now look inside, we will see what Zend_Tool has created:

The first thing we see here is that we have a views folder within the application folder. This holds all of the Views, View Helpers, and View Filters for our application. Within the views folder, we have two directories helpers and scripts. These directories contain View and View Helpers respectively. We may also have a filters folder. However, Zend_Tool does not create this for us. Within the scripts folder, we have another three folders. Each folder relates to a controller name. So in our application—we have contact, error, and index that match the three controllers we have ContactController, ErrorController, and IndexController. All of these were created by Zend_Tool as we added the Controllers and Actions to our application.

Creating a view

As we have been using Zend_Tool, all of the Views have already been created for us. Therefore, we only need to edit what is already there to get our application working. Views in the Zend Framework are written in PHP and are known as View Scripts. All View Scripts have their files ending in .phtml. We can see that Zend_Tool has created all the .phtml files for us, and they are contained within their respective controller View Script folders.

So let's now edit the index controller's index view script and add in some of our own code. We can delete any code that is already in these files.

application/views/scripts/index/index.phtml

<html>
<head>
    <title>Hello Zend</title>
</head>
<body>
    <h1>Hello Zend</h1>
    <p>Hello from Zend Framework</p>
</body>
</html>

That's it! Our first view has been created. As you can see, it's just some very simple HTML. However, if we browse to http://127.0.0.1:8080/, we don't see this rendered. We need to refactor our controller to get things working.

application/controllers/IndexController.php

public function init()    
{}
    
    
public function indexAction()
{
    $name = $this->_getParam('name', 'guest');    
}

We first remove $this->_helper->viewRenderer->setNoRender(); from the init() method. This tells the viewRenderer that we want its default behavior of automatically rendering the view scripts for us. Then, we remove $this->getResponse()->appendBody('hello ' . $name . ' from indexAction'); from the indexAction. This is because the view will write to the response object for us.

If we now browse to http://127.0.0.1:8080, we should see the HTML rendered from our view script. When we visit our page, the viewRenderer Action Helper is automatically instantiating a view object and looking for our view script in /application/views/scripts/index/ and then rendering it for us.

Of course, we can also pass data into the view. In order to do this, we simply set the data in the view object, which is stored in the Action Controllers $view property.

application/controllers/IndexController.php

public function indexAction()
{
    $this->view->name = $this->_getParam('name', 'guest');
}

application/views/scripts/index/index.phtml

<head>
    <title>Hello Zend</title>
</head>
<body>
    <h1>Hello Zend</h1>
    <p>Hello <?=$this->Escape($this->name);?> from Zend Framework</p>
</body>

In our IndexController, we assign the name user parameter into the view, and then in the view we echo it out. There are a couple of important things happening in the view. First, we are escaping the output using the Escape() view method. Second, we are using PHP short tags.

Escape() is used to safely output data in views. You should always make sure your data is escaped, unless you know that it has already been escaped. This will help prevent Cross Site Scripting attacks. By default, Escape() uses the htmlspecialchars() PHP function for escaping. You can customize this by using the setEscape() method of the view object. This accepts a callback function that will be used for escaping.

We are using PHP short tags, because it makes our view much easier to read and much more designer friendly. If you do not have short tags enabled, then you will need to enable them for the examples to work. There is also a special stream wrapper for views that will automatically convert short tags into long tags. However, you will take a performance hit when using it. I would only use this if you can't enable short tags. You can enable the stream wrapper using $view->setUseStreamWrapper(true); on the view.

Now, we have our view, which is rendering our user parameter. If we browse to http://127.0.0.1:8080/index/index/name/keith, then we should now see Hello keith from the Zend Framework displayed. We should note here that we have to use index/index/ to access the indexAction of the indexController. Using index/name/keith would not work, as the dispatcher would look for the nameAction in the indexController.

There is also another method of assigning variables to the view object using the assign() method. This can be helpful for assigning multiple values to the view. Let's have a little play with assigning some variables using assign().

application/controllers/IndexController.php

public function indexAction()
{
    $date = new Zend_Date();

    $data = array(
        'hour' => $date->get(Zend_Date::HOUR),
        'min'  => $date->get(Zend_Date::MINUTE),
        'sec'  => $date->get(Zend_Date::SECOND)
    );

    $obj = new stdClass();
    $obj->day   = $date->get(Zend_Date::DAY);
    $obj->month = $date->get(Zend_Date::MONTH);
    $obj->year  = $date->get(Zend_Date::YEAR);

    $this->view->assign($data);
    $this->view->assign((array) $obj);
    $this->view->name = $this->_getParam('name', 'guest');
}

application/views/scripts/index/index.phtml

<html>
<head>
    <title>Hello Zend</title>
</head>
<body>
    <h1>Hello Zend</h1>
    <p>
        Hello <?=$this->Escape($this->name); ?> from Zend Framework
        @ <?=$this->Escape($this->hour); ?>:<?=$this->Escape($this->min); ?>:<?=$this->Escape($this->sec); ?>
         on <?=$this->Escape($this->year); ?>/<?=$this->Escape($this->month); ?>/<?=$this->Escape($this->day); ?>
    </p>
</body>
</html>

If we now browse to http://127.0.0.1:8080/index/index/name/keith, then we can see that the date and year is displayed after the hello message.

The first way in which we use assign() is to add values stored in an array using $this->view->assign($data);. This assigns the matched pair values to the view object, so hour gets assigned to the view with a value of the current hour, and so on.

In the second method, we use assign() to add the values of an object's public properties using $this->view->assign((array) $obj);. This will assign all of the public properties to the view, so day gets assigned to the view with a value of the current day, and so on. Note that we need to cast the object to an array for this to work, as the assign method only accepts both a string and a value or an array. It does not automatically convert objects for us.

View Helpers

View Helpers are an important tool in creating our view. Just as the Action Controller has Action Helpers, the view has View Helpers. These are helper classes that assist us in creating our view. Zend Framework packs a number of View Helpers, most of which are used for creating HTML elements. Let's look at an example of using a View Helper.

URL View Helper

One common task when creating web pages is creating links that point to other parts of your web site. To help with this, we have the URL View Helper. To use the URL Helper, we simply need to call it from within one of our view scripts.

application/views/scripts/index/index.phtml

<html>
<head>
    <title>Hello Zend</title>
</head>
<body>
    <h1>Hello Zend</h1>
    <p>
       Hello <?=$this->Escape($this->name); ?> from Zend Framework
        @ <?=$this->Escape($this->hour); ?>:<?=$this->Escape($this->min); ?>:<?=$this->Escape($this->sec); ?>
        on <?=$this->Escape($this->year); ?>/<?=$this->Escape($this->month); ?>/<?=$this->Escape($this->day); ?>
    </p>
    <p>
        <a href="<?=$this->url(array('controller' => 'contact','name' => $this->name), null, true );?>">Contact Me!</a>
    </p>
</body>
</html>

All View Helpers are available through the view instance ($this). In order to invoke the URL Helper, we simply enter $this->url(). The URL Helper returns a string of the generated URL. We also have to provide some arguments to tell the helper where we want the link to point. If we do not provide any arguments, then the returned string will be the current URL. The URL Helper accepts the following arguments:

  • $urlOptions (array optional): An associative array containing options for the router

  • $name (string optional): The name of a route

  • $reset (Boolean optional): Whether to reset the route or not

In our example, we supply $urlOptions to define the controller that we want to link (contact), and we also define a new user parameter (name). We do not supply a $name, as we don't have any routes setup in the router. The URL Helper uses the router to assemble the URL. This is partly why using the URL Helper is a good practice, as our links are then router aware. We will be using the router later, so don't worry about the fact that we haven't covered it yet. Finally, we set the reset flag to true so that any user parameters in the current request are not appended to the URL.

This will then produce a URL like /contact/index/name/guest if we browse to http://127.0.0.1:8080/ and will produce a URL like /contact/index/name/keith if we browse to http://127.0.0.1:8080/index/index/name/keith.

As you can see, using View Helpers is pretty straightforward. However, you may be wondering why you would use the URL Helper, as it adds a lot of code into the view. The reason we use the URL Helper is mainly for maintainability. If we change any of the routes later, then we won't need to update our code. You will see this in action when we start using custom routes later.

There are many more View Helpers available. These include the following:

  • Action View: Calls an Action

  • Partial: Renders another view in its own variable scope

  • Placeholder: Persists content between Views

  • Doctype: Returns the doctype

  • HeadLink: Links CSS

  • HeadMeta: Meta tags

  • HeadScript: Script tags

  • HeadStyle: Style tags

  • HeadTitle: Document title

  • JSON: Easy JSON output

  • Translate: Language translation

  • InlineScript: Inline script tag

  • HTML Object: Flash

  • Various Form Element Helpers: Creating forms

We have a wide range of View Helpers to choose from when creating our views. We will be using many of these as we progress and will create some of our own View Helpers.

View customization

There are many situations where we need to customize our view instance. We have briefly mentioned some of these customizations such as setting the escaping used by the view.

In order to show this, let's add some view customization to our Bootstrap class. Add the following method to the Bootstrap class:

application/Bootstrap.php

    protected function _initViewSettings()
    {
        $this->bootstrap('view');
        $view = $this->getResource('view');
        $view->doctype('XHTML1_STRICT');
    }

Here, we have created a new bootstrap resource, which will be executed by Zend_Application during the bootstrap process. Inside the _initViewSettings() method, we first call the view resource ($this->boostrap('view')). This is a default resource provided by Zend_Application that initializes the view for us. Internally, the view resource creates a new view instance for us and registers a new ViewRenderer Action Helper to the Action Helper Broker. This allows us to then get the Zend_View instance from the resource and configure it.

We only apply one small configuration to our view instance. This is the doctype for Zend_View to use, and we set this to XHTML1_STRICT. This will now make Zend_View produce XHTML1 compliant HTML. We can also use the Doctype view helper to add the doctype declaration to our pages. In order to do this, we simply edit any of our .phtml view scripts and add this at the top:

<?= $this->doctype() ?>

If we now browse to http://127.0.0.1:8080 and view the HTML source, we see that we have the doctype definition added to our document.

 

Handling errors


Something that all applications need is error handling, and most important of all is displaying meaningful errors to users. So far, our application has no nice way to display errors to users, or to us for that matter. Zend Framework provides a default way of handling thrown exceptions through the ErrorHandler Front Controller plugin. This plugin is automatically registered and enabled by default. If you do not wish to use the ErrorHandler, then set the noErrorHandler parameter to true on the Front Controller or set throwExceptions to true on the Front Controller.

Zend_Tool has already created an ErrorController and error view for us. If we open the ErrorController and its view, then we see the following:

application/controllers/ErrorController.php

<?php
class ErrorController extends Zend_Controller_Action
{

    public function errorAction()
    {
        $errors = $this->_getParam('error_handler');

        switch ($errors->type) { 
          case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:

                // 404 error -- controller or action not found
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Page not found';
                break;
            default:
                // application error 
                $this->getResponse()->setHttpResponseCode(500);
                $this->view->message = 'Application error';
                break;
        }

        $this->view->exception = $errors->exception;
        $this->view->request   = $errors->request;
    }
}

application/views/scripts/error/error.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN";"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd> 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>Zend Framework Default Application</title> 
</head>
<body>
  <h1>An error occurred</h1>
  <h2><?= $this->message ?></h2>

  <? if ('development' == APPLICATION_ENV): ?>
  
  <h3>Exception information:</h3>
  <p>
      <b>Message:</b> <?= $this->exception->getMessage() ?>
  </p>

  <h3>Stack trace:</h3>
  <pre><?= $this->exception->getTraceAsString() ?>
  </pre>

  <h3>Request Parameters:</h3>
  <pre><? var_dump($this->request->getParams()) ?>
  </pre>
  <? endif ?>
  
</body>
</html>

In order to see this in action, we need to edit the .htaccess file and change the application environment to production. By default, we are in a development environment where the error controller is not used.

public/.htaccess
SetEnv APPLICATION_ENV production

Now, if we browse to a page that does not exist, we should see a 404 page, for example, http://127.0.0.1:8080/thisdoesnotexist.

Our ErrorController simply gets the ErrorHandler and then uses it to decide what type of error to display. At the moment, this is very simplistic. However, for most applications you will probably want to add a lot more into your ErrorController. For example, you could add logging through Zend_Log.

When an exception is thrown within one of our Action Controllers or from the Front Controller when it cannot find a Controller or Action, it will set the type of error. The type of error can be:

  • EXCEPTION_NO_CONTROLLER

  • EXCEPTION_NO_ACTION

  • EXCEPTION_OTHER

These are set as class constants of the Zend_Controller_Plugin_ErrorHandler class. We also have access to the exception through the public exception property of the ErrorHandler. From this we can get the error message, stack trace, and so on.

It is important to note that the ErrorHandler handles only exceptions thrown from missing Action Controllers or internal application errors. It is not designed to catch errors from routing or other plugins.

 

Summary


In this chapter, we have looked at the basics of building a web application using the Zend Framework's MVC components. We have created a very simple application and have briefly looked at some of the core components and their various uses. Hopefully, you have an idea of what you can do with the Zend Framework and how flexible it really is. In the next chapter, we will look at the architecture and inner workings of the MVC components to help you understand just what exactly happens when a request is made, and show you the various ways in which you can customize and extend all of these features.

About the Author

  • Keith Pope

    Keith Pope has over ten years of experience in web-related industries and has had a keen interest in programming from an early age. Keith currently works in the airline industry as a technical project manager, providing entertainment systems
    for aircraft.

    He has been working with the Zend Framework since its first preview release, using it in many of his work and personal projects.

    Browse publications by this author
Book Title
Access this book and the full library for just $5/m.
Start FREE trial