svn: /pear/peardoc/trunk/en/package/html/ html-quickform2/rules.xml html-quickform2.xml

[email protected] (Alexey Borzov) Sat, 12 Mar 2011 12:02:38 +0000
Newsgroups php.pear.doc
Message-ID <[email protected]>
avb                                      Sat, 12 Mar 2011 12:02:38 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=309133

Log:
Validation in QF2

Changed paths:
    A   pear/peardoc/trunk/en/package/html/html-quickform2/rules.xml
    U   pear/peardoc/trunk/en/package/html/html-quickform2.xml
svn-diffs-309133.txt (text/x-diff, 25.1 KB)
Added: pear/peardoc/trunk/en/package/html/html-quickform2/rules.xml
===================================================================
--- pear/peardoc/trunk/en/package/html/html-quickform2/rules.xml	                        (rev 0)
+++ pear/peardoc/trunk/en/package/html/html-quickform2/rules.xml	2011-03-12 12:02:38 UTC (rev 309133)
@@ -0,0 +1,550 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry
+ xmlns="http://docbook.org/ns/docbook"
+ xmlns:phd="http://www.php.net/ns/phd"
+ version="lillet"
+ xml:id="package.html.html-quickform2.rules"
+>
+ <refnamediv>
+  <refname>Rules and validation</refname>
+  <refpurpose>Checking that you get the values you need</refpurpose>
+ </refnamediv>
+ <refsection xml:id="package.html.html-quickform2.rules.intro">
+  <info>
+   <title>Introduction</title>
+  </info>
+  <para>
+   Server-side validation in HTML_QuickForm2 is performed by <phd:pearapi
+    phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2::validate" /> method. Validation
+   rules doing actual checks on element values are implemented as subclasses of <phd:pearapi
+    phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule" />, they are added to
+   elements via <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Node::addRule" />.
+  </para>
+  <para>
+   Basically, the form is invalid if it contains at least one invalid element. The element is
+   considered invalid if it has an error message (accessible by <phd:pearapi
+    phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Node::getError" />) set and valid
+   otherwise. That error can appear in two different ways:
+   <itemizedlist>
+    <listitem><simpara>You can manually set an error message for an element using <phd:pearapi
+     phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Node::setError"
+    />.</simpara></listitem>
+    <listitem><simpara>A rule added to the element will set an error message if it has such a message
+     and its validation routine returned &false;.</simpara></listitem>
+   </itemizedlist>
+   The latter happens in the course of executing <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2::validate" />. It iterates over all form's elements, for each
+   element calling <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Rule::validate">validate()</phd:pearapi> methods of all its rules in
+   the order they were added. As soon as an error is set on an element, its validation stops.
+  </para>
+  <tip>
+   <para>
+    Do not forget to provide an error message to the rule, otherwise the element will be considered
+    valid even if rule's validation routine returns &false;. Not setting an error message is only
+    useful when chaining (see below).
+   </para>
+  </tip>
+  <tip>
+   <para>
+    Some of the elements may perform additional hardcoded validation. For example, file uploads will
+    check the value of <literal>'error'</literal> field in <varname>$_FILES</varname> and assign a
+    relevant error message when file upload was attempted but failed.
+   </para>
+  </tip>
+  <example>
+   <info>
+    <title>Instantiating Rule objects directly</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+require_once 'HTML/QuickForm2.php';
+require_once 'HTML/QuickForm2/Rule/Required.php';
+require_once 'HTML/QuickForm2/Rule/Regex.php';
+
+$form = new HTML_QuickForm2('tutorial');
+$username = $form->addElement('text', 'username');
+$form->addElement('submit', null, array('value' => 'Send!'));
+
+$username->addRule(new HTML_QuickForm2_Rule_Required(
+    $username, 'Username is required!'
+));
+$username->addRule(new HTML_QuickForm2_Rule_Regex(
+    $username, 'Username should contain only letters, digits and underscores', '/^[a-zA-Z0-9_]+$/'
+));
+
+if ($form->validate()) {
+    // process form
+}
+
+echo $form;
+]]>
+   </programlisting>
+  </example>
+  <para>
+   Of course, you will rarely need to instantiate Rule subclasses directly, Rule objects can be
+   created by <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Node::createRule" /> or automatically by
+   <function>addRule</function> if first parameter is a string representing registered rule type.
+  </para>
+  <example>
+   <info>
+    <title>Automatic creation of Rule objects</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+require_once 'HTML/QuickForm2.php';
+
+$form = new HTML_QuickForm2('tutorial');
+$username = $form->addElement('text', 'username');
+$form->addElement('submit', null, array('value' => 'Send!'));
+
+$username->addRule('required', 'Username is required!');
+$username->addRule('regex', 'Username should contain only letters, digits and underscores',
+                   '/^[a-zA-Z0-9_]+$/');
+
+if ($form->validate()) {
+    // process form
+}
+
+echo $form;
+]]>
+   </programlisting>
+  </example>
+  <para>
+   New rule types are registered by <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Factory::registerRule" /> which accepts rule type name,
+   corresponding class name and optionally file name containing that class and default configuration
+   data for all rules of the given type.
+  </para>
+ </refsection>
+
+
+ <refsection xml:id="package.html.html-quickform2.rules.list">
+  <info>
+   <title>Built-in validation rules</title>
+  </info>
+  <para>
+   For your convenience, all rules included in the package are already registered with
+   <classname>HTML_QuickForm2_Factory</classname> and can be easily created with
+   <function>createRule</function> / <function>addRule</function>. Some of the rule classes are
+   registered under several names with different configuration data to save keystrokes and improve
+   readability:
+   <programlisting role="php">
+<![CDATA[
+// these calls are identical
+$username->addRule('minlength', 'Username should be at least 4 characters long', 4);
+$username->addRule('length', 'Username should be at least 4 characters long', array('min' => 4));
+
+// as are these
+$start->addRule('lt', 'Start should be less than finish', $finish);
+$start->addRule('compare', 'Start should be less than finish',
+                array('operator' => '<', 'operand' => $finish));
+]]>
+   </programlisting>
+  </para>
+<!--
+ This table will look quite fucked-up due to a bug in current PhD_PEAR
+ See: http://bugs.php.net/bug.php?id=54208
+-->
+  <table>
+   <title>List of validation rules known to <classname>HTML_QuickForm2_Factory</classname></title>
+   <tgroup cols="4">
+    <colspec colname="name" />
+    <colspec colname="classname" />
+    <colspec colname="description" />
+    <colspec colname="config" />
+    <thead>
+     <row>
+      <entry>Rule name</entry>
+      <entry>Class name</entry>
+      <entry>Description</entry>
+      <entry>Configuration</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><varname>nonempty</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Nonempty" /></entry>
+      <entry>Checks that the field is not empty</entry>
+      <entry>Minimum number of nonempty values for Containers / arrays, &type.integer;</entry>
+     </row>
+     <row>
+      <entry><varname>empty</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Empty" /></entry>
+      <entry>Checks that the field is empty</entry>
+      <entry></entry>
+     </row>
+     <row>
+      <entry><varname>required</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Required" /></entry>
+      <entry>Like <varname>nonempty</varname>, but the field is marked as required in output</entry>
+      <entry>Like <varname>nonempty</varname></entry>
+     </row>
+     <row valign="top">
+      <entry><varname>compare</varname></entry>
+      <entry morerows="6"><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Compare" /></entry>
+      <entry>Compares the value of the field with some other value using the given operator</entry>
+      <entry>
+       Either of the following:
+       <itemizedlist>
+        <listitem><simpara>operand</simpara></listitem>
+        <listitem><simpara>array([operator, ]operand)</simpara></listitem>
+        <listitem><simpara>array(['operator' =&gt; operator, ]['operand' =&gt; operand])</simpara></listitem>
+       </itemizedlist>
+       If operator is missing it will default to <literal>'==='</literal>. Operand can either be a
+       literal value or another form element.
+      </entry>
+     </row>
+     <row valign="top">
+      <entry><varname>eq</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'==='</literal> operator</entry>
+      <entry morerows="1">Operand. The values are compared as strings.</entry>
+     </row>
+     <row>
+      <entry><varname>neq</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'!=='</literal> operator</entry>
+     </row>
+     <row valign="top">
+      <entry><varname>lt</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'&lt;'</literal> operator</entry>
+      <entry morerows="3">Operand. The values are compared as numbers.</entry>
+     </row>
+     <row>
+      <entry><varname>lte</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'&lt;='</literal> operator</entry>
+     </row>
+     <row>
+      <entry><varname>gt</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'&gt;'</literal> operator</entry>
+     </row>
+     <row>
+      <entry><varname>gte</varname></entry>
+      <entry>As <varname>compare</varname> rule with hardcoded <literal>'&gt;='</literal> operator</entry>
+     </row>
+     <row>
+      <entry><varname>regex</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Regex" /></entry>
+      <entry>Checks that the field value matches the given regular expression.</entry>
+      <entry>Regular expression, &type.string;. Use slashes for delimiters if you intend to do
+       client-side validation.</entry>
+     </row>
+     <row valign="top">
+      <entry><varname>callback</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Callback" /></entry>
+      <entry>Checks the value using a provided callback function (method). It is expected to return
+       &true; if the element is valid</entry>
+      <entry>Either of
+       <itemizedlist>
+        <listitem><simpara>A valid &type.callback;</simpara></listitem>
+        <listitem><simpara>array ('callback' =&gt; validation callback [, 'arguments' =&gt; additional arguments]
+         [, 'js_callback' =&gt; javascript callback for client-side validation])</simpara></listitem>
+       </itemizedlist>
+      </entry>
+     </row>
+     <row valign="top">
+      <entry><varname>length</varname></entry>
+      <entry morerows="2"><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Length" /></entry>
+      <entry>Checks that the value's length is within the given limits</entry>
+      <entry>
+       Either of
+       <itemizedlist>
+        <listitem><simpara>&type.integer; (rule checks for exact length)</simpara></listitem>
+        <listitem><simpara>array(minlength, maxlength)</simpara></listitem>
+        <listitem><simpara>array(['min' =&gt; minlength, ]['max' =&gt; maxlength])</simpara></listitem>
+       </itemizedlist>
+      </entry>
+     </row>
+     <row>
+      <entry><varname>minlength</varname></entry>
+      <entry>Checks that the value's length is at least the given number of characters</entry>
+      <entry>Minimal length, &type.integer;</entry>
+     </row>
+     <row>
+      <entry><varname>maxlength</varname></entry>
+      <entry>Checks that the value's length is at most the given number of characters</entry>
+      <entry>Maximal length, &type.integer;</entry>
+     </row>
+     <row>
+      <entry><varname>notcallback</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2"
+       phd:linkend="HTML_QuickForm2_Rule_NotCallback" /></entry>
+      <entry>Checks the value using a provided callback function (method). It is expected to return
+       &false; if the element is valid.</entry>
+      <entry>Like <varname>callback</varname></entry>
+     </row>
+     <row>
+      <entry><varname>notregex</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_NotRegex" /></entry>
+      <entry>Checks that the field value <emphasis>does not match</emphasis> the given regular
+       expression.</entry>
+      <entry>Like <varname>regex</varname></entry>
+     </row>
+     <row>
+      <entry namest="name" nameend="config">Rules specific for <phd:pearapi
+       phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Element_InputFile">file
+       uploads</phd:pearapi></entry>
+     </row>
+     <row>
+      <entry><varname>maxfilesize</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_MaxFileSize" /></entry>
+      <entry>Checks that uploaded file size does not exceed the given limit</entry>
+      <entry>Maximum allowed file size, &type.integer;</entry>
+     </row>
+     <row>
+      <entry><varname>mimetype</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_MimeType" /></entry>
+      <entry>Checks that uploaded file is of the correct MIME type</entry>
+      <entry>Allowed MIME type or an array of types</entry>
+     </row>
+     <row>
+      <entry namest="name" nameend="config">Rules specific for <phd:pearapi
+       phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Container">containers</phd:pearapi></entry>
+     </row>
+     <row>
+      <entry><varname>each</varname></entry>
+      <entry><phd:pearapi phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule_Each" /></entry>
+      <entry>Validates all elements in a Container using a template Rule</entry>
+      <entry>Template Rule, instance of <classname>HTML_QuickForm2_Rule</classname></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+  <tip>
+   <para>
+    Usage of builtin rules is covered in <filename>builtin-rules.php</filename> example installed
+    with the package.
+   </para>
+  </tip>
+ </refsection>
+
+
+ <refsection xml:id="package.html.html-quickform2.rules.containers">
+  <info>
+   <title>Validating containers</title>
+  </info>
+  <para>
+   Most of the built-in rules are designed to check scalar values and will not work properly if
+   added to a Container (this includes <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Container_Group">Groups</phd:pearapi> and Group-based elements as
+   <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Element_Date">Date</phd:pearapi> and <phd:pearapi
+    phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_Element_Hierselect">Hierselect</phd:pearapi>), as Containers return
+   their values in an associative array. One notable exception is <varname>nonempty</varname> /
+   <varname>required</varname> rule that can validate a container (or <literal>&lt;select
+   multiple=&quot;multiple&quot; /&gt;</literal>):
+  </para>
+  <example>
+   <info>
+    <title>Checks that at least two checkboxes in a group are selected</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+$boxGroup = $form->addElement('group', 'boxes')->setLabel('Check at least two:');
+$boxGroup->addElement('checkbox', null, array('value' => 'first'))->setContent('First');
+$boxGroup->addElement('checkbox', null, array('value' => 'second'))->setContent('Second');
+$boxGroup->addElement('checkbox', null, array('value' => 'third'))->setContent('Third');
+
+$boxGroup->addRule('required', 'Check at least two boxes', 2);
+]]>
+   </programlisting>
+  </example>
+  <para>
+   It is of course possible to implement a custom rule that will properly handle an associative
+   array as the element's value. It is also possible to leverage existing &quot;scalar&quot; rules
+   to validate Containers by using <varname>each</varname> rule, it applies a template rule to all the
+   elements in a Container and considers Container valid if its validation routine returns &true;
+   for all of them:
+  </para>
+  <example>
+   <info>
+    <title>Checks that all phone fields in a group contain numeric data</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+$phones = $form->addElement('group', 'phones')->setLabel('Phones (numeric):')
+               ->setSeparator('<br />');
+$phones->addElement('text', '0');
+$phones->addElement('text', '1');
+
+$phones->addRule('each', 'Phones should be numeric',
+                 $phones->createRule('regex', '', '/^\\d+([ -]\\d+)*$/'));
+]]>
+   </programlisting>
+  </example>
+  <tip>
+   <para>
+    More specific rules are run first: rules added to container will be checked after rules added to
+    its contained elements.
+   </para>
+  </tip>
+ </refsection>
+
+
+ <refsection xml:id="package.html.html-quickform2.rules.chaining">
+  <info>
+   <title>Chaining the rules</title>
+  </info>
+  <para>
+   HTML_QuickForm2 allows validation of elements based on values and validation status of other
+   elements. This is done by building a &quot;chain&quot; of validation rules using <phd:pearapi
+    phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule::and_" /> and <phd:pearapi
+    phd:package="HTML_QuickForm2" phd:linkend="HTML_QuickForm2_Rule::or_" /> methods. Execution of
+   the chain starts with a rule that was added to an element, then results of other rules'
+   validation routines are combined using corresponding logical operators. Error is only set on the
+   element if the whole chain returned &false;.
+  </para>
+  <para>
+   Behaviour of <function>and_</function> and <function>or_</function> is similar to PHP's
+   <varname>and</varname> and <varname>or</varname> operators:
+   <itemizedlist>
+    <listitem><simpara><function>and_</function> has higher precedence than
+     <function>or_</function>.</simpara></listitem>
+    <listitem><simpara>Evaluation is short-circuited. If first argument of <function>and_</function>
+     evaluates to &false; then &false; is returned without evaluating second argument, if first
+     argument of <function>or_</function> evaluates to &true; then &true; is returned without
+     evaluating second argument.</simpara></listitem>
+   </itemizedlist>
+  </para>
+  <para>
+   Rules that are added to the chain behave the same way as the rules that are added directly to the
+   element they validate (this is not necessarily the same element the chain is added to), they will
+   set an error if the rule itself returns &false;, not the chain. Thus it is often needed
+   <emphasis>not to provide</emphasis> error messages to the rules. It may also make sense to add a
+   chain of rules to a chain (this is similar to adding parentheses to a PHP expression with
+   <varname>and</varname> and <varname>or</varname>).
+  </para>
+  <example>
+   <info>
+    <title>Skips checking email field if &quot;receive email&quot; box is not checked</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+$emailPresent = $email->createRule('nonempty', 'Supply a valid email if you want to receive our spam');
+// note lack of error message here, error should only be set by previous rule
+$emailValid   = $email->createRule('callback', '', array('callback'  => 'filter_var',
+                                                         'arguments' => array(FILTER_VALIDATE_EMAIL)));
+// note lack of error message for 'empty' rule, we don't want error on a checkbox
+$spamCheck->addRule('empty')
+          ->or_($emailPresent->and_($emailValid));
+]]>
+   </programlisting>
+  </example>
+  <example>
+   <info>
+    <title>Checks password fields in password change form</title>
+   </info>
+   <programlisting role="php">
+<![CDATA[
+$newPassword->addRule('empty')
+            ->and_($repPassword->createRule('empty'))
+            ->or_($newPassword->createRule('minlength', 'The password is too short', 6))
+            ->and_($repPassword->createRule('eq', 'The passwords do not match', $newPassword))
+            ->and_($oldPassword->createRule('nonempty', 'Supply old password if you want to change it'));
+]]>
+   </programlisting>
+  </example>
+ </refsection>
+
+
+ <refsection xml:id="package.html.html-quickform2.rules.clientside">
+  <info>
+   <title>Client-side validation</title>
+  </info>
+  <para>
+   You can tell a rule to also generate Javascript necessary for client-side validation. This is
+   done by passing a <parameter>$runAt</parameter> parameter with
+   <constant>HTML_QuickForm2_Rule::CLIENT</constant> flag set to <function>addRule</function>:
+   <programlisting role="php">
+<![CDATA[
+// if first parameter to addRule() is a string:
+$username->addRule('required', 'Username is required', null,
+                   HTML_QuickForm2_Rule::SERVER | HTML_QuickForm2_Rule::CLIENT);
+// if first parameter to addRule() is a Rule instance:
+$username->addRule($username->createRule('required', 'Username is required'),
+                   HTML_QuickForm2_Rule::SERVER | HTML_QuickForm2_Rule::CLIENT);
+]]>
+   </programlisting>
+   If more rules were chained to the added one with <function>and_</function> and
+   <function>or_</function>, Javascript will be generated for the whole chain.
+  </para>
+  <note>
+   <para>
+    While it is possible to add a client-side only rule
+    <programlisting role="php">
+<![CDATA[
+$username->addRule('minlength', 'Username should be at least 4 characters long', 4,
+                   HTML_QuickForm2_Rule::CLIENT);
+]]>
+    </programlisting>
+    it is not recommended unless you perform the same validation server-side using some other rule.
+   </para>
+  </note>
+  <para>
+   Most of the built-in rules are able to run client-side, the only exceptions are
+   <varname>maxfilesize</varname> and <varname>mimetype</varname> rules specific for file uploads.
+  </para>
+  <tip>
+   <para>
+    If you want to run <varname>callback</varname> rule client-side, you will obviously need to
+    implement a callback in Javascript as well as in PHP. If you don't explicitly set
+    <parameter>'js_callback'</parameter> configuration parameter, <varname>callback</varname> rule
+    will try to run Javascript function having the same name as provided PHP
+    <parameter>'callback'</parameter>. This may be especially useful if you use
+    <classname>HTML_AJAX</classname> to create proxy classes in Javascript.
+   </para>
+  </tip>
+  <para>
+   Javascript for the rules is aggregated by <phd:pearapi phd:package="HTML_QuickForm2"
+    phd:linkend="HTML_QuickForm2_JavascriptBuilder" /> class when rendering a form and usually
+   output by a renderer. That class also tracks what Javascript libraries should be included in the
+   page before the form for client-side validation and javascript-backed elements to work. Libraries
+   are not output by default, you need either
+   <itemizedlist>
+    <listitem><para>
+     Call <phd:pearapi phd:package="HTML_QuickForm2"
+      phd:linkend="HTML_QuickForm2_JavascriptBuilder::getLibraries" /> to inline the libraries,
+     including their contents into the page
+     <programlisting role="php">
+<![CDATA[
+require_once 'HTML/QuickForm2/Renderer.php';
+
+$renderer = HTML_QuickForm2_Renderer::factory('default');
+$form->render($renderer);
+
+echo $renderer->getJavascriptBuilder()->getLibraries(true, true);
+echo $renderer;
+]]>
+     </programlisting>
+    </para></listitem>
+    <listitem><para>
+     Copy/symlink <filename>*.js</filename> files installed into <filename
+      role="dir">HTML_QuickForm2/</filename> directory under PEAR's <parameter>data_dir</parameter>
+     to some directory under your website's document root and provide this information to
+     JavascriptBuilder:
+     <programlisting role="php">
+<![CDATA[
+require_once 'HTML/QuickForm2/Renderer.php';
+require_once 'HTML/QuickForm2/JavascriptBuilder.php';
+
+$renderer = HTML_QuickForm2_Renderer::factory('default');
+// Here '/path/to/libraries' is whatever directory available via HTTP you copied libraries to
+$renderer->setJavascriptBuilder(new HTML_QuickForm2_JavascriptBuilder('/path/to/libraries'));
+$form->render($renderer);
+
+// This will output necessary <script src="/path/to/libraries/..."></script> tags
+foreach ($renderer->getJavascriptBuilder()->getLibraries() as $link) {
+    echo $link . "\n";
+}
+echo $renderer;
+]]>
+     </programlisting>
+     If you have trouble finding where <parameter>data_dir</parameter> is, you can use <link
+      linkend="guide.users.commandline.config">config-show</link> command of PEAR installer.
+    </para></listitem>
+   </itemizedlist>
+  </para>
+ </refsection>
+</refentry>

Modified: pear/peardoc/trunk/en/package/html/html-quickform2.xml
===================================================================
--- pear/peardoc/trunk/en/package/html/html-quickform2.xml	2011-03-11 23:16:46 UTC (rev 309132)
+++ pear/peardoc/trunk/en/package/html/html-quickform2.xml	2011-03-12 12:02:38 UTC (rev 309133)
@@ -40,6 +40,7 @@
   &package.html.html-quickform2.tutorial;
   &package.html.html-quickform2.qf-migration;
   &package.html.html-quickform2.values-datasources;
+  &package.html.html-quickform2.rules;
  </chapter>
 </book>