[GENERIC] Zend_Translate:
[zend.git] / documentation / manual / en / tutorials / form-decorators-individual.xml
blob3cbc1c36920b9952f6224c51a5fd6c58fc933040
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="learning.form.decorators.individual">
4     <title>Rendering Individual Decorators</title>
6     <para>
7         In the <link linkend="learning.form.decorators.layering">previous section</link>, we
8         looked at how you can combine decorators to create complex output. We noted that while you
9         have a ton of flexibility with this approach, it also adds some complexity and overhead. In
10         this section, we will examine how to render decorators individually in order to create
11         custom markup for forms and/or individual elements.
12     </para>
14     <para>
15         Once you have registered your decorators, you can later retrieve them by name from the
16         element. Let's review the previous example:
17     </para>
19     <programlisting language="php"><![CDATA[
20 $element = new Zend_Form_Element('foo', array(
21     'label'      => 'Foo',
22     'belongsTo'  => 'bar',
23     'value'      => 'test',
24     'prefixPath' => array('decorator' => array(
25         'My_Decorator' => 'path/to/decorators/',
26     )),
27     'decorators' => array(
28         'SimpleInput'
29         array('SimpleLabel', array('placement' => 'append')),
30     ),
31 ));
32 ]]></programlisting>
34     <para>
35         If we wanted to pull and render just the <classname>SimpleInput</classname> decorator, we
36         can do so using the <methodname>getDecorator()</methodname> method:
37     </para>
39     <programlisting language="php"><![CDATA[
40 $decorator = $element->getDecorator('SimpleInput');
41 echo $decorator->render('');
42 ]]></programlisting>
44     <para>
45         This is pretty easy, but it can be made even easier; let's do it in a single line:
46     </para>
48     <programlisting language="php"><![CDATA[
49 echo $element->getDecorator('SimpleInput')->render('');
50 ]]></programlisting>
52     <para>
53         Not too bad, but still a little complex. To make this easier, a shorthand notation was
54         introduced into <classname>Zend_Form</classname> in 1.7: you can render any registered
55         decorator by calling a method of the format <methodname>renderDecoratorName()</methodname>.
56         This will effectively perform what you see above, but makes the <varname>$content</varname>
57         argument optional and simplifies the usage:
58     </para>
60     <programlisting language="php"><![CDATA[
61 echo $element->renderSimpleInput();
62 ]]></programlisting>
64     <para>
65         This is a neat trick, but how and why would you use it?
66     </para>
68     <para>
69         Many developers and designers have very precise markup needs for their forms. They would
70         rather have full control over the output than rely on a more automated solution which may or
71         may not conform to their design. In other cases, the form layout may require a lot of
72         specialized markup -- grouping arbitrary elements, making some invisible unless a particular
73         link is selected, etc.
74     </para>
76     <para>
77         Let's utilize the ability to render individual decorators to create some specialized markup.
78     </para>
80     <para>
81         First, let's define a form. Our form will capture a user's demographic details. The markup
82         will be highly customized, and in some cases use view helpers directly instead of form
83         elements in order to achieve its goals. Here is the basic form definition:
84     </para>
86     <programlisting language="php"><![CDATA[
87 class My_Form_UserDemographics extends Zend_Form
89     public function init()
90     {
91         // Add a path for my own decorators
92         $this->addElementPrefixPaths(array(
93             'decorator' => array('My_Decorator' => 'My/Decorator'),
94         ));
96         $this->addElement('text', 'firstName', array(
97             'label' => 'First name: ',
98         ));
99         $this->addElement('text', 'lastName', array(
100             'label' => 'Last name: ',
101         ));
102         $this->addElement('text', 'title', array(
103             'label' => 'Title: ',
104         ));
105         $this->addElement('text', 'dateOfBirth', array(
106             'label' => 'Date of Birth (DD/MM/YYYY): ',
107         ));
108         $this->addElement('text', 'email', array(
109             'label' => 'Your email address: ',
110         ));
111         $this->addElement('password', 'password', array(
112             'label' => 'Password: ',
113         ));
114         $this->addElement('password', 'passwordConfirmation', array(
115             'label' => 'Confirm Password: ',
116         ));
117     }
119 ]]></programlisting>
121     <note>
122         <para>
123             We're not defining any validators or filters at this time, as they are not relevant to
124             the discussion of decoration. In a real-world scenario, you should define them.
125         </para>
126     </note>
128     <para>
129         With that out of the way, let's consider how we might want to display this form. One common
130         idiom with first/last names is to display them on a single line; when a title is provided,
131         that is often on the same line as well. Dates, when not using a JavaScript date chooser,
132         will often be separated into three fields displayed side by side.
133     </para>
135     <para>
136         Let's use the ability to render an element's decorators one by one to accomplish this.
137         First, let's note that no explicit decorators were defined for the given elements. As a
138         refresher, the default decorators for (most) elements are:
139     </para>
141     <itemizedlist>
142         <listitem>
143             <para>
144                 <classname>ViewHelper</classname>: utilize a view helper to render a form input
145             </para>
146         </listitem>
148         <listitem>
149             <para>
150                 <classname>Errors</classname>: utilize the <classname>FormErrors</classname> view
151                 helper to render validation errors
152             </para>
153         </listitem>
155         <listitem>
156             <para>
157                 <classname>Description</classname>: utilize the <classname>FormNote</classname> view
158                 helper to render the element description (if any)
159             </para>
160         </listitem>
162         <listitem>
163             <para>
164                 <classname>HtmlTag</classname>: wrap the above three items in a
165                 <emphasis>&lt;dd&gt;</emphasis> tag
166             </para>
167         </listitem>
169         <listitem>
170             <para>
171                 <classname>Label</classname>: render the element label using the
172                 <classname>FormLabel</classname> view helper (and wrap it in a
173                 <emphasis>&lt;dt&gt;</emphasis> tag)
174             </para>
175         </listitem>
176     </itemizedlist>
178     <para>
179         Also, as a refresher, you can access any element of a form as if it were a class property;
180         simply reference the element by the name you assigned it.
181     </para>
183     <para>
184         Our view script might then look like this:
185     </para>
187     <programlisting language="php"><![CDATA[
188 <?php
189 $form = $this->form;
190 // Remove <dt> from label generation
191 foreach ($form->getElements() as $element) {
192     $element->getDecorator('label')->setOption('tag', null);
195 <form method="<?php echo $form->getMethod() ?>" action="<?php echo
196     $form->getAction()?>">
197     <div class="element">
198         <?php echo $form->title->renderLabel()
199               . $form->title->renderViewHelper() ?>
200         <?php echo $form->firstName->renderLabel()
201               . $form->firstName->renderViewHelper() ?>
202         <?php echo $form->lastName->renderLabel()
203               . $form->lastName->renderViewHelper() ?>
204     </div>
205     <div class="element">
206         <?php echo $form->dateOfBirth->renderLabel() ?>
207         <?php echo $this->formText('dateOfBirth[day]', '', array(
208             'size' => 2, 'maxlength' => 2)) ?>
209         /
210         <?php echo $this->formText('dateOfBirth[month]', '', array(
211             'size' => 2, 'maxlength' => 2)) ?>
212         /
213         <?php echo $this->formText('dateOfBirth[year]', '', array(
214             'size' => 4, 'maxlength' => 4)) ?>
215     </div>
216     <div class="element">
217         <?php echo $form->password->renderLabel()
218               . $form->password->renderViewHelper() ?>
219     </div>
220     <div class="element">
221         <?php echo $form->passwordConfirmation->renderLabel()
222               . $form->passwordConfirmation->renderViewHelper() ?>
223     </div>
224     <?php echo $this->formSubmit('submit', 'Save') ?>
225 </form>
226 ]]></programlisting>
228     <para>
229         If you use the above view script, you'll get approximately the following
230         <acronym>HTML</acronym> (approximate, as the <acronym>HTML</acronym> below is formatted):
231     </para>
233     <programlisting language="html"><![CDATA[
234 <form method="post" action="">
235     <div class="element">
236         <label for="title" tag="" class="optional">Title:</label>
237         <input type="text" name="title" id="title" value=""/>
239         <label for="firstName" tag="" class="optional">First name:</label>
240         <input type="text" name="firstName" id="firstName" value=""/>
242         <label for="lastName" tag="" class="optional">Last name:</label>
243         <input type="text" name="lastName" id="lastName" value=""/>
244     </div>
246     <div class="element">
247         <label for="dateOfBirth" tag="" class="optional">Date of Birth
248             (DD/MM/YYYY):</label>
249         <input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
250             value="" size="2" maxlength="2"/>
251         /
252         <input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
253             value="" size="2" maxlength="2"/>
254         /
255         <input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
256             value="" size="4" maxlength="4"/>
257     </div>
259     <div class="element">
260         <label for="password" tag="" class="optional">Password:</label>
261         <input type="password" name="password" id="password" value=""/>
262     </div>
264     <div class="element">
265         <label for="passwordConfirmation" tag="" class="" id="submit"
266             value="Save"/>
267 </form>
268 ]]></programlisting>
270     <para>
271         It may not be truly pretty, but with some CSS, it could be made to look exactly how you
272         might want to see it. The main point, however, is that this form was generated using almost
273         entirely custom markup, while still leveraging decorators for the most common markup (and to
274         ensure things like escaping with htmlentities and value injection occur).
275     </para>
277     <para>
278         By this point in the tutorial, you should be getting fairly comfortable with the markup
279         possibilities using <classname>Zend_Form</classname>'s decorators. In the next section,
280         we'll revisit the date element from above, and demonstrate how to create a custom element
281         and decorator for composite elements.
282     </para>
283 </sect1>