Conseguir que una aplicación MVC quede configurada y lista para despachar ha requerido una cantidad de código cada vez mayor a medida que se dispone de más funcionalidades: configurar la base de datos, configurar la vista y los helpers de vista, configurar los layouts, registrar plugins, registrar helpers de acción, y más.
Además, a menudo querrá reutilizar el mismo código para arrancar sus pruebas, un cronjob o un script de servicio. Aunque es posible simplemente incluir su script de arranque, con frecuencia hay inicializaciones específicas del entorno: puede que no necesite el MVC para un cronjob, o solo la capa de base de datos para un script de servicio.
Zend_Application pretende facilitar esto y
fomentar la reutilización encapsulando el arranque en paradigmas OOP.
Zend_Application se divide en tres ámbitos:
Zend_Application: carga el entorno PHP, incluyendo los include_paths y la autocarga, e instancia la clase de arranque solicitada.Zend_Application_Bootstrap: proporciona interfaces para las clases de arranque.Zend_Application_Bootstrap_Bootstrapproporciona funcionalidad común para la mayoría de las necesidades de arranque, incluyendo algoritmos de comprobación de dependencias y la capacidad de cargar recursos de arranque bajo demanda.Zend_Application_Resourceproporciona una interfaz para los recursos de arranque estándar que pueden ser cargados bajo demanda por una instancia de arranque, así como varias implementaciones de recursos por defecto.
Los desarrolladores crean una clase de arranque para su aplicación, extendiendo
Zend_Application_Bootstrap_Bootstrap o implementando (como mínimo)
Zend_Application_Bootstrap_Bootstrapper. El punto de entrada
(por ejemplo, public/index.php) cargará
Zend_Application, y la instanciará pasando:
El entorno actual
Opciones para el arranque
Las opciones de arranque incluyen la ruta al archivo que contiene la clase de arranque y, opcionalmente:
Cualquier include_paths adicional a establecer
Cualquier namespace de autoloader adicional a registrar
Cualquier configuración de
php.inia inicializarEl nombre de clase para la clase de arranque (si no es "Bootstrap")
Pares de prefijo de recurso a ruta a utilizar
Cualquier recurso a utilizar (por nombre de clase o nombre corto)
Ruta adicional a un archivo de configuración a cargar
Opciones de configuración adicionales
Las opciones pueden ser un array, un objeto Zend_Config, o la ruta
a un archivo de configuración.
La segunda área de responsabilidad de Zend_Application es
ejecutar el arranque de la aplicación. Los arranques necesitan, como mínimo,
implementar Zend_Application_Bootstrap_Bootstrapper,
que define la siguiente API:
interface Zend_Application_Bootstrap_Bootstrapper
{
public function __construct($application);
public function setOptions(array $options);
public function getApplication();
public function getEnvironment();
public function getClassResources();
public function getClassResourceNames();
public function bootstrap($resource = null);
public function run();
}
Esta API permite que el arranque acepte el entorno y la configuración del objeto application, que reporte los recursos de los que es responsable de arrancar, y luego arranque y ejecute la aplicación.
Puede implementar esta interfaz por su cuenta, extender
Zend_Application_Bootstrap_BootstrapAbstract, o utilizar
Zend_Application_Bootstrap_Bootstrap.
Además de esta funcionalidad, hay una serie de otras áreas de interés con las que debería familiarizarse.
La implementación de Zend_Application_Bootstrap_BootstrapAbstract
proporciona una convención sencilla para definir métodos de
recurso de clase. Cualquier método protegido cuyo nombre comience con el prefijo
_init será considerado un método
de recurso.
Para arrancar un único método de recurso, use el
método bootstrap(), y páselo el nombre del
recurso. El nombre será el nombre del método menos el
prefijo _init.
Para arrancar varios métodos de recurso, pase un array de nombres. Para arrancar todos los métodos de recurso, no pase nada.
Tome la siguiente clase de arranque:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initFoo()
{
// ...
}
protected function _initBar()
{
// ...
}
protected function _initBaz()
{
// ...
}
}
Para arrancar únicamente el método _initFoo(), haga lo
siguiente:
$bootstrap->bootstrap('foo');
Para arrancar los métodos _initFoo() y
_initBar(), haga lo siguiente:
$bootstrap->bootstrap(array('foo', 'bar'));
Para arrancar todos los métodos de recurso, llame a bootstrap()
sin argumentos:
$bootstrap->bootstrap();
Para hacer sus arranques más reutilizables, hemos proporcionado la capacidad de trasladar sus recursos a clases de plugin de recurso. Esto permite mezclar y combinar recursos simplemente mediante configuración. Veremos cómo crear recursos más adelante; en esta sección mostraremos solo cómo utilizarlos.
Si su arranque debe ser capaz de usar plugins de recurso,
necesitará implementar una interfaz adicional,
Zend_Application_Bootstrap_ResourceBootstrapper.
Esta interfaz define una API para localizar, registrar y
cargar plugins de recurso:
interface Zend_Application_Bootstrap_ResourceBootstrapper
{
public function registerPluginResource($resource, $options = null);
public function unregisterPluginResource($resource);
public function hasPluginResource($resource);
public function getPluginResource($resource);
public function getPluginResources();
public function getPluginResourceNames();
public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader);
public function getPluginLoader();
}
Los plugins de recurso básicamente proporcionan la capacidad de crear inicializadores de recurso que pueden reutilizarse entre aplicaciones. Esto permite mantener su arranque real relativamente limpio, e introducir nuevos recursos sin necesidad de tocar el propio arranque.
Zend_Application_Bootstrap_BootstrapAbstract (y
Zend_Application_Bootstrap_Bootstrap por extensión)
también implementan esta interfaz, permitiéndole utilizar
plugins de recurso.
Para utilizar plugins de recurso, debe especificarlos en las
opciones pasadas al objeto application y/o al arranque. Estas
opciones pueden provenir de un archivo de configuración, o pasarse
manualmente. Las opciones serán pares de clave a opciones, siendo la clave
el nombre del recurso. El nombre del recurso será el segmento
que sigue al prefijo de clase. Por ejemplo, los recursos
incluidos con Zend Framework tienen el prefijo de clase
"Zend_Application_Resource_"; cualquier cosa que siga a esto sería
el nombre del recurso. Como ejemplo,
$application = new Zend_Application(APPLICATION_ENV, array(
'resources' => array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));
Esto indica que se debe utilizar el recurso "FrontController", con las opciones especificadas.
Si comienza a escribir sus propios plugins de recurso, o utiliza
plugins de recurso de terceros, necesitará indicar a su
arranque dónde buscarlos. Internamente, el arranque
utiliza Zend_Loader_PluginLoader, así que solo
necesitará indicar el prefijo de clase común y los pares de ruta.
Como ejemplo, supongamos que tiene plugins de recurso personalizados en
APPLICATION_PATH/resources/ y que comparten el
prefijo de clase común My_Resource. Entonces
pasaría esa información al objeto application de la siguiente manera:
$application = new Zend_Application(APPLICATION_ENV, array(
'pluginPaths' => array(
'My_Resource' => APPLICATION_PATH . '/resources/',
),
'resources' => array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));
Ahora podría usar recursos de ese directorio.
Al igual que con los métodos de recurso, se utiliza el método
bootstrap() para ejecutar los plugins de recurso. Al igual que con los
métodos de recurso, puede especificar un único plugin de recurso,
varios plugins (mediante un array), o todos los plugins. Además,
puede mezclar y combinar para ejecutar también métodos de recurso.
// Ejecutar uno:
$bootstrap->bootstrap('FrontController');
// Ejecutar varios:
$bootstrap->bootstrap(array('FrontController', 'Foo'));
// Ejecutar todos los métodos y plugins de recurso:
$bootstrap->bootstrap();
Muchos, si no todos, de sus métodos o plugins de recurso inicializarán objetos, y en muchos casos, estos objetos serán necesarios en otras partes de su aplicación. ¿Cómo puede acceder a ellos?
Zend_Application_Bootstrap_BootstrapAbstract
proporciona un registro local para estos objetos. Para almacenar sus
objetos en él, simplemente los devuelve desde sus recursos.
Para máxima flexibilidad, este registro se denomina internamente
"contenedor"; su único requisito es que sea un
objeto. Los recursos se registran entonces como propiedades nombradas según
el nombre del recurso. Por defecto, se utiliza una instancia de
Zend_Registry, pero también puede especificar cualquier
otro objeto que desee. Los métodos setContainer()
y getContainer() pueden utilizarse para manipular el
propio contenedor. getResource($resource) puede
utilizarse para obtener un recurso determinado del contenedor, y
hasResource($resource) para comprobar si el recurso
ha sido realmente registrado.
Como ejemplo, considere un recurso de vista básico:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initView()
{
$view = new Zend_View();
// más inicialización...
return $view;
}
}
Puede entonces comprobarlo y/u obtenerlo de la siguiente manera:
// Usando el par has/getResource():
if ($bootstrap->hasResource('view')) {
$view = $bootstrap->getResource('view');
}
// A través del contenedor:
$container = $bootstrap->getContainer();
if (isset($container->view)) {
$view = $container->view;
}
Tenga en cuenta que el registro, y también el contenedor, no son globales. Esto
significa que necesita acceso al arranque para poder obtener
recursos. Zend_Application_Bootstrap_Bootstrap
proporciona cierta comodidad para esto: durante su
ejecución de run(), se registra a sí mismo como el parámetro
"bootstrap" del controlador frontal, lo que le permite obtenerlo
desde el router, el dispatcher, los plugins y los controladores de acción.
Como ejemplo, si quisiera acceder al recurso de vista anterior desde su controlador de acción, podría hacer lo siguiente:
class FooController extends Zend_Controller_Action
{
public function init()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$view = $bootstrap->getResource('view');
// ...
}
}
Además de ejecutar métodos y plugins de recurso, es necesario asegurarse de que se ejecuten una única vez; están pensados para arrancar una aplicación, y ejecutarlos varias veces puede provocar sobrecarga de recursos.
Al mismo tiempo, algunos recursos pueden depender de que se hayan
ejecutado otros recursos. Para resolver estos dos problemas,
Zend_Application_Bootstrap_BootstrapAbstract
proporciona un mecanismo sencillo y efectivo de seguimiento
de dependencias.
Como se ha señalado anteriormente, todos los recursos -- ya sean métodos o plugins
-- se arrancan llamando a bootstrap($resource),
donde $resource es el nombre de un recurso, un array
de recursos, o, si se deja vacío, indica que deben ejecutarse todos los
recursos.
Si un recurso depende de otro recurso, debería llamar a
bootstrap() dentro de su código para asegurarse de que ese recurso
se ha ejecutado. Las llamadas posteriores serán entonces ignoradas.
En un método de recurso, una llamada así se vería de la siguiente manera:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initRequest()
{
// Asegurar que el controlador frontal está inicializado
$this->bootstrap('FrontController');
// Obtener el controlador frontal del registro de arranque
$front = $this->getResource('FrontController');
$request = new Zend_Controller_Request_Http();
$request->setBaseUrl('/foo');
$front->setRequest($request);
// Asegurar que la petición se almacena en el registro de arranque
return $request;
}
}
Como se ha señalado anteriormente, una buena manera de crear recursos de arranque reutilizables y de trasladar gran parte de su código a clases discretas es utilizar plugins de recurso. Aunque Zend Framework incluye una serie de plugins de recurso estándar, la intención es que los desarrolladores escriban los suyos propios para encapsular sus propias necesidades de inicialización.
Los plugins de recurso solo necesitan implementar
Zend_Application_Resource_Resource, o, de manera aún más
sencilla, extender
Zend_Application_Resource_ResourceAbstract. La interfaz
básica es simplemente esta:
interface Zend_Application_Resource_Resource
{
public function __construct($options = null);
public function setBootstrap(
Zend_Application_Bootstrap_Bootstrapper $bootstrap
);
public function getBootstrap();
public function setOptions(array $options);
public function getOptions();
public function init();
}
La interfaz define simplemente que un plugin de recurso debe aceptar opciones en el constructor, disponer de mecanismos para establecer y obtener opciones, disponer de mecanismos para establecer y obtener el objeto de arranque, y un método de inicialización.
Como ejemplo, supongamos que tiene una inicialización de vista común que utiliza en sus aplicaciones. Tiene un doctype, CSS y JavaScript comunes, y quiere poder pasar un título de documento base mediante configuración. Un plugin de recurso así podría ser como sigue:
class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
{
protected $_view;
public function init()
{
// Devolver la vista para que el arranque la almacene en el registro
return $this->getView();
}
public function getView()
{
if (null === $this->_view) {
$options = $this->getOptions();
$title = '';
if (array_key_exists('title', $options)) {
$title = $options['title'];
unset($options['title']);
}
$view = new Zend_View($options);
$view->doctype('XHTML1_STRICT');
$view->headTitle($title);
$view->headLink()->appendStylesheet('/css/site.css');
$view->headScript()->appendfile('/js/analytics.js');
$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer'
);
$viewRenderer->setView($view);
$this->_view = $view;
}
return $this->_view;
}
}
Mientras registre la ruta de prefijo para este plugin de recurso, podrá utilizarlo en su aplicación. Aún mejor, dado que usa el cargador de plugins, está efectivamente sobrescribiendo el plugin de recurso "View" incluido, asegurando que se utilice el suyo propio.