LogoPhly, boy, phly
the weblog and site of Matthew Weier O'Phinney

Friday, January 8. 2010

Quick Start to Zend_Application_Bootstrap

We added Zend_Application to Zend Framework starting in version 1.8.0. The intent behind the component was to formalize the application bootstrapping process, and provide a simplified, configuration-driven mechanism for it.

Zend_Application works in conjunction with Zend_Application_Bootstrap, which, as you might guess from its name, is what really does the bulk of the work for bootstrapping your application. It allows you to utilize plugin bootstrap resources, or define local bootstrap resources as class methods. The former allow for re-usability, and the latter for application-specific initialization and configuration.

Additionally, Zend_Application_Bootstrap provides for dependency tracking (i.e., if one resource depends on another, you can ensure that that other resource will be executed first), and acts as a repository for initialized resources. This means that once a resource has been bootstrapped, you can retrieve it later from the bootstrap itself.

How it works

Now that you know what it does, let's jump into the basics.

If you use the zf command-line tool provided with Zend Framework to generate your project ("zf create project"), you'll get a bootstrap and a default configuration right out of the gate. This includes the following files in the tree:

application/
|-- Bootstrap.php
|   `-- configs/
|   |   `-- application.ini

The Bootstrap.php file will contain the class Bootstrap which extends Zend_Application_Bootstrap_Bootstrap; this class will be empty at first. The application.ini file will contain the following:


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

[staging : production]

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

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1
 

Zend_Application runs in three stages. First, it initializes the PHP environment, using INI settings from your configuration if provided, and setting up the include_path and autoloading. Second, it initializes and executes the bootstrap class. Finally, it then "runs" the application (by calling the bootstrap's run() method).

Configuration Settings

What we see in the above listing is a set of:

  • PHP initialization settings (here, they indicate whether or not to display errors)
  • include_path settings
  • Settings that indicate the name and location of the bootstrap class
  • Application resource settings

The phpSettings key accepts any php.ini keys as subkeys, and these key/value pairs will be passed to ini_set. This can be useful when you need to either ensure specific INI settings are made, particularly when you want them to vary based on environment. (In the example above, display_errors is enabled in testing and development, but disabled otherwise.)

When it comes to the include_path and autoloading, probably the most often asked question is, "How do I add namespace prefixes for code other than ZF to the autoloader?" This can be done easily in the configuration file using the autoloaderNamespaces key, and appending namespace prefixes to it:


autoloaderNamespaces[] = "Phly_"
 

Regarding the bootstrap class and file location, typically the defaults will be fine. However, if you want to specify a custom name -- for instance, to provide a class prefix -- or perhaps if your default module is in a subdirectory, you can notify Zend_Application of this via the bootstrap.class and boostrap.path settings:


bootstrap.class = "Application_Bootstrap"
bootstrap.path = APPLICATION_PATH "/modules/application/Bootstrap.php"
 

Getting started with Bootstrap Resources

Now we finally get to the true fun: the bootstrap resources themselves.

Yes, I'm aware I'm glossing over the "appnamespace" setting; I'l cover that at another time.

Bootstrap resources may be one of two things:

  • A protected method in the bootstrap class prefixed with "_init"; e.g., "protected function _initFoo()"
  • A class implementing Zend_Application_Resource_Resource_Resource

In the former case, _init*() methods, each will be executed in each request. In the latter, only those that you specify in your configuration will be executed, allowing you to selectively choose which of the various shipped resource plugins (or those you have written yourself!) will be used.

In the case of the default configuration, only the "frontcontroller" resource plugin will be used, corresponding to Zend_Application_Resource_Frontcontroller. As of the upcoming 1.10 release, you can pick and choose from the following additional resource plugins as well:

  • Cachemanager
  • Db
  • Dojo
  • Layout
  • Locale
  • Log
  • Mail
  • Modules
  • Multidb
  • Navigation
  • Router
  • Session
  • Translate
  • View

Each has its own configuration options, documented in the manual.

Writing Resource Methods

Writing your own resource methods is trivial: you simply create the method, and do some work. You then have the option of returning a value; if you do, it will be stored within the bootstrap so that you may retrieve it later. As an example:


class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initRegistry()
    {
        $registry = new Zend_Registry();
        return $registry;
    }
}
 

If we wanted to retrieve the registry later, we could do so using the bootstrap's getResource() method:


$registry = $bootstrap->getResource('Registry');
 

Note that we pass the name of the method minus the "_init" prefix; this "short name" is how the resource is referred to within the bootstrap, and how you will refer to it later.

Now, let's say you have a resource that depends on your "Registry" resource; for instance, let's say you want to create a Zend_Currency object, and pass it to the registry. Zend_Application_Bootstrap was designed to handle this very situation, and institutes some powerful dependency tracking (this is, in fact, why the initialization methods are protected; it prevents them being called directly). Simply call the bootstrap() method with the name of the resource to initialize. Additionally, the getResource() method can then be used to retrieve the value registered for that resource. As an example:


class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initCurrency()
    {
        $this->bootstrap('Registry');
        $registry = $this->getResource('Registry');

        $currency = new Zend_Currency('$');
        $registry['Zend_Currency'] = $currency;
        return $currency;
    }

    protected function _initRegistry()
    {
        $registry = new Zend_Registry();
        return $registry;
    }
}
 

What will happen is this:

  • Zend_Application will call bootstrap() with no arguments, which loops through the internal resource methods first, and then any configured resource plugins.
  • The bootstrap will execute the _initCurrency() method
  • It sees the bootstrap() call, and executes it
  • The bootstrap() call executes the _initRegistry() method, storing a Zend_Registry instance (which was returned from the method) internally on completion
  • Execution of _initCurrency() resumes, starting with the getResource() call; this returns the Zend_Registry instance stored under that key in the bootstrap.
  • Execution of _initCurrency() completes, and the bootstrap stores the returned Zend_Currency instance.
  • The bootstrap() method then attempts to call the _initRegistry() method, but notes that it has already been executed, and thus moves on to execute resource plugins.

As you can see by now, the bootstrap functionality is quite flexible and powerful, and provides a number of benefits immediately out of the box.

Until next time...

At this point, you should have enough to get started writing your own bootstrap initialization resources. In coming weeks, I'll blog about how to build reusable resource plugins, as well as discuss how bootstrapping fits into modular applications.

Posted by Matthew Weier O'Phinney in PHP at 12:57 | Comments (25) | Trackback (1)
Defined tags for this entry: php, zend framework
Related entries by tags:
Responding to Different Content Types in RESTful ZF Apps
Symfony Live 2010
Creating Re-Usable Zend_Application Resource Plugins
Real-time ZF Monitoring via Zend Server
Building RESTful Services with Zend Framework

Trackbacks
Trackback specific URI for this entry

Quick Start to Zend_Application_Bootstrap - phly, boy, phly
We added Zend_Application to Zend Framework starting in version 1.8.0. The intent behind the component was to formalize the application bootstrapping process, and provide a simplified, configuration-driven mechanism for it.
Weblog: abcphp.com
Tracked: Jan 09, 00:34

Comments
Display comments as (Linear | Threaded)

Good one :-)

Thanks for telling us in advance the application resources of 1.10.
#1 Bruno (Link) on 2010-01-08 13:40 (Reply)
Are there any preferred methods of setting which environment (devel, staging, productoon) will be used for Zend_Application_Bootstrap? I realize there are many ways it could be done but was wondering if you have any thoughts to share?

One method that has worked out reasonably well for me lately is to have a preBootstrap.php that gets included from index.php. In preBootstrap I look at where I'm running ($_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']) and then set APPLICATION_ENV in a big switch.

I've even wound up having to set the Zend Framework path when I've had environments which force it to be in different places.

The trade-offs for me is that I like to be able to use rsync for releases and not have to change any files (including symlinks) in the source tree between environments.

Thanks,
--Rob
#2 Rob T. on 2010-01-08 15:17 (Reply)
Rob T,

I like use environment variables set in the Vhost declaration of my httpd.conf.

Regards,

Rob..
#2.1 Rob... (Link) on 2010-01-08 15:19 (Reply)
Rob:

Yes that's good if you have access to httpd.conf. You wouldn't necessarily have that in a shared hosting environment.

I did see your recent post blog about running ZF in a shared hosting environment http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/

(To me running in some sort of shared environment is usually the most common case, especially given cookie restrictions)

Thanks,
--Rob T.
#2.1.1 Rob T. on 2010-01-08 15:44 (Reply)
In a shared environment, I would use htaccess to redirect all possibly domain addresses to a single canonical one and then use that as the APPLICATION_ENV using a putenv('APPLICATION_ENV='.$httpHostName); in index.php.

Regards,

Rob...
#2.1.1.1 Rob... (Link) on 2010-01-08 15:52 (Reply)
As Rob Allen notes, I like to use server environment variables -- and the approach is actually used in the index.php/.htaccess generated by Zend_Tool already. ;-)

This allows you to default to production, but have your vhosts in staging and development set a different environment, without requiring you to make any code modifications.
#2.2 Matthew Weier O'Phinney (Link) on 2010-01-08 15:41 (Reply)
Unfortunately this approach does not work with command line scripts. How do you set the environment when running from the command line?

I have solved it by checking if a given file exists and if the file exists it will be included.
In the included file I do something like this:

define('APPLICATION_ENV', 'staging');

I am curious how other developers have solved this problem?
#2.2.1 Joris van de Sande (Link) on 2010-01-09 10:29 (Reply)
environment variables work just fine for command line:
echo "export SL_ENV=dev" >> ~/.bashrc # SL_ENV being the environment variable we use to detect, well, environment
bin/devel/some_script # will use dev environment
#2.2.1.1 Bruce Weirdan (Link) on 2010-01-12 13:45 (Reply)
oh, forgot to mention you would need to source .bashrc (. ~/.bashrc) before running scripts (this won't be necessary once you log out and then log in back).
#2.2.1.2 Bruce Weirdan (Link) on 2010-01-12 13:48 (Reply)
To change the environment from the command line:
One time run:
APPLICATION_ENV=staging php script.php

Set for the current session:
export APPLICATION_ENV=staging
php script.php

To set permanently see Bruce Weirdan's comments.


That said, I do use your method of using an environment file on hosts that don't allow me to set environment variables via .htaccess
#2.2.1.3 David (Link) on 2010-01-18 21:31 (Reply)
uname -n
#2.2.1.4 Joe Devon (Link) on 2010-02-02 23:53 (Reply)
Will the $bootstrap variable always be available to Controllers Actions? If not, what's the best way to get an instance of it?
#3 Bryan Zarzuela (Link) on 2010-01-09 10:41 (Reply)
In your controller you can use:
$bootstrap = $this->getInvokeArg('Bootstrap');
#3.1 Rocco Bruyn on 2010-01-09 12:11 (Reply)
Which is the best way to get the Bootstrap object and it's resources within other classes than controllers, e.g. Forms, ViewHelpers etc?

Would it be acceptable to have a

class Bootstrap...
{
...
public function _initBootstrap()
{Zend_Registry::set('bootstrap', $this);}

}
#3.1.1 Jakob Schumann on 2010-01-09 17:01 (Reply)
Jakob:

$frontController = Zend_Controller_Front::getInstance();
$view = $frontController->getParam('bootstrap')->getResource('db');


Regards,

Rob...
#3.1.1.1 Rob... (Link) on 2010-01-09 17:12 (Reply)
»In coming weeks, I'll blog about how to build reusable resource plugins, as well as discuss how bootstrapping fits into modular applications.«

I am eager to learn about module bootstrapping. I am also curious how these things will work in zf 2.0, since standalone modules are not really envisioned within zf 1.x
#4 Exception e on 2010-01-09 17:45 (Reply)
A concern for me is that the Bootstrapping class tends to promote alot of pre-initialization (I'm aware that it can be restricted to certain ini method calls if needed) as opposed to loading on demand. For example db initialization. So at present for me bootstrapping is a minimal effort in initializing the application environment with a 'context' class that extends the Zend_Application class from which all other primary components can be retrieved (on demand) e.g. db, session and access to a Zend_Config object.
#5 Greg on 2010-01-12 10:33 (Reply)
So, a few comments.

First, Zend_Db actually is inexpensive to load. The actual database connection does not happen until an operation is made that actually needs to talk to the database. As such, you shouldn't be worried about it.

As for your approach, it's one that's not unfamiliar to me. A number of ZF users are using DI containers such as Yadif or the new Symfony DI container in conjunction with Zend_Application; this allows them to populate the container with the appropriate configuration, and then retrieve objects on demand from it later. Some do this by replacing the "container" within the bootstrap object with their DI container -- an operation that is not only fully supported, but part of the design.

The idea with any form of bootstrapping is that you initialize only what is needed for every request, and also that you provide enough configuration information that anything else may be loaded on-demand later. As such, your approach makes complete sense -- and is not incompatible with the architecture of Zend_Application as it currently stands.
#5.1 Matthew Weier O'Phinney (Link) on 2010-01-12 11:11 (Reply)
Matthew, are you going to cover this topic in future?
#5.1.1 Martin on 2010-01-14 06:13 (Reply)
Very likely, yes.
#5.1.1.1 Matthew Weier O'Phinney (Link) on 2010-01-14 07:03 (Reply)
This is great, but I dont need entire navigation or ACL on every page, i don't need logger as well on every request. Is there a way to lazy load resources, or sth like that? to instantiate them on demand, when I need them, dynamically.
#6 umpirsky (Link) on 2010-01-12 14:06 (Reply)
I'll be covering that in another post. The short answer: there are ways to allow it in the existing infrastructure: you can initialize controller plugins per-bootstrap that only initialize information if the module is matched in the request, or, as binarykitten blogged recently, do some additional logic from a single front controller plugin that calls additional initialization from the matched module.
#6.1 Matthew Weier O'Phinney (Link) on 2010-01-12 14:10 (Reply)
Nice article. I think, it will very useful to beginners.

You not against if I publish translation of this article in the my blog?
#7 Oleg Lobach (Link) on 2010-01-16 20:37 (Reply)
My translate of this article to russian language - http://lobach.info/develop/zf/quick-start-to-zend_application_bootstrap/
#7.1 Oleg Lobach (Link) on 2010-01-23 07:11 (Reply)
Thank you for this useful article.
#8 Adg (Link) on 2010-02-25 07:46 (Reply)

Add Comment

Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
 
  • Home
  • Resume
  • Blog
  • Phly PEAR Channel
  • Contact Me
  • About this site

ZCE

Zend Education Advisory Board Member

Add to Technorati Favorites

Calendar

Back March '10 Forward
Mon Tue Wed Thu Fri Sat Sun
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

Quicksearch

Links

  • PHLY - PHp LibrarY
  • Paul M. Jones
  • Mike Naberezny
  • Shahar Evron
  • Planet PHP
  • Zend Where I now work
  • Garden.org Where I once worked

Archives

March 2010
February 2010
January 2010
Recent...
Older...

Categories

XML Linux
XML Personal
XML Aikido
XML Family
XML Programming
XML Dojo
XML Perl
XML PHP

All categories

Syndicate This Blog

XML RSS 0.91 feed
XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 0.3 feed
ATOM/XML ATOM 1.0 feed
XML RSS 2.0 Comments

Show tagged entries

xml best practices
xml books
xml conferences
xml cw09
xml decorators
xml dojo
xml dpc08
xml file_fortune
xml git
xml linux
xml mvc
xml oop
xml pear
xml perl
xml personal
xml php
xml phpworks08
xml programming
xml rest
xml ubuntu
xml vim
xml webinar
xml zendcon
xml zendcon08
xml zendcon09
xml zend framework
© 2004 - present, Matthew Weier O'Phinney
matthew-web <at> weierophinney.net