View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{note:title=New Proposal Under Consideration}
This proposal has been rejected, but a new proposal is currently under consideration: [ZFPROP:Zend_Application - Ben Scholzen]. Please see that proposal for current APIs and discussion.
{note}

{zone-data:component-name}
Zend_Application
{zone-data}

{zone-data:proposer-list}
[Bill Karwin|mailto:bill.k@zend.com]
{zone-data}

{zone-data:revision}
1.1 - 17 August 2006: Initial proposal posting.
{zone-data}

{zone-data:overview}
This is a proposal for a general-purpose bootstrap class for Zend Framework MVC applications. The objectives are (1) to implement a reusable and extensible class for bootstrapping web-based applications, and (2) establish a convention for configuration-driven application instances.
{zone-data}

{zone-data:references}
* [Zend_Application_Resource|http://framework.zend.com/wiki/x/lY4]
{zone-data}

{zone-data:requirements}
* Component will instantiate Zend_Controller_Front or user-specified front controller class.
* Component will load config data from an array, file, or Zend_Config object and use the properties to configure the front controller.
* Component will register the autoload callback of Zend_Loader or user-specified loader class.
* Component will register a front controller plugin to load module-specific configuration files and process them with Zend_Application_Resource or user-supplied subclass of that component.
* Component will support conventions for locations and names for config files, modules, controllers.
* Component will proxy a run() method to the front controller, to dispatch web application requests.
{zone-data}

{zone-data:dependencies}
* Zend_Application_Resource
* Zend_Config
* Zend_Controller_Front
* Zend_Loader
* Zend_Registry
{zone-data}

{zone-data:operation}
The Zend_Application class is a general-purpose, configurable bootstrap class. It configures an instances of Zend_Controller_Front, sets an autload callback, and dispatches to the front controller. The only parameter you are required to give to Zend_Application is the home directory of the application. Then use the {{run()}} method to start processing the request.

An example of the simplest usage of Zend_Application is the following:

{code}
<?php
require_once 'Zend/Application.php';
$app = new Zend_Application('/path/to/app/home');
$app->run();
{code}

The Zend_Application constructor processes the home directory argument with the {{realpath()}} PHP function. If this function determines that the path is invalid, a Zend_Application_Exception is thrown.

h3. Using Config Files

Zend_Application attemps to read a "front" config upon startup. This config contains data specific to configuring the Front Controller and other resources that are application-wide, such as the Zend_Session.

Specify the config in the second constructor argument, or in the {{setConfig()}} method. You can specify the config in the following ways:

* Zend_Config object instance - you can load the config file yourself in your bootstrap script, and pass the object to Zend_Application.
{code}
$configObject = new Zend_Config_Ini('test-config.ini', 'section');
$app = new Zend_Application('/path/to/app/home, $configObject);
{code}

* PHP array - you can declare a plain PHP array, so you don't have to write config data in a file at all.
{code}
$configData = array('key' => 'value');
$app = new Zend_Application('/path/to/app/home', $configData);
{code}

* Path to the config file.
{code}
$app = new Zend_Application('/path/to/app/home', '/path/to/app/configdir/test-config.ini', 'section');
{code}

* Path to the directory containing the config file. The directory is searched for a file called 'config.ini' or 'config.xml'. The Zend_Config subtype is determined from the file extension. If more than one config.* file exists, it is non-deterministic which file is used, so it is best to specify the full filename. Only files named 'config.*' are searched; if you have a different filename, it is best to specify the full filename.
{code}
$app = new Zend_Application('/path/to/app/home', '/path/to/app/configdir', 'section');
{code}

* If you specify nothing, or a PHP null, this means to search the application home directory according to the behavior in the previous case.
{code}
$app = new Zend_Application('/path/to/app/home');
{code}

In addition to the "front" config file, each application module may have its own config file. This config file specifies module-level resources and other module-specific data. Also, routes can be defined in each module's config file. Zend_Application includes a front controller plugin that loads the appropriate config files for a ll modules and adds all routes prior to routing. Then after routing, during the pre-dispatch step, the plugin processes other entries in the module's config file, so that resources are loaded only for the module to which the request is routed.

By default, this config file is located in a directory "config" which is a sister to the "controllers", "modules", and "views" directories.

{code}
$app = new Zend_Application('/path/to/app/home');
// Finds module config in '/path/to/app/home/config/config.ini'
{code}

The name of the "config" directory can be customized with a property in the front config file called 'moduleConfigDirectoryName', but that directory name is still relative to a given module's home directory.

{code}
$configData = array('moduleConfigDirectoryName' => 'etc');
$app = new Zend_Application('/path/to/app/home', $configData);
// Finds module config in '/path/to/app/home/etc/config.ini'.
{code}

Both {{.ini}} and {{.xml}} formats are supported.

h3. Registering Autoloader

By default, Zend_Application registers an autoload callback, using Zend_Loader::registerAutoload().
You can specify properties 'autoloadEnabled' and 'autoloadClass' in the front config, to override the behavior of whether or not to enable autoloading, and the class to use for the autoload callback.

Also, if you subclass Zend_Application, you can specify different default values in the protected class members {{$_autoloadEnabled}} and {{$_autoloadClass}}

h3. Configuring Zend_Application

Zend_Application uses config properties to declare customizations to the front controller and other application bootstrapping. None of the config properties are mandatory.

The following config properties are recognized:

|| Property || Description ||
| 'applicationResourceClass' | String names the class for the resource plugin to use to read module config files. |
| 'autoloadEnabled' | Boolean; enable the autoload callback if true. Default true. |
| 'autoloadClass' | String names the class to use for the autoload callback. Default Zend_Loader. |
| 'baseUrl' | String names the base URL of the application. This is passed to the front controller's {{setBaseUrl()}} method. |
| 'configFile' | String specify the modules' config file name, to be found by the front controller resource plugin. |
| 'configSection' | String specifies the config section to be read in the modules' config files. |
| 'controllers' | Array or Zend_Config object, maps one or more module names to their respective controller directories, in the manner supported by the front controller's {{setControllerDirectory()}} method. |
| 'frontControllerClass' | String names the class to instantiate the front controller. The class must be loadable and extend Zend_Controller_Front. |
| 'modules' | If this is the Boolean true value, the application support modules, and the modules are assumed to exist under the application home directory. If this is a string, array, or Zend_Config object, it maps one or more module names to their respective module directories, in the manner supported by the front controller's {{addModuleDirectory()}} method. |
| 'moduleConfigDirectoryName' | String names the directory for config files, under each module directory. Default is "config". |
| 'moduleControllerDirectoryName' | String names the directory for controllers, under each module directory. Default is "controllers". |
| 'moduleModelDirectoryName' | String names the directory for models, under each module directory. Default is "models". |
| 'params' | Array or Zend_Config object, maps parameter names to values, in the manner supported by the front controller's {{setParams()}} method. |
| 'resourcePluginClass' | String names the class to instantiate for processing module config files. |
| 'returnResponse' | Boolean; this is passed to the front controller's {{returnResponse()}} method. |
| 'routes' | Zend_Config object, contains a heirarchy of properties to declare routing rules for the front controller, in the manner supported by the rewrite router's {{addConfig()}} method. |
| 'saveResourcesInRegistry' | Boolean; this is passed to the Zend_Application_Resource class. Default is true. |
| 'throwExceptions' | Boolean; this is passed the the front controller's {{throwExceptions()}} method. |

If any other customization of the front controller is needed, the developer can call the Zend_Application {{getFrontController()}} method to return the front controller object.

h3. Creating Application Resources

Zend_Application includes a front controller plugin, called Zend_Application_Plugin. This plugin uses the proposed Zend_Application_Resource component. This component performs the following tasks prior to routing:
* Read each module's config file.
* Add all routes defined in the config files (this may supplement the routes defined in the front config file, or may be used instead of defining routes in the front config).

When a request is routed to a given module, additionally perform the following tasks:

* Store the config object loaded from the module config dir in the registry, under registry key 'config'.
* Instantiate resource classes declared in that config file.
* Store the resources in the registry.

If the current request is in a non-default module, the config object and the resources instantiated by Zend_Application_Resource are stored in a new Zend_Registry object, which is in turn stored in the registry. The key for the new registry is the name of the module. This is to avoid key conflicts if two modules use the same key name.

Thus if a module named "blog" loads resources based on the module's config file, code within the blog module can retrieve a resource from the registry-within-a-registry as follows:

{code}
$resource = Zend_Registry::get('blog')->get('resource-key');
{code}

{zone-data}

{zone-data:milestones}
Milestone 1: \[DONE\] Publish proposal.
Milestone 2: Revise proposal, approve for Incubator development.
Milestone 3: Commit working prototype to Incubator.
Milestone 4: Commit working unit tests.
Milestone 5: Write end-user documentation.
Milestone 6: Release prototype in incubator.
Milestone 7: Revise implementation, tests, and documentation based on feedback.
Milestone 8: Merge changes from Incubator to Core.
{zone-data}

{zone-data:class-list}
* Zend_Application
* Zend_Application_Plugin
* Zend_Application_Exception
* Zend_Application_Resource_FrontController
{zone-data}

{zone-data:use-cases}

|| UC01: Bootstrap a simple web application ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application';
$app = new Zend_Application($appHome);
$app->run();
{code}

|| UC02: Specify a base URL for requests ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application';

$config = array(
'baseUrl' => '/~user/application-root/'
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC03: Bootstrap script of web application with default module location ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application';

$config = array(
'modules' => true
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC04: Adding a custom module location ||

{code}
<?php

$appHome = dirname(dirname(__FILE__)) . '/application;
$config = array(
'modules' => '/path/to/modules'
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC05: Adding multiple custom module locations ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application;

$config = array(
'moduleControllerDir' => 'con',
'moduleConfigDir' => 'etc',
'modules' => array(
1 => '/path/to/modules',
2 => '/path/to/more/modules'
)
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC06: Adding custom controller locations ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application;

$config = array(
'controllers' => array(
'default' => '/path/to/application/controllers',
'blog' => '/path/to/application/blog/controllers',
)
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC07: Customizing the Front Controller ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application;

$config = array(
'params' => array(
'useDefaultControllerAlways' => true,
'noViewRenderer' => true
)
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC08: Declaring routes in an array ||

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application;

$config = array(
'routes' => array(
'user' => array(
'route' => 'user/:username',
'defaults' => array(
'controller' => 'user',
'action' => 'info'
),
'reqs' => array(
'username' => '\w+'
)
),
'login' => array(
'type' => 'Zend_Controller_Router_Route_Static',
'route' => 'login',
'defaults' => array(
'controller' => 'auth',
'action' => 'login'
)
)
)
);

$app = new Zend_Application($appHome, $config);
$app->run();
{code}

|| UC09: Declaring routes in a config file ||

front-config.ini:

{code}
[production]
routes.user.route = user/:username
routes.user.defaults.controller = user
routes.user.defaults.action = info
routes.user.reqs.username = "\w+"
routes.login.type = "Zend_Controller_Route_Router_Static"
routes.login.route = login
routes.login.defaults.controller = auth
routes.login.defaults.action = login
{code}

index.php:

{code}
<?php
$appHome = dirname(dirname(__FILE__)) . '/application;

$config = new Zend_Config_Ini("$appHome/app-config.ini", 'production');

$app = new Zend_Application($appHome, $config);
$app->run();
{code}
{zone-data}

{zone-data:skeletons}
See proof-of-concept code and unit tests in the Zend Framework Laboratory. Check it out using Subversion (http://framework.zend.com/svn/laboratory), or browse it online using FishEye (http://framework.zend.com/fisheye/browse/Zend_Framework_Laboratory/library/Zend).
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>