TigerZF
🌐Español

71.2. Extender Zend_Tool

71.2.1. Resumen de Zend_Tool

Zend_Tool_Framework es un framework para exponer funcionalidades comunes tales como la creación de esqueletos de proyecto, generación de código, generación de índices de búsqueda, y mucho más. Se puede escribir y exponer funcionalidad a través de clases de PHP colocadas en el include_path de PHP, proporcionando una increíble flexibilidad de implementación. La funcionalidad puede entonces ser consumida escribiendo clientes específicos de implementación y/o protocolo -- tales como clientes de consola, XML-RPC, SOAP, y mucho más.

Zend_Tool_Project se construye sobre y extiende las capacidades de Zend_Tool_Framework hacia la de gestionar un "proyecto". En general, un "proyecto" es un esfuerzo planificado o una iniciativa. En el mundo de la informática, los proyectos generalmente son una colección de recursos. Estos recursos pueden ser archivos, directorios, bases de datos, esquemas, imágenes, estilos, y más.

71.2.2. Extensiones de Zend_Tool_Framework

71.2.2.1. Arquitectura general

Zend_Tool_Framework proporciona lo siguiente:

  • Interfaces y abstracciones comunes que permiten a los desarrolladores crear funcionalidad y capacidades que son despachables por los clientes de herramientas.

  • Funcionalidad base de cliente y una implementación concreta de consola que conecta herramientas externas e interfaces con Zend_Tool_Framework. El cliente de consola puede usarse en entornos de CLI tales como shells de unix y la consola de Windows.

  • Interfaces "Provider" y "Manifest" que pueden ser utilizadas por el sistema de herramientas. Los "Providers" representan el aspecto funcional del framework, y definen las acciones que los clientes de herramientas pueden llamar. Los "Manifests" actúan como registros de metadatos que proporcionan contexto adicional para los distintos providers definidos.

  • Un sistema de carga introspectivo que explorará el entorno en busca de providers y determinará lo que se requiere para despacharlos.

  • Un conjunto estándar de providers de sistema que permite al sistema reportar cuáles son las capacidades completas del sistema, además de proporcionar información útil. Esto también incluye un "Sistema de Ayuda" completo.

Definiciones que debe conocer a lo largo de este manual con respecto a Zend_Tool_Framework:

  • Zend_Tool_Framework - El framework que expone las capacidades de herramientas.

  • Cliente de herramientas - Una herramienta de desarrollador que se conecta a y consume Zend_Tool_Framework.

  • Cliente - El subsistema de Zend_Tool_Framework que expone una interfaz de tal manera que los clientes de herramientas puedan conectarse, consultar y ejecutar comandos.

  • Cliente de Consola / Interfaz de línea de comandos / zf.php - El cliente de herramientas para la línea de comandos.

  • Provider - Un subsistema y una colección de funcionalidad incorporada que el framework exporta.

  • Manifest - Un subsistema para definir, organizar, y difundir los datos de requisitos de los providers.

  • Provider de Zend_Tool_Project - Un conjunto de providers específicamente para crear y mantener proyectos basados en Zend Framework.

71.2.2.2. Entender el cliente CLI

El CLI, o herramienta de línea de comandos (conocida internamente como la herramienta de consola), es actualmente la interfaz principal para despachar solicitudes de Zend_Tool. Con la herramienta CLI, los desarrolladores pueden emitir solicitudes de herramientas dentro de la "ventana de línea de comandos", también conocida comúnmente como una ventana "terminal". Este entorno predomina en el entorno *nix, pero también tiene una implementación común en windows con cmd.exe, console2 y también con el proyecto Cygwin.

71.2.2.2.1. Configurar la herramienta CLI

Para emitir solicitudes de herramientas a través del cliente de línea de comandos, primero necesita configurar el cliente de manera que su sistema pueda manejar el comando "zf". El cliente de línea de comandos, para todos los propósitos, es el archivo .sh o .bat que se proporciona con su distribución de Zend Framework. En trunk, se puede encontrar aquí: http://framework.zend.com/svn/framework/standard/trunk/bin/.

Como puede ver, hay 3 archivos en el directorio /bin/: un zf.php, zf.sh, y zf.bat. El zf.sh y el zf.bat son los wrappers de cliente específicos del sistema operativo: zf.sh para el entorno *nix, y zf.bat para el entorno Win32. Estos wrappers de cliente son responsables de encontrar el php.exe apropiado, encontrar el zf.php, y pasar la solicitud del cliente. El zf.php es el responsable de entender su entorno, construir el include_path apropiado, y pasar lo que se proporciona en la línea de comandos al componente de biblioteca apropiado para el despacho.

En última instancia, quiere asegurar dos cosas para hacer que todo funcione sin importar en qué sistema operativo se encuentre:

  1. zf.sh/zf.bat es alcanzable desde el path de su sistema. Esta es la capacidad de invocar zf desde cualquier lugar en su línea de comandos, sin importar cuál sea su directorio de trabajo actual.

  2. ZendFramework/library está en su include_path.

[Note] Nota

Nota: aunque lo anterior son los requisitos más ideales, simplemente puede descargar Zend Framework y esperar que funcione como ./path/to/zf.php algún comando.

71.2.2.2.2. Configurar la herramienta CLI en sistemas tipo Unix

La configuración más común en el entorno *nix es copiar zf.sh y zf.php en el mismo directorio que su binario de PHP. Este generalmente se puede encontrar en uno de los siguientes lugares:

/usr/bin
/usr/local/bin
/usr/local/ZendServer/bin/
/Applications/ZendServer/bin/

Para averiguar la ubicación de su binario de PHP, puede ejecutar 'which php' en la línea de comandos. Esto devolverá la ubicación del binario de PHP que utilizará para ejecutar scripts de PHP en este entorno.

El siguiente asunto a atender es asegurar que la biblioteca de Zend Framework esté correctamente configurada dentro del include_path del sistema PHP. Para averiguar dónde está ubicado su include_path, puede ejecutar php -i y buscar la variable include_path, o más sucintamente, ejecutar php -i | grep include_path. Una vez que haya encontrado dónde está ubicado su include_path (esto generalmente será algo como /usr/lib/php, /usr/share/php, /usr/local/lib/php, o similar), asegúrese de que el contenido del directorio /library/ se coloque dentro del directorio especificado por su include_path.

Una vez que haya hecho esas dos cosas, debería poder emitir un comando y obtener la respuesta apropiada como esta:

Si no ve este tipo de salida, vuelva atrás y verifique su configuración para asegurarse de que tiene todas las piezas necesarias en el lugar apropiado.

Hay un par de configuraciones alternativas que podría querer emplear dependiendo de la configuración de sus servidores, su nivel de acceso, o por otras razones.

La configuración alternativa implica mantener la descarga de Zend Framework junta tal como está, y crear un enlace desde una ubicación de PATH hacia el zf.sh. Lo que esto significa es que puede colocar el contenido de la descarga de ZendFramework en una ubicación como /usr/local/share/ZendFramework, o de forma más local como /home/username/lib/ZendFramework, y crear un enlace simbólico al zf.sh.

Suponiendo que quiere colocar el enlace dentro de /usr/local/bin (esto también podría funcionar para colocar el enlace dentro de /home/username/bin/ por ejemplo) emitiría un comando similar a este:

ln -s /usr/local/share/ZendFramework/bin/zf.sh /usr/local/bin/zf

# OR (for example)
ln -s /home/username/lib/ZendFramework/bin/zf.sh /home/username/bin/zf

Esto creará un enlace al cual debería poder acceder globalmente en la línea de comandos.

71.2.2.2.3. Configurar la herramienta CLI en Windows

La configuración más común en el entorno Windows Win32 es copiar zf.bat y zf.php en el mismo directorio que su binario de PHP. Este generalmente se puede encontrar en uno de los siguientes lugares:

C:\PHP
C:\Program Files\ZendServer\bin\
C:\WAMP\PHP\bin

Debería poder ejecutar php.exe en la línea de comandos. Si no puede, primero revise la documentación que vino con su distribución de PHP, o asegúrese de que la ruta a php.exe esté en su variable de entorno PATH de Windows.

El siguiente asunto a atender es asegurar que la biblioteca de Zend Framework esté correctamente configurada dentro del include_path del sistema PHP. Para averiguar dónde está ubicado su include_path, puede escribir php -i y buscar la variable include_path, o más sucintamente ejecutar php -i | grep include_path si tiene Cygwin configurado con grep disponible. Una vez que haya encontrado dónde está ubicado su include_path (esto generalmente será algo como C:\PHP\pear, C:\PHP\share, C:\Program%20Files\ZendServer\share o similar), asegúrese de que el contenido del directorio library/ se coloque dentro de su directorio especificado por include_path.

Una vez que haya hecho esas dos cosas, debería poder emitir un comando y obtener la respuesta apropiada como esta:

Si no ve este tipo de salida, vuelva atrás y verifique su configuración para asegurarse de que tiene todas las piezas necesarias en el lugar apropiado.

Hay un par de configuraciones alternativas que podría querer emplear dependiendo de la configuración de su servidor, su nivel de acceso, o por otras razones.

La configuración alternativa implica mantener la descarga de Zend Framework junta tal como está, y alterar tanto su PATH del sistema como el archivo php.ini. En el entorno de su usuario, asegúrese de agregar C:\Path\To\ZendFramework\bin, de manera que su archivo zf.bat sea ejecutable. Además, altere el archivo php.ini para asegurarse de que C:\Path\To\ZendFramework\library esté en su include_path.

71.2.2.2.4. Otras consideraciones de configuración

Si por alguna razón no quiere la biblioteca de Zend Framework dentro de su include_path, hay otra opción. Hay dos variables de entorno especiales que zf.php va a utilizar para determinar la ubicación de su instalación de Zend Framework.

La primera es ZEND_TOOL_INCLUDE_PATH_PREPEND, que va a anteponer el valor de esta variable de entorno al include_path del sistema (php.ini) antes de cargar el cliente.

Alternativamente, podría querer usar ZEND_TOOL_INCLUDE_PATH para reemplazar completamente el include_path del sistema por uno que tenga sentido específicamente para la herramienta de línea de comandos zf.

71.2.2.3. Crear providers

En general, un provider, por sí solo, no es más que el armazón para que un desarrollador empaquete algunas capacidades que desea despachar con la línea de comandos (u otros) clientes. Es un análogo de lo que es un "controller" dentro de su aplicación MVC.

71.2.2.3.1. Cómo Zend_Tool encuentra sus providers

Por defecto Zend_Tool usa el BasicLoader para encontrar todos los providers que puede ejecutar. Itera recursivamente todos los directorios del include path y abre todos los archivos que terminen con "Manifest.php" o "Provider.php". Todas las clases en estos archivos son inspeccionadas para ver si implementan Zend_Tool_Framework_Provider_Interface o Zend_Tool_Framework_Manifest_ProviderManifestable. Las instancias de la interfaz provider constituyen la funcionalidad real y todos sus métodos públicos son accesibles como acciones del provider. La interfaz ProviderManifestable, sin embargo, requiere la implementación de un método getProviders() que devuelve un array de instancias de la interfaz provider ya instanciadas.

Las siguientes reglas de nomenclatura aplican en cuanto a cómo puede acceder a los providers que fueron encontrados por el IncludePathLoader:

  • La última parte de su nombre de clase dividido por guion bajo se usa para el nombre del provider, por ejemplo "My_Provider_Hello" hace que su provider sea accesible con el nombre "hello".

  • Si su provider tiene un método getName() este se usará en lugar del método anterior para determinar el nombre.

  • Si su provider tiene "Provider" como prefijo, por ejemplo se llama My_HelloProvider, será eliminado del nombre de manera que el provider se llamará "hello".

[Note] Nota

El IncludePathLoader no sigue enlaces simbólicos, lo que significa que no puede enlazar funcionalidad de providers en sus include paths, tienen que estar físicamente presentes en los include paths.

Ejemplo 71.1. Exponer sus providers con un Manifest

Puede exponer sus providers a Zend_Tool ofreciendo un manifest con un nombre de archivo especial que termine en "Manifest.php". Un Provider Manifest es una implementación de Zend_Tool_Framework_Manifest_ProviderManifestable y requiere que el método getProviders() devuelva un array de providers instanciados. En anticipación a nuestro primer provider propio My_Component_HelloProvider crearemos el siguiente manifest:

class My_Component_Manifest
    implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
    public function getProviders()
    {
        return array(
            new My_Component_HelloProvider()
        );
    }
}

71.2.2.3.2. Instrucciones básicas para crear providers

Como ejemplo, si un desarrollador quiere agregar la capacidad de mostrar la versión de un archivo de datos con el que trabaja su componente de terceros, solo hay una clase que el desarrollador necesitaría implementar. Suponiendo que el componente se llama My_Component, crearía una clase llamada My_Component_HelloProvider en un archivo llamado HelloProvider.php en algún lugar del include_path. Esta clase implementaría Zend_Tool_Framework_Provider_Interface, y el cuerpo de este archivo solo tendría que verse como lo siguiente:

class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say()
    {
        echo 'Hello from my provider!';
    }
}

Dado el código anterior, y suponiendo que el desarrollador desea acceder a esta funcionalidad a través del cliente de consola, la llamada se vería así:

% zf say hello
Hello from my provider!
71.2.2.3.3. El objeto response

Como se comentó en la sección de arquitectura, Zend_Tool permite conectar diferentes clientes para usar sus providers de Zend_Tool. Para mantenerse compatible con diferentes clientes debería usar el objeto response para devolver mensajes desde sus providers en lugar de usar echo() o un mecanismo de salida similar. Reescribiendo nuestro provider hello con este conocimiento se ve así:

class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $this->_registry
             ->getResponse()
             ->appendContent("Hello from my provider!");
    }
}

Como puede ver, uno tiene que extender Zend_Tool_Framework_Provider_Abstract para ganar acceso a el Registry que contiene la instancia de Zend_Tool_Framework_Client_Response.

71.2.2.3.4. Información avanzada de desarrollo
71.2.2.3.4.1. Pasar variables a un provider

El ejemplo anterior de "Hello World" es excelente para comandos simples, pero ¿qué pasa con algo más avanzado? A medida que crecen sus necesidades de scripting y herramientas, podría descubrir que necesita la capacidad de aceptar variables. Así como las firmas de funciones tienen parámetros, sus solicitudes de herramientas también pueden aceptar parámetros.

Así como cada solicitud de herramienta puede aislarse en un método dentro de una clase, los parámetros de una solicitud de herramienta también pueden aislarse en un lugar muy conocido. Los parámetros de los métodos de acción de un provider pueden incluir los mismos parámetros que quiere que su cliente utilice al invocar esa combinación de provider y acción. Por ejemplo, si quisiera aceptar un nombre en el ejemplo anterior, probablemente haría esto en código OO:

class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say($name = 'Ralph')
    {
        echo 'Hello' . $name . ', from my provider!';
    }
}

El ejemplo anterior puede entonces invocarse a través de la línea de comandos zf say hello Joe. "Joe" será suministrado al provider como un parámetro de la llamada al método. Además note, como puede ver, que el parámetro es opcional, lo que significa que también es opcional en la línea de comandos, de manera que zf say hello seguirá funcionando, y por defecto usará el nombre "Ralph".

71.2.2.3.4.2. Solicitar entrada al usuario

Hay casos en los que el flujo de trabajo de su provider requiere solicitar entrada al usuario. Esto puede hacerse pidiendo al cliente que pida más de la entrada requerida invocando:

class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say($name = 'Ralph')
    {
        $nameResponse = $this->_registry
                             ->getClient()
                             ->promptInteractiveInput("Whats your name?");
        $name = $nameResponse->getContent();

        echo 'Hello' . $name . ', from my provider!';
    }
}

Este comando lanza una excepción si el cliente actual no es capaz de manejar solicitudes interactivas. En el caso del Console Client por defecto, sin embargo, se le pedirá que introduzca el nombre.

71.2.2.3.4.3. Simular la ejecución de una acción de provider

Otra característica interesante que podría desear implementar es la capacidad de simulación (pretendability). La capacidad de simulación es la habilidad de que su provider "simule" que está realizando la combinación solicitada de acción y provider y le dé al usuario tanta información como sea posible sobre lo que haría sin realmente hacerlo. Esto podría ser una noción importante cuando se realizan modificaciones intensivas de base de datos o del sistema de archivos que el usuario podría no querer hacer de otro modo.

La capacidad de simulación es fácil de implementar. Hay dos partes en esta característica: 1) marcar el provider como con capacidad de "simular", y 2) verificar la solicitud para asegurarse de que la solicitud actual efectivamente se pidió que fuera "simulada". Esta característica se demuestra en el ejemplo de código a continuación.

class My_Component_HelloProvider
    extends    Zend_Tool_Framework_Provider_Abstract
    implements Zend_Tool_Framework_Provider_Pretendable
{
    public function say($name = 'Ralph')
    {
        if ($this->_registry->getRequest()->isPretend()) {
            echo 'I would say hello to ' . $name . '.';
        } else {
            echo 'Hello' . $name . ', from my provider!';
        }
    }
}

Para ejecutar el provider en modo de simulación simplemente llame a:

% zf --pretend say hello Ralph
I would say hello Ralph.
71.2.2.3.4.4. Modos verbose y debug

También puede ejecutar las acciones de su provider en modos "verbose" o "debug". La semántica con respecto a estas acciones tiene que ser implementada por usted en el contexto de su provider. Puede acceder a los modos debug o verbose con:

class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say($name = 'Ralph')
    {
        if($this->_registry->getRequest()->isVerbose()) {
            echo "Hello::say has been called\n";
        }
        if($this->_registry->getRequest()->isDebug()) {
            syslog(LOG_INFO, "Hello::say has been called\n");
        }
    }
}
71.2.2.3.4.5. Acceder a la configuración de usuario y al almacenamiento

Usando la variable de entorno ZF_CONFIG_FILE o el .zf.ini en su directorio home puede inyectar parámetros de configuración en cualquier provider de Zend_Tool. El acceso a esta configuración está disponible a través del registry que se pasa a su provider si extiende Zend_Tool_Framework_Provider_Abstract.

class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $username = $this->_registry->getConfig()->username;
        if(!empty($username)) {
            echo "Hello $username!";
        } else {
            echo "Hello!";
        }
    }
}

La configuración devuelta es del tipo Zend_Tool_Framework_Client_Config pero internamente los métodos mágicos __get() y __set() actúan como proxy hacia un Zend_Config del tipo de configuración dado.

El almacenamiento permite guardar datos arbitrarios para referencia posterior. Esto puede ser útil para tareas de procesamiento por lotes o para reejecuciones de sus tareas. Puede acceder al almacenamiento de manera similar a la configuración:

class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $aValue = $this->_registry->getStorage()->get("myUsername");
        echo "Hello $aValue!";
    }
}

La API del almacenamiento es muy simple:

class Zend_Tool_Framework_Client_Storage
{
    public function setAdapter($adapter);
    public function isEnabled();
    public function put($name, $value);
    public function get($name, $defaultValue=null);
    public function has($name);
    public function remove($name);
    public function getStreamUri($name);
}
[Important] Importante

Al diseñar sus providers que sean conscientes de la configuración o el almacenamiento, recuerde verificar si las claves de configuración de usuario o almacenamiento requeridas realmente existen para un usuario. No se encontrará con errores fatales cuando ninguna de estas se proporcione, ya que se crean unas vacías cuando se solicitan.

71.2.3. Extensiones de Zend_Tool_Project

Zend_Tool_Project expone un rico conjunto de funcionalidad y capacidades que hacen que la tarea de crear nuevos providers, específicamente aquellos dirigidos a proyectos, sea más fácil y manejable.

71.2.3.1. Arquitectura general

Este mismo concepto se aplica a los proyectos de Zend Framework. En los proyectos de Zend Framework, tiene controllers, actions, views, models, bases de datos y demás. En términos de Zend_Tool, necesitamos una manera de rastrear estos tipos de recursos - de ahí Zend_Tool_Project.

Zend_Tool_Project es capaz de rastrear los recursos de un proyecto a lo largo del desarrollo de un proyecto. Así, por ejemplo, si en un comando creó un controller, y en el siguiente comando desea crear una action dentro de ese controller, Zend_Tool_Project va a tener que saber sobre el archivo controller que creó para que pueda (en la siguiente acción) agregar esa action al mismo. Esto es lo que mantiene nuestros proyectos actualizados y con estado.

Otro punto importante para entender sobre los proyectos es que, típicamente, los recursos se organizan de forma jerárquica. Con esto en mente, Zend_Tool_Project es capaz de serializar el proyecto actual en una representación interna que le permite hacer seguimiento no solo de qué recursos son parte de un proyecto en un momento dado, sino también dónde están en relación entre sí.

71.2.3.2. Crear providers

Los providers específicos de proyecto se crean de la misma manera que los providers de framework simples, con una excepción: los providers de proyecto deben extender Zend_Tool_Project_Provider_Abstract. Esta clase viene con funcionalidad significativa que ayuda a los desarrolladores a cargar el proyecto existente, obtener el objeto profile, y poder buscar en el profile, y luego almacenar cualquier cambio en el profile del proyecto actual.

class My_Component_HelloProvider
    extends Zend_Tool_Project_Provider_Abstract
{
    public function say()
    {
        $profile = $this->_loadExistingProfile();

        /* ... do project stuff here */

        $this->_storeProfile();
    }
}