1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="learning.plugins.usage">
4 <title>Using Plugins</title>
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.
17 Some examples will make all of this more clear.
20 <example id="learning.plugins.usage.basic">
21 <title>Basic Plugin Example: Adding a single prefix path</title>
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:
32 <programlisting language="text"><![CDATA[
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
48 <programlisting language="php"><![CDATA[
49 $element->addPrefixPath('Foo_Validate', 'foo/plugins/validators/', 'validate');
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"):
58 <programlisting language="php"><![CDATA[
59 $element->addValidator('NotEmpty')
61 ->addValidator('Even')
62 ->addValidator('Dozens');
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>,
76 <title>What happens if a plugin is not found?</title>
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?
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
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>.
96 <example id="learning.plugins.usage.override">
97 <title>Intermediate Plugin Usage: Overriding existing plugins</title>
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.
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.
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.
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.
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
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
142 // The below assumes your class is in the directory 'foo/view/helpers/'.
143 $view->addHelperPath('foo/view/helpers', 'Foo_View_Helper');
147 Once done, anywhere you now use the "Button" helper will delegate to your custom
148 <classname>Foo_View_Helper_Button</classname> class!