I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 637 posts at DZone. You can read more from them at their website. View Full User Profile

Zend Application demystified

11.16.2010
| 5875 views |
  • submit to reddit

Zend_Application is a bootstrap facility available in Zend Framework from the 1.8 release. While using single components of Zend Framework is as simple as including the source files, the MVC machine is quite more difficult to set up and the approach of organizing the boostrap via reusable, segregated application resources lets you manage the process without screaming for its complexity. However, it's not so simple to get Zend_Application to work the first time, and here's a primer on how it can help you.

Resource is a generic name in the English language; however, in Zend Framework it denotes a small class or method that Zend_Application can call in order to set up a component such as a database connection, a View object or the session storage. Usually, the config/application.ini file is read to define which resources has to be instantiated.

Keep the environment clean

Zend_Application supports different environments you can define (such as testing or production, or whatever number of environments you may want). These environments can inherit configuration values from one another.

There are severail ways to define the environment to choose at startup: an environment variable valorized in the Apache configuration, or manually. It is one of the two parameters of Zend_Application, the other being the whole Ini configuration.

There are many resources to mine

Resources can be defined as _init*() method of a Boostrap class or as standalone classes.

Resources usually return something, which is the product of their work. For example, Zend Framework by default runs some resource like the Frontcontroller one or the View one. The latter returns the View object that will be used to render .phtml scripts, and that you can interfere with.

The boostrap object, internal to Zend_Application, can be grabbed by the controllers or by other resources. For example they can

  • Require other resources to be run, defining essentially a dependency. The other resource will be run only once, even if called multiple times.
  • Grab the products of other resources, like a database connection.

The resources that have to be run are defined by the configuration values present in the same .ini file. For some inflection reason, the name of the resources are case insensitive and are not usually written in camelCase (Frontcontroller, Entitymanagerfactory).

Show me the code!

Let's dive into an application.ini example.

[production]
autoloaderNamespaces[] = "My_"

This means that the Autoloader will try to load classes that starts with My_ from the include_path. The classes have to conform to the psr0 standard: for example: My_Filter_Klass will be placed in My/Filter/Klass.php.

Note that this option is a numerical array, of which 'My_'  is a value.

bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

These values are pretty common, and define the boostrap class, containing the resources defined as methods. You can use constants in your ini file (APPLICATION_PATH) as long as they are defined into the .php file that instantiates Zend_Application.

pluginPaths.ZendX_Doctrine2_Application_Resource_ = "ZendX/Doctrine2/Application/Resource"

This option defines an additional path for custom resources. All the resources in that folder will be referred from now on simply with their basename. In this case, we had an Entitymanagerfactory whose complete name is ZendX_Doctrine2_Application_Resource_Entitymanagerfactory.

resources.view.helperPath.My_View_Helper = "My/View/Helper/"
resources.view.helperPath.Zend_View_Helper = APPLICATION_PATH "/views/helpers"

These are the first example of passing parameters to a resource. The view resource accepts a bunch of options, one of them is helperPath. helperPath is an associative array, which maps prefixes to folders and is used to define where View Helper classes can be found.

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

This line is instead related to the frontController resource. The option under scrutiny defines the directory containing the controller classes.

resources.entitymanagerfactory.modelsPath = APPLICATION_PATH "/models"

Another example of passing a configuration option to a custom resource.

Here is the skeleton of a boostrap class instead:

class Boostrap extends Zend_Application_Boostrap_Bootstrap
{
    public function _initSomething()
    {
        // ...
        return $result;
    }

    public function _initDb()
    {
        // ...
        return $pdoConnection;
    }
}

And here's a fictional application resource example:

My_Application_Resource_WorldDominationEngine extends Zend_Application_Resource_ResourceAbstract
{
    public function init()
    {
        // lazy-executes the view resource and access its result so that the WorldDominationEngine
        // can get a reference to the View object
        $view = $this->bootstrap('view')->getResource();
        // ...
        return $worldDominationEngine; // the product of this resource, that
                                       // can be requested by other resources in order to work
    }

}

Remember that Boostrap methods and resource classes are functionally equivalent: the difference is only in the format of the initialization method and your preferences about code organization.

Once autoloading has been taken care of, instantiating Zend_Application is as simple as this:

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

Recommendations

Zend_Application ties you into Zend Framework a bit more than a plain old file-based setup, but it simplifies the integration and the reusability of all the resources an application may require, first of all external connections to Gateways and object|relational|document databases.

Reusability is also important: it's common to run a resource in isolation in testing, or even the whole set of resources within a different environment to perform functional tests. The classic case is an Sqlite in-memory database instead of a real one: this can be achieved by overriding a single option in the testing Ini configuration section.

As a final note, you may know that you can generate your application skeleton, and also its Ini configuration file by executing Zend_Tool from the command line. I'm not fond of this approach: writing the configuration and creating the folder structure yourself will give you a primer on which are the moving parts of a Zend Framework application and the cause-effect relationships between them. Zend_Tool is tought to avoid repeating this process over and over on new applications.

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mark Twain replied on Sat, 2011/10/01 - 12:37pm

A little note about performance: ini parsing is expensive and pretty unnecessary in production environment.

I suggest to implement a cache system, obiously expernal to Zend system, to improve performance, like this:

$configIni = APPLICATION_PATH . '/configs/application.ini';
$configIniSerialized = ROOT_PATH . '/data/cache/' . basename($configIni) .'.cache';
if (
		!is_file($configIniSerialized)
	or	!($configCache = unserialize(file_get_contents($configIniSerialized)))
	or	$configCache['filemtime'] != filemtime($configIni))
{
	$configCache = array(
		'filemtime' => false,
		'config' => $configIni,
	);
}

// Zend_Application
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
	APPLICATION_ENV,
	$configCache['config']
);

if (!$configCache['filemtime']) {
	file_put_contents($configIniSerialized, serialize(array(
		'filemtime' => filemtime($configIni),
		'config' => $application->getOptions(),
	)));
}

$application
	->bootstrap()
	->run()
;

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.