1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.loader.pluginloader">
<title>Chargeur de Plugins</title>
<para>
Zend Framework vous propose l'utilisation de composants "pluggables", que vous créez
vous même. Ceux-ci ne sont pas forcément dans l'include_path. De même, ils ne suivent pas
forcément les mêmes règles de nommage que les composants de Zend
Framework.<classname>Zend_Loader_PluginLoader</classname> propose une solution à ce
problème.
</para>
<para>
<code>PluginLoader</code> suit la convention "une classe par fichier" et les tirets
bas sont utilisés comme séparateurs de dossiers. Il accepte aussi qu'un préfixe optionnel
lui soit passé, afin de charger une classe. Tous les chemins sont analysés en ordre LIFO.
Grâce à ces deux spécificités, vous pouvez "namespacer" vos plugins, et écraser les plugins
enregistrés plus tôt.
</para>
<sect2 id="zend.loader.pluginloader.usage">
<title>Utilisation basique</title>
<para>
Même si nous parlons de "plugins", ce n'est pas réservé aux plugins de contrôleur
frontal, mais bien à toute classe étant utilisée avec Zend Framework. Imaginons une
structure de répertoires comme suit, dans laquelle les dossiers "application" et
"library" sont dans l'include_path :
</para>
<programlisting language="txt"><![CDATA[
application/
modules/
foo/
views/
helpers/
FormLabel.php
FormSubmit.php
bar/
views/
helpers/
FormSubmit.php
library/
Zend/
View/
Helper/
FormLabel.php
FormSubmit.php
FormText.php
]]></programlisting>
<para>
Maintenant créons un chargeur de plugins pour utiliser les différentes classes
d'aides de vue :
</para>
<programlisting language="php"><![CDATA[
$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');
]]></programlisting>
<para>
Il devient alors possible de charger une aide de vue en spécifiant juste le nom de
sa classe :
</para>
<programlisting language="php"><![CDATA[
// charge l'aide 'FormText' :
$formTextClass = $loader->load('FormText');
// 'Zend_View_Helper_FormText'
// charge l'aide 'FormLabel' :
$formLabelClass = $loader->load('FormLabel');
// 'Foo_View_Helper_FormLabel'
// charge l'aide 'FormSubmit' :
$formSubmitClass = $loader->load('FormSubmit');
// 'Bar_View_Helper_FormSubmit'
]]></programlisting>
<para>Une fois chargée, la classe devient instanciable.</para>
<note>
<title>Plusieurs dossiers peuvent être assignés à un même préfixe</title>
<para>
Vous pouvez "namespacer" vos composants en enregistrant plusieurs chemins pour
un même préfixe.<classname>Zend_Loader_PluginLoader</classname> cherchera alors en
ordre LIFO (dernier arrivé, premier sorti). Ceci est pratique pour court-circuiter
ses composants et utiliser ceux en incubateur, par exemple.
</para>
</note>
<note>
<title>Paramétrage des chemins dans le constructeur</title>
<para>
En constructeur, passez un tableau de paires prefix / path ou prefix / paths
-- plusieurs dossiers par préfixe :
</para>
<programlisting language="php"><![CDATA[
$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'
));
]]></programlisting>
</note>
<para>
<classname>Zend_Loader_PluginLoader</classname> peut aussi permettre de partager
des plugins grâce au registre. Indiquez le nom du registre de cette manière :
</para>
<programlisting language="php"><![CDATA[
// Stocke les plugins dans le registre à l'index 'foobar':
$loader = new Zend_Loader_PluginLoader(array(), 'foobar');
]]></programlisting>
<para>
Si un autre composant instancie le <code>PluginLoader</code> en utilisant le même
nom de registre, alors tous les chemins et plugins déjà chargés seront
disponibles.
</para>
</sect2>
<sect2 id="zend.loader.pluginloader.paths">
<title>Manipulation des chemins des Plugins</title>
<para>
Pour afficher ou supprimer des chemins déjà enregistrés, utilisez l'une des
méthodes suivantes :
</para>
<itemizedlist>
<listitem>
<para>
<methodname>getPaths($prefix = null)</methodname> retourne les chemin sous la forme
prefix / path si <varname>$prefix</varname> n'est pas renseigné. Sinon, ce sont les
chemins enregistrés pour le préfixe en question qui sont renvoyés.
</para>
</listitem>
<listitem>
<para>
<methodname>clearPaths($prefix = null)</methodname> va effacer tous les chemins. Si
<varname>$prefix</varname> est passé, ce sont les chemins correspondants à ce préfixe
qui seront supprimés.
</para>
</listitem>
<listitem>
<para>
<methodname>removePrefixPath($prefix, $path = null)</methodname> permet de supprimer
un chemin précis, d'un préfixe spécifié. Si <varname>$path</varname> n'est pas
renseigné, tous les chemins du préfixe seront effacés.
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="zend.loader.pluginloader.checks">
<title>Test des Plugins et récupération des noms de classe</title>
<para>
Lorsque vous voulez savoir si une classe de plugin a été chargée,
<methodname>isLoaded()</methodname> prend en paramètre le nom du plugin, et retourne sont
statut.
</para>
<para>
Une autre utilisation de <code>PluginLoader</code> peut être de récupérer le nom
des classes des plugins chargés.<methodname>getClassName()</methodname> vous le permet. Utilisée en
conjonction avec <methodname>isLoaded()</methodname>, vous pouvez écrire par exemple ceci :
</para>
<programlisting language="php"><![CDATA[
if ($loader->isLoaded('Adapter')) {
$class = $loader->getClassName('Adapter');
$adapter = call_user_func(array($class, 'getInstance'));
}
]]></programlisting>
</sect2>
<sect2 id="zend.loader.pluginloader.performance">
<title>Obtenir de meilleures performances avec les Plugins</title>
<para>
Le chargement des plugins peut être une opération consommatrice en ressources. En
interne, il doit parcourir chaque préfixe, ainsi que chaque chemin dans ce préfixe
jusqu'à ce qu'il trouve un fichier qui correspond - et qui définit de plus la classe
voulue. Dans le cas où le fichier existe mais ne défini pas la classe, une erreur sera
ajouté à la pile d'erreur <acronym>PHP</acronym>, opération qui est elle aussi consommatrice. La question
qui vient à l'esprit est : comment maintenir la flexibilité des plugins et la
performance ?
</para>
<para>
<classname>Zend_Loader_PluginLoader</classname> offre une fonctionnalité intégrée
pour ce cas, un fichier de cache des inclusions de classe. Quand il est activé, ceci
crée un fichier qui contient toutes les inclusions qui ont fonctionnées et qui peuvent
donc être appelées dans votre fichier d'initialisation. En utilisant ceci, vous pouvez
considérablement accroître les performances de vos serveurs de production.
</para>
<example id="zend.loader.pluginloader.performance.example">
<title>Utilisation du fichier de cache des inclusions de classe de
PluginLoader</title>
<para>
Pour utiliser le fichier de cache des inclusions de classe, collez simplement
le code suivant dans votre fichier d'initialisation :
</para>
<programlisting language="php"><![CDATA[
$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
]]></programlisting>
<para>
Évidemment, le chemin et le fichier varieront en fonction de vos besoins. Ce
code doit intervenir aussi vite que possible, pour s'assurer que tous les composants
à base de plugins pourront l'utiliser.
</para>
<para>
En cours du développement, vous pouvez souhaiter désactiver le cache. Une
méthode permettant ceci est d'utiliser une clé de configuration pour déterminer ou
non si le chargeur de plugins doit mettre les informations en cache.
</para>
<programlisting language="php"><![CDATA[
$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
if ($config->enablePluginLoaderCache) {
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
}
]]></programlisting>
<para>
Cette technique vous permet de restreindre les modifications au seul fichier
de configuration plutôt que dans votre code.
</para>
</example>
</sect2>
</sect1>
|