[GENERIC] Zend_Translate:
[zend.git] / documentation / manual / en / tutorials / plugins-usage.xml
blob48ccbcd03c8bc47775367e1d435005a502ea3224
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="learning.plugins.usage">
4     <title>Using Plugins</title>
6     <para>
7         Components that make use of plugins typically use
8         <classname>Zend_Loader_PluginLoader</classname> to do their work. This class has you
9         register plugins by specifying one or more "prefix paths". The component will then call the
10         PluginLoader's <methodname>load()</methodname> method, passing the plugin's short name to
11         it. The PluginLoader will then query each prefix path to see if a class matching that short
12         name exists. Prefix paths are searched in LIFO (last in, first out) order, so it will match
13         those prefix paths registered last first -- allowing you to override existing plugins.
14     </para>
16     <para>
17         Some examples will make all of this more clear.
18     </para>
20     <example id="learning.plugins.usage.basic">
21         <title>Basic Plugin Example: Adding a single prefix path</title>
23         <para>
24             In this example, we will assume some validators have been written and placed in the
25             directory <filename>foo/plugins/validators/</filename>, and that all these classes share
26             the class prefix "Foo_Validate_"; these two bits of information form our "prefix path".
27             Furthermore, let's assume we have two validators, one named "Even" (ensuring a number to
28             be validated is even), and another named "Dozens" (ensuring the number is a multiple of
29             12). The tree might look like this:
30         </para>
32         <programlisting language="text"><![CDATA[
33 foo/
34 |-- plugins/
35 |   |-- validators/
36 |   |   |-- Even.php
37 |   |   |-- Dozens.php
38 ]]></programlisting>
40         <para>
41             Now, we'll inform a <classname>Zend_Form_Element</classname> instance of this prefix
42             path. <classname>Zend_Form_Element</classname>'s
43             <methodname>addPrefixPath()</methodname> method expects a third argument that indicates
44             the type of plugin for which the path is being registered; in this case, it's a
45             "validate" plugin.
46         </para>
48         <programlisting language="php"><![CDATA[
49 $element->addPrefixPath('Foo_Validate', 'foo/plugins/validators/', 'validate');
50 ]]></programlisting>
52         <para>
53             Now we can simply tell the element the short name of the validators we want to use. In
54             the following example, we're using a mix of standard validators ("NotEmpty", "Int") and
55             custom validators ("Even", "Dozens"):
56         </para>
58         <programlisting language="php"><![CDATA[
59 $element->addValidator('NotEmpty')
60         ->addValidator('Int')
61         ->addValidator('Even')
62         ->addValidator('Dozens');
63 ]]></programlisting>
65         <para>
66             When the element needs to validate, it will then request the plugin class from the
67             PluginLoader. The first two validators will resolve to
68             <classname>Zend_Validate_NotEmpty</classname> and
69             <classname>Zend_Validate_Int</classname>, respectively; the next two will resolve to
70             <classname>Foo_Validate_Even</classname> and <classname>Foo_Validate_Dozens</classname>,
71             respectively.
72         </para>
73     </example>
75     <note>
76         <title>What happens if a plugin is not found?</title>
78         <para>
79             What happens if a plugin is requested, but the PluginLoader is unable to find a class
80             matching it? For instance, in the above example, if we registered the plugin "Bar" with
81             the element, what would happen?
82         </para>
84         <para>
85             The plugin loader will look through each prefix path, checking to see if a file matching
86             the plugin name is found on that path. If the file is not found, it then moves on to the
87             next prefix path.
88         </para>
90         <para>
91             Once the stack of prefix paths has been exhausted, if no matching file has been found,
92             it will throw a <exceptionname>Zend_Loader_PluginLoader_Exception</exceptionname>.
93         </para>
94     </note>
96     <example id="learning.plugins.usage.override">
97         <title>Intermediate Plugin Usage: Overriding existing plugins</title>
99         <para>
100             One strength of the PluginLoader is that its use of a LIFO stack allows you to override
101             existing plugins by creating your own versions locally with a different prefix path, and
102             registering that prefix path later in the stack.
103         </para>
105         <para>
106             For example, let's consider <classname>Zend_View_Helper_FormButton</classname> (view
107             helpers are one form of plugin). This view helper accepts three arguments, an element
108             name (also used as the element's DOM identifier), a value (used as the button label),
109             and an optional array of attributes. The helper then generates <acronym>HTML</acronym>
110             markup for a form input element.
111         </para>
113         <para>
114             Let's say you want the helper to instead generate a true <acronym>HTML</acronym>
115             <constant>button</constant> element; don't want the helper to generate a DOM identifier,
116             but instead use the value for a CSS class selector; and that you have no interest in
117             handling arbitrary attributes. You could accomplish this in a couple of ways. In both
118             cases, you'd create your own view helper class that implements the behavior you want;
119             the difference is in how you would name and invoke them.
120         </para>
122         <para>
123             Our first example will be to name the element with a unique name:
124             <classname>Foo_View_Helper_CssButton</classname>, which implies the plugin name
125             "CssButton". While this certainly is a viable approach, it poses several issues: if
126             you've already used the Button view helper in your code, you now have to refactor;
127             alternately, if another developer starts writing code for your application, they may
128             inadvertently use the Button view helper instead of your new view helper.
129         </para>
131         <para>
132             So, the better example is to use the plugin name "Button", giving us the class name
133             <classname>Foo_View_Helper_Button</classname>. We then register the prefix path with the
134             view:
135         </para>
137         <programlisting language="php"><![CDATA[
138 // Zend_View::addHelperPath() utilizes the PluginLoader; however, it inverts
139 // the arguments, as it provides a default value of "Zend_View_Helper" for the
140 // plugin prefix.
142 // The below assumes your class is in the directory 'foo/view/helpers/'.
143 $view->addHelperPath('foo/view/helpers', 'Foo_View_Helper');
144 ]]></programlisting>
146         <para>
147             Once done, anywhere you now use the "Button" helper will delegate to your custom
148             <classname>Foo_View_Helper_Button</classname> class!
149         </para>
150     </example>
151 </sect1>