TigerZF
🌐Español

42.4. Carga de Plugins

Varios componentes de Zend Framework son enchufables (pluggable), y permiten la carga de funcionalidad dinámica especificando un prefijo de clase y una ruta a los archivos de clase que no necesariamente están en el include_path o no necesariamente siguen las convenciones de nomenclatura tradicionales. Zend_Loader_PluginLoader proporciona la funcionalidad común para este proceso.

El uso básico de PluginLoader sigue las convenciones de nomenclatura de Zend Framework de una clase por archivo, usando el guion bajo como separador de directorio al resolver rutas. Permite pasar un prefijo de clase opcional para anteponer al determinar si una clase de plugin concreta está cargada. Además, las rutas se buscan en orden LIFO. Debido a la búsqueda LIFO y a los prefijos de clase, esto le permite definir espacios de nombres para sus plugins, y así sobrescribir plugins de rutas registradas anteriormente.

42.4.1. Caso de uso básico

Primero, supongamos la siguiente estructura de directorios y archivos de clase, y que el directorio de nivel superior y el directorio de biblioteca están en el include_path:

application/
    modules/
        foo/
            views/
                helpers/
                    FormLabel.php
                    FormSubmit.php
        bar/
            views/
                helpers/
                    FormSubmit.php
library/
    Zend/
        View/
            Helper/
                FormLabel.php
                FormSubmit.php
                FormText.php

Ahora, creemos un cargador de plugins para abordar los diversos repositorios de view helper disponibles:

$loader = new Zend_Loader_PluginLoader();
$loader->addPrefixPath('Zend_View_Helper', 'Zend/View/Helper/')
       ->addPrefixPath('Foo_View_Helper',
                       'application/modules/foo/views/helpers')
       ->addPrefixPath('Bar_View_Helper',
                       'application/modules/bar/views/helpers');

Entonces podemos cargar un view helper dado usando solo la parte del nombre de clase que sigue a los prefijos según se definieron al añadir las rutas:

// load 'FormText' helper:
$formTextClass = $loader->load('FormText'); // 'Zend_View_Helper_FormText';

// load 'FormLabel' helper:
$formLabelClass = $loader->load('FormLabel'); // 'Foo_View_Helper_FormLabel'

// load 'FormSubmit' helper:
$formSubmitClass = $loader->load('FormSubmit'); // 'Bar_View_Helper_FormSubmit'

Una vez cargada la clase, ahora podemos instanciarla.

[Note] Nota

En algunos casos, puede usar el mismo prefijo para varias rutas. Zend_Loader_PluginLoader en realidad registra un array de rutas para cada prefijo dado; la última registrada será la primera comprobada. Esto es particularmente útil si está utilizando componentes del incubador (incubator).

[Note] Las rutas se pueden definir en la instanciación

Opcionalmente puede proporcionar un array de pares prefijo / ruta (o prefijo / rutas -- se permiten varias rutas) como parámetro para el constructor:

$loader = new Zend_Loader_PluginLoader(array(
    'Zend_View_Helper' => 'Zend/View/Helper/',
    'Foo_View_Helper'  => 'application/modules/foo/views/helpers',
    'Bar_View_Helper'  => 'application/modules/bar/views/helpers'
));

Zend_Loader_PluginLoader también le permite opcionalmente compartir plugins entre objetos que admiten plugins, sin necesidad de utilizar una instancia singleton. Lo hace a través de un registro estático. Indique el nombre del registro en la instanciación como segundo parámetro del constructor:

// Store plugins in static registry 'foobar':
$loader = new Zend_Loader_PluginLoader(array(), 'foobar');

Otros componentes que instancian el PluginLoader usando el mismo nombre de registro tendrán entonces acceso a las rutas y plugins ya cargados.

42.4.2. Manipulación de rutas de plugins

El ejemplo de la sección anterior muestra cómo añadir rutas a un cargador de plugins. ¿Qué pasa si desea determinar las rutas ya cargadas, o eliminar una o más?

  • getPaths($prefix = null) devuelve todas las rutas como pares prefijo / ruta si no se proporciona ningún $prefix, o solo las rutas registradas para un prefijo dado si un $prefix está presente.

  • clearPaths($prefix = null) eliminará todas las rutas registradas por defecto, o solo las asociadas con un prefijo dado, si el $prefix se proporciona y está presente en la pila.

  • removePrefixPath($prefix, $path = null) le permite eliminar selectivamente una ruta específica asociada con un prefijo dado. Si no se proporciona ningún $path, se eliminan todas las rutas para ese prefijo. Si se proporciona un $path y existe para ese prefijo, solo se eliminará esa ruta.

42.4.3. Comprobación de plugins y obtención de nombres de clase

A veces simplemente desea determinar si una clase de plugin ha sido cargada antes de realizar una acción. isLoaded() toma un nombre de plugin, y devuelve el estado.

Otro caso de uso común para PluginLoader es determinar los nombres de clase de plugin completamente calificados de las clases cargadas; getClassName() proporciona esta funcionalidad. Normalmente, esto se usaría junto con isLoaded():

if ($loader->isLoaded('Adapter')) {
    $class   = $loader->getClassName('Adapter');
    $adapter = call_user_func(array($class, 'getInstance'));
}

42.4.4. Cómo obtener mejor rendimiento para los plugins

La carga de plugins puede ser una operación costosa. En esencia, necesita recorrer en bucle cada prefijo, y luego cada ruta del prefijo, hasta que encuentra un archivo que coincide -- y que define la clase esperada. En los casos en que el archivo existe pero no define la clase, se añadirá un error a la pila de errores de PHP, lo cual también es una operación costosa. La pregunta entonces es: ¿cómo puede mantener la flexibilidad de los plugins y también abordar el rendimiento?

Zend_Loader_PluginLoader ofrece una característica opcional para precisamente esta situación, una caché de inclusión de archivos de clase. Cuando está habilitada, creará un archivo que contiene todas las inclusiones exitosas, que puede invocar desde su bootstrap. Usando esta estrategia, puede mejorar considerablemente el rendimiento de sus servidores de producción.

Ejemplo 42.6. Uso de la caché de inclusión de archivos de clase de PluginLoader

Para usar la caché de inclusión de archivos de clase, simplemente inserte el siguiente código en su bootstrap:

$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
    include_once $classFileIncCache;
}
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);

Obviamente, la ruta y el nombre de archivo variarán según sus necesidades. Este código debe aparecer lo antes posible, para asegurar que los componentes basados en plugins puedan hacer uso de él.

Durante el desarrollo, puede que desee deshabilitar la caché. Un método para hacerlo es usar una clave de configuración para determinar si el cargador de plugins debe cachear o no.

$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
    include_once $classFileIncCache;
}
if ($config->enablePluginLoaderCache) {
    Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
}

Esta técnica le permite mantener sus modificaciones en su archivo de configuración en lugar de en el código.