Advanced bootstrapping : Configure your Zend Framework application for multiple host

This tutorial is intended to explain a way of bootstrapping Zend Framework based MVC application for multiple host/domains. Before starting, let me explain a bit about the situation when it’s needed.

A web application goes through some stages when growing up. Generally, it starts from development and ends at production. There can be some more stages within this two ends. And, in maximum cases this stages are overlapped. The overlapped stages can be hosted in different servers with different settings but shares the same code. In this situations, if we want to keep bootstrap in SVN repo, it needs to setup bootstrap in a little different way. So that, it can handle many server settings with a single bootstrap.

For example, just now I am working on an application which is being developed in 3 local machines (me and two other members of my team) and being tested in our staging server. Besides, our client is monitoring progress of current sprint in their staging server and testing completed sprints in their pre-production server. Here, except the production servers, all hosts contains a checked out copy of code from a single repository. But this hosts have some difference in their library path, database host and authentication etc.

If my assumptions are ok for you, let’s start after downloading.

Assumptions


I have assumed that you are familiar with Zend Framework. And already worked on (atleast one) ZF MVC application. You know the basic things about bootstrapping and using the most common directory structure (shown in image). However, you can tune this technique for your favorite Zend directory stracture.

Download files

Downoad the files from here. The zip file contains –

  1. index.php – This is the bootstrap file. Your .htaccess file points all request to this file.
  2. config.xml – Contains all configurations of your application, for all hosts.
  3. Bootstrap.php – A php class that handles all startup settings in a vary organized way. (I don’t know who first wrote it, Thanks to him)

How to bootstrap for multiple host

After extracting the zip, put the Bootstrap.php in your own library directory(library/my) and config.xml in applications configs directory. Index.php file will be generally located at myapp/public/index.php. All requests need to go through this file (Front Controller).

Just change this 3 files as your applications need. Then your application will be ready for bootstrapping for all your servers, without any change. So, lets see what to change in these files and how it will work.

First, open the index.php file. Now, in ‘List of servers’ section, list all your server paths in arrays by their application stage. For example, here I’ve listed all staging servers in $staging. Then, in ‘Define APPSTAGE’ section, define the application stage and set the include_path for this stage. If you if you have 2 or more servers with different library path but for same stage, you should  write set_include_path in conditions by checking the server-name. At end of this file, include the Bootstrap.php file (assuming in library/my folder) and run the static Bootstrap::start() method. Pass the path of config.xml file as parameter.

   1: // List of servers
   2: // each array will contain all your server paths for a specific stage of application
   3: $development = array('local.myapp.com', 'another.localhost.com');
   4: $staging     = array('myapp.devs-staging.com', 'clients-staging.com');
   5: $production  = array('myapp.com');
   6:
   7:
   8: // What is our host right now ?
   9: $host = $_SERVER['HTTP_HOST'];
  10:
  11: /*
  12: * Define APPSTAGE
  13: *
  14: * Check in which server the application is running,
  15: * and define the application stage as 'APPSTAGE'
  16: * then set library to the include_path so that we can access the libraries, also set models directory for servers of each stage.
  17: */
  18: if(in_array($host, development)) {
  19:     define('APPSTAGE', 'development');
  20:     set_include_path('path/of/development/library' . PATH_SEPARATOR . '../myapp/path/of/models' . PATH_SEPARATOR . get_include_path());
  21: }
  22: elseif(in_array($host, $staging)) {
  23:     define('APPSTAGE', 'staging');
  24:     set_include_path('path/of/staging/library' . PATH_SEPARATOR . '../myapp/path/of/models' . PATH_SEPARATOR . get_include_path());
  25: }
  26: elseif(in_array($host, $production))
  27: {
  28:     define('APPSTAGE', 'production');
  29:     set_include_path('path/of/production/library' . PATH_SEPARATOR . '../myapp/path/of/models' . PATH_SEPARATOR . get_include_path());
  30: }
  31: else
  32: {
  33:     die('Application is not within configured servers.');
  34: }
  35:
  36: // Load our Bootstrap class
  37: require_once('/path/of/Bootstrap.php');
  38: My_Bootstrap::start('path/of/configs/config.xml');

Then open the config.xml file. Under the root element (configdata), first child nodes will be the name of you application stages which you’ve defined in index.php. In my example, they are production, staging and development. This nodes will now contain the stage specific settings. Change this settings as your application and servers environment.

   1: <?xml version="1.0" encoding="UTF-8"?>
   2: <configdata>
   3:     <!-- Config for production server -->
   4:     <production>
   5:         ............
   6:         ............
   7:     </production>
   8:
   9:     <!-- Config for staging servers -->
  10:     <staging extends="production">
  11:         ............
  12:         ............
  13:     </staging>
  14:
  15:     <!-- Config for development servers -->
  16:     <development extends="production">
  17:          ............
  18:          ............
  19:     </development>
  20: </configdata>

Now, look at the bootstrap class (in Bootstrap.php). When you run the Bootstrap::start() method in index.php, it loads setting for your APPSRAGE section. Then  setup everything of your application using this settings.

   1: // Load the Configarations
   2: self::$config = new Zend_Config_Xml(self::$configPath, APPSTAGE);
   3:
   4: // Prepare your application
   5: self::setupEnviroment();
   6: self::prepare();

See how this class setting up everything carefully and change as your need. For quick reference, I am just listing here the methods of this class –

  • start() – Starts the bootstrapping process by calling a number of interim functions and at the end, sends the response.
  • setupEnvironment() – Setup application environment by specifying debug option, query logging, output compression and  setting the time zone.
  • prepare() – Prepare the application by loading the required Zend libraries and then calling other functions for their specific setup (Front controller,  View, Database etc.)
  • setupFrontController() – Get the instance of Zend front controller and then set a few basic options. Also specify the default controller path.
  • setupView() – Get an instance of Zend view and set the unicode encoding. Then get the view renderer and set it as a view helper for further help.
  • setupDatabase() – Load the DB config and then store it in Zend registry. Afterwards, use it for connection to database and setting it as default adapter of Zend_Db_Table.
  • setRoutes() – Setup and manage all routings of appllication
  • sendResponse() – Receive the response object and set the unicode header before sending it to the output

That’s all. feel free to change anything at any step of this process. Your comments/suggestions are very much welcome.  If you have a better idea, please let us know. We’ll be grateful to you.

19 Comments

  1. Thanks for sharing. I hadn’t seen this Bootstrap.php before, will take a look at that.

    I do have some problems with this method of loading configuration though. Firstly, the need to add the domains to the configuration – meaning every new domain (new developers, a local fork by me etc) will result in changes to the code base. Secondly, I’m not sure how you handle CLI scripts using this? – almost every larger application I’ve made has used CLI for batch processing etc.

    I’ve posted (http://blog.tekerson.com/2009/02/13/environment-specific-bootstrapping-for-zend-framework/) the method I use to handle the same problem. It uses separate configuration files instead of “sections”, but could easily be modified if you prefer the sections approach.

  2. A shorter beginning for index.php would be:

    $servers = array_fill_keys(array(‘local.myapp.com’, ‘another.localhost.com’), ‘development’);
    $servers += array_fill_keys(array(‘myapp.devs-staging.com’, ‘clients-staging.com’), ‘staging’);
    $servers += array_fill_keys(array(‘myapp.com’), ‘production’);

    if(isset($servers[$_SERVER[‘HTTP_HOST’]])) {
    define(‘APPSTAGE’, $servers[$_SERVER[‘HTTP_HOST’]]);
    set_include_path(‘path/of/’ . APPSTAGE . ‘/library’ . PATH_SEPARATOR . ‘../myapp/path/of/models’ . PATH_SEPARATOR . get_include_path());
    unset($servers);
    } else {
    die(‘Application is not within configured servers.’);
    }

  3. I use a different way to configure server. I don’t really like $servers=…
    Instead I use an other config file based on hostname.

    dev

    prod

    With a new server, I only have to modify my config file to add my new server…

  4. I made a boo boo ! html tags are stripped 🙁

    my config file is an xml config file, I assign a tag “server” with dev, prod, etc. in sections named by hostname. When I load my config file, I juste have to specify the hostname

  5. Have you ever worked with any other J2EE (aka java framework) for example, Struts. It should be 101 for any distributed development environment. Good start for using Zend Framework !!! Cheers. Good work!

  6. nice article, thanks for sharing.

    I was wondering if you could point me to some post or article where I can understand bootstrapping better. Do suggest me some way for this.

    Many Thanks in Advance

  7. Great post!

    One thing I’m very interested in learning – and what isn’t very well documented is to how to build modular zend application.

    There are many resources, but none of them covers the whole process.

    Would you be keen on creating the tutorial on how to deal with it?

Leave a Comment

Your email address will not be published. Required fields are marked *