Debido a que los proveedores y manifiestos pueden provenir de cualquier lugar del include_path, se proporciona un registro para simplificar el acceso a las diversas piezas de la cadena de herramientas. Este registro se inyecta en los componentes que tienen conocimiento del registro, los cuales pueden luego extraer dependencias de ellos según sea necesario. La mayoría de las dependencias registradas con el registro serán repositorios específicos de subcomponentes.
La interfaz del registro consiste en la siguiente definición:
interface Zend_Tool_Framework_Registry_Interface
{
public function setClient(Zend_Tool_Framework_Client_Abstract $client);
public function getClient();
public function setLoader(Zend_Tool_Framework_Loader_Abstract $loader);
public function getLoader();
public function setActionRepository(
Zend_Tool_Framework_Action_Repository $actionRepository
);
public function getActionRepository();
public function setProviderRepository(
Zend_Tool_Framework_Provider_Repository $providerRepository
);
public function getProviderRepository();
public function setManifestRepository(
Zend_Tool_Framework_Manifest_Repository $manifestRepository
);
public function getManifestRepository();
public function setRequest(Zend_Tool_Framework_Client_Request $request);
public function getRequest();
public function setResponse(Zend_Tool_Framework_Client_Response $response);
public function getResponse();
}
Los diversos objetos que gestiona el registro se tratarán en sus secciones correspondientes.
Las clases que deban tener conocimiento del registro deben
implementar
Zend_Tool_Framework_Registry_EnabledInterface.
Esta interfaz simplemente permite la inicialización del registro
en la clase de destino.
interface Zend_Tool_Framework_Registry_EnabledInterface
{
public function setRegistry(
Zend_Tool_Framework_Registry_Interface $registry
);
}
Zend_Tool_Framework_Provider representa el
aspecto funcional o de "capacidad" del framework.
Fundamentalmente, Zend_Tool_Framework_Provider
proporcionará las interfaces necesarias para producir
"proveedores", o piezas de funcionalidad de herramientas que se
pueden invocar y usar dentro de la cadena de herramientas
Zend_Tool_Framework. La naturaleza
simplista de implementar esta interfaz de proveedor permite al
desarrollador un "punto único" para añadir funcionalidad o
capacidades a Zend_Tool_Framework.
La interfaz de proveedor es una interfaz vacía y no impone ningún método (este es el patrón de interfaz marcadora):
interface Zend_Tool_Framework_Provider_Interface
{}
O, si lo desea, puede implementar el Provider base (o
abstracto) que le dará acceso al
Zend_Tool_Framework_Registry:
abstract class Zend_Tool_Framework_Provider_Abstract
implements Zend_Tool_Framework_Provider_Interface,
Zend_Tool_Registry_EnabledInterface
{
protected $_registry;
public function setRegistry(
Zend_Tool_Framework_Registry_Interface $registry
);
}
El propósito de un Loader es encontrar Providers y archivos de
Manifest que contengan clases que implementen
Zend_Tool_Framework_Provider_Interface o
Zend_Tool_Framework_Manifest_Interface. Una
vez que un cargador encuentra estos archivos, los proveedores se
cargan en el Repositorio de Proveedores y los metadatos de
manifiesto se cargan en el Repositorio de Manifiestos.
Para implementar un cargador, se debe extender la siguiente clase abstracta:
abstract class Zend_Tool_Framework_Loader_Abstract
{
abstract protected function _getFiles();
public function load()
{
/** ... */
}
}
El método _getFiles() debe devolver un
array de archivos (rutas absolutas). El cargador integrado
suministrado con Zend Framework se llama cargador IncludePath.
Por defecto, el framework de herramientas utilizará un cargador
basado en include_path para encontrar archivos que podrían
incluir objetos Provider o Manifest Metadata.
Zend_Tool_Framework_Loader_IncludePathLoader,
sin ninguna otra opción, buscará archivos dentro del include
path que terminen en Mainfest.php,
Tool.php o
Provider.php. Una vez encontrados, se
comprobará (mediante el método
load() de
Zend_Tool_Framework_Loader_Abstract) si
implementan alguna de las interfaces soportadas. Si es así, se
instancia una instancia de la clase encontrada, y se añade al
repositorio correspondiente.
class Zend_Tool_Framework_Loader_IncludePathLoader
extends Zend_Tool_Framework_Loader_Abstract
{
protected $_filterDenyDirectoryPattern = '.*(/|\\\\).svn';
protected $_filterAcceptFilePattern = '.*(?:Manifest|Provider)\.php$';
protected function _getFiles()
{
/** ... */
}
}
Como puede ver, el cargador IncludePath buscará en todos los
include_paths los archivos que coincidan con
$_filterAcceptFilePattern y
no coincidan con
$_filterDenyDirectoryPattern.
En resumen, el Manifest contendrá metadatos específicos o arbitrarios que resulten útiles para cualquier proveedor o cliente, además de ser responsable de cargar cualquier proveedor adicional en el repositorio de proveedores.
Para introducir metadatos en el repositorio de manifiestos, todo
lo que se debe hacer es implementar la interfaz vacía
Zend_Tool_Framework_Manifest_Interface, y
proporcionar un método getMetadata() que
devuelva un array de objetos que implementen
Zend_Tool_Framework_Manifest_Metadata.
interface Zend_Tool_Framework_Manifest_Interface
{
public function getMetadata();
}
Los objetos de metadatos se cargan (mediante un cargador
definido más abajo) en el Repositorio de Manifiestos
(Zend_Tool_Framework_Manifest_Repository).
Los Manifests se procesarán después de que se hayan encontrado
y cargado todos los Providers en el repositorio de proveedores.
Esto permitirá que los Manifests creen objetos de Metadata
basados en lo que actualmente hay dentro del repositorio de
proveedores.
Existen algunas clases de metadatos diferentes que se pueden
usar para describir metadatos. La clase
Zend_Tool_Framework_Manifest_Metadata es el
objeto de metadatos base. Como se puede ver en el siguiente
fragmento de código, la clase de metadatos base es bastante
ligera y de naturaleza abstracta:
class Zend_Tool_Framework_Metadata_Basic
{
protected $_type = 'Global';
protected $_name = null;
protected $_value = null;
protected $_reference = null;
public function getType();
public function getName();
public function getValue();
public function getReference();
/** ... */
}
También hay otras clases de metadatos integradas para describir
metadatos más especializados: ActionMetadata
y ProviderMetadata. Estas clases le
ayudarán a describir con más detalle los metadatos específicos
de acciones o proveedores, y se espera que la referencia sea una
referencia a una acción o a un proveedor, respectivamente. Estas
clases se describen en el siguiente fragmento de código.
class Zend_Tool_Framework_Manifest_ActionMetadata
extends Zend_Tool_Framework_Manifest_Metadata
{
protected $_type = 'Action';
protected $_actionName = null;
public function getActionName();
/** ... */
}
class Zend_Tool_Framework_Manifest_ProviderMetadata
extends Zend_Tool_Framework_Manifest_Metadata
{
protected $_type = 'Provider';
protected $_providerName = null;
protected $_actionName = null;
protected $_specialtyName = null;
public function getProviderName();
public function getActionName();
public function getSpecialtyName();
/** ... */
}
El 'Type' en estas clases se utiliza para describir el tipo de
metadatos del que es responsable el objeto. En el caso de
ActionMetadata, el tipo sería 'Action', y,
a la inversa, en el caso de ProviderMetadata
el tipo es 'Provider'. Estos tipos de metadatos también
incluirán información estructurada adicional tanto sobre la
"cosa" que están describiendo como sobre el objeto (el
getReference()) al que hacen referencia con
estos nuevos metadatos.
Para crear su propio tipo de metadatos, todo lo que se debe
hacer es extender la clase base
Zend_Tool_Framework_Manifest_Metadata y
devolver estos nuevos objetos de metadatos a través de una clase
u objeto Manifest local. Estas clases basadas en el usuario
vivirán en el Repositorio de Manifiestos
Una vez que estos objetos de metadatos están en el repositorio, hay entonces dos métodos diferentes que se pueden usar para buscarlos en el repositorio.
class Zend_Tool_Framework_Manifest_Repository
{
/**
* To use this method to search, $searchProperties should contain the names
* and values of the key/value pairs you would like to match within the
* manifest.
*
* For Example:
* $manifestRepository->findMetadatas(array(
* 'action' => 'Foo',
* 'name' => 'cliActionName'
* ));
*
* Will find any metadata objects that have a key with name 'action' value
* of 'Foo', AND a key named 'name' value of 'cliActionName'
*
* Note: to either exclude or include name/value pairs that exist in the
* search criteria but do not appear in the object, pass a bool value to
* $includeNonExistentProperties
*/
public function findMetadatas(Array $searchProperties = array(),
$includeNonExistentProperties = true);
/**
* The following will return exactly one of the matching search criteria,
* regardless of how many have been returned. First one in the manifest is
* what will be returned.
*/
public function findMetadata(Array $searchProperties = array(),
$includeNonExistentProperties = true)
{
$metadatas = $this->getMetadatas($searchProperties,
$includeNonExistentProperties);
return array_shift($metadatas);
}
}
Observando los métodos de búsqueda anteriores, las firmas
permiten una búsqueda extremadamente flexible. Para encontrar un
objeto de metadatos, simplemente pase un array de restricciones
de coincidencia mediante un array. Si se puede acceder a los
datos a través del accesor de Propiedad (los métodos
getSomething() implementados en el objeto
de metadatos), entonces se devolverá al usuario como un objeto
de metadatos "encontrado".
Los Clients son la interfaz que conecta a un usuario o
herramienta externa con el sistema
Zend_Tool_Framework. Los Clients pueden
presentarse en todas las formas y tamaños: puntos finales
RPC, Interfaz de Línea de Comandos, o
incluso una interfaz web. Zend_Tool ha
implementado la interfaz de línea de comandos como la interfaz
predeterminada para interactuar con el sistema
Zend_Tool_Framework.
Para implementar un cliente, sería necesario extender la siguiente clase abstracta:
abstract class Zend_Tool_Framework_Client_Abstract
{
/**
* This method should be implemented by the client implementation to
* construct and set custom loaders, request and response objects.
*
* (not required, but suggested)
*/
protected function _preInit();
/**
* This method should be implemented by the client implementation to parse
* out and set up the request objects action, provider and parameter
* information.
*/
abstract protected function _preDispatch();
/**
* This method should be implemented by the client implementation to take
* the output of the response object and return it (in an client specific
* way) back to the Tooling Client.
*
* (not required, but suggested)
*/
abstract protected function _postDispatch();
}
Como puede ver, se requiere 1 método para satisfacer las necesidades de un cliente (se sugieren otros dos), la inicialización, el prehandling y el posthandling. Para un estudio más detallado de cómo funciona el cliente de línea de comandos, consulte el código fuente.