打造最大的网络营销知识与推广的信息化航母

进入论坛 | 会员注册 | 会员登陆 |
首页 >> php >> php进阶教程 >> Decorators with Zend_Form正文

Decorators with Zend_Form

来源:it我领先 发布时间:2010-04-03               浏览次数:88 进入论坛社区

Zend_Form has been lauded by many as a welcome addition to Zend Framework, and a flexible solution to the problem of forms. That said, one point of flexibility it offers has proved to be a pain point for many developers: decorators. This tutorial aims to shed some light on decorators, as well as provide strategies for creating your own decorators and combining them in creative ways to customize the output your forms generate.

Background

When designing Zend_Form, a primary goal was that it should generate the markup necessary to display each element and the form itself. The rationale was that injecting values and metadata into the element markup and reporting errors is often a tedious, repetitive task. Any form solution needed to address this and make these actions trivial.

Of course, the problem with generating form markup is that there is no standard way to do it. The approaches vary greatly from developer to developer and project to project. So, any solution for this had to be flexible enough to accomodate a variety of approaches.

Another objective was that Zend_Form not be tied to Zend_View. While it单引号s true that the default decorators actually do utilize Zend_View, the solution needed to be flexible enough that should a developer choose not to utilize Zend_View, they could.

With all these goals in mind, the solution finally presented itself: use the principles of the Decorator Pattern. A decorator traditionally is used as a way to extend the functionality of a class by wrapping it. This allows the developer the ability to add or modify existing behavior while making calls to the same API. Decorators may wrap other decorators, allowing for a layered approach to extension. The decorator itselfis used in place of the original object, as it follows the same API; it simply provides new or additional functionality to the original.

As an example, consider a Window class. You might then create a WindowDecorator that displays the window, and additional decorators for showing the scrollbars, window title, etc; each decorator is responsible for a single aspect of the final display. Instantiation might look like this:

$window = new WindowScrollbarDecorator(    new WindowTitleDecorator(        new WindowDecorator(            new Window()        )    ));


To render the final window:

$window->render();


This would execute the WindowScrollbarDecorator::render() method, which would in turn call the WindowTitleDecorator::render() method, which would then call WindowDecorator::render(), which would finally either call on the Window::render() method or simply use object state from it. The final result is a window with a title and scrollbars.

Decorators present an ideal solution for Zend_Form, in that a developer may want to selectively determine what to display in their final output. The final solution settled on is a modified decorator; instead of decorating the object, we decorate the content generated, but we do so using metadata from the element or form object. Whereas a traditional decorator operates from the outside in, Zend_Form单引号s operates from the inside out, layering content outward.

Basics of Operation

When decorating, you have the ability to either prepend, append, or replace (which could include wrapping) the content passed in. The initial content is an empty string, and then each decorator works on the content from the previously executed decorator.

Let单引号s look at how the default decorators for most elements work. The default decorators are ViewHelper, Errors, HtmlTag, and finally Label. By default, the ViewHelper decorator replaces any content provided; the Errors decorator appends the content provided; the HtmlTag decorator wraps content provided and the Label decorator prepends content provided. (In all cases except the ViewHelper, the placement -- to append, prepend, or wrap -- is configurable.) To visualize execution, the final execution call looks something like this:

$label->render($htmlTag->render($errors->render($viewHelper->render(单引号单引号))))


Step by step, let单引号s look at how the content is built:

    单引号单引号
            <input name=双引号foo双引号 id=双引号foo双引号 type=双引号text双引号 value=双引号双引号 />    
            <input name=双引号foo双引号 id=双引号foo双引号 type=双引号text双引号 value=双引号双引号 />        <div class=双引号error双引号><ul>            <li>...</li>        </ul></div>    
            <dd>        <input name=双引号foo双引号 id=双引号foo双引号 type=双引号text双引号 value=双引号双引号 />        <div class=双引号error双引号><ul>            <li>...</li>        </ul></div>        </dd>    
            <dt><label for=双引号foo双引号 class=双引号optional双引号>Foo</label><dt>        <dd>        <input name=双引号foo双引号 id=双引号foo双引号 type=双引号text双引号 value=双引号双引号 />        <div class=双引号error双引号><ul>            <li>...</li>        </ul></div>        </dd>    

    As you can see, each decorator does one thing, and the final result is an aggregation of the content produced by each decorator.

    Customizing Output Using Standard Decorators

    To get an idea of how to customize output, first you need to know the baseline: what the standard, registered decorators are for each object type. The standard decorators, in the order they are registered, for most elements are:

      ViewHelperErrorsHtmlTag (<dd>)Label (with wrapping <dt> tag)

      For the form object, the standard decorators are:

        FormElements (iterates through all elements, display groups, and sub forms, rendering each)HtmlTag (<dl>)Form

        Display groups and sub forms share the following decorators by default:

          FormElementsFieldsetDtDdWrapper (wraps fieldset in a <dd>, and prepends with an empty <dt>)

          One easy way to customize output is to either add or modify options on a decorator. For instance, if you decide you want your label to follow your element, instead of precede it, you could change the placement option:

          $label = $element->getDecorator(单引号label单引号);$label->setOption(单引号placement单引号, 单引号append单引号);


          There are a variety of options available for most decorators; you will need to read the manual and/or API documentation to get the full details.

          Another easy way to customize output is to remove a decorator. If you don单引号t want to display a label, for instance, remove that decorator:

          $element->removeDecorator(单引号label单引号);


          Unfortunately, there are not currently methods for inserting decorators at specific locations in the decorator stack, so if you find you need to insert a new decorator in the middle of the stack, the best way is to simply reset the stack. For example, if you wanted to add a Description following the element (perhaps a paragraph detailing the purpose of the element), you could do the following:

          $element->setDescription($desc);$element->setDecorators(array(    单引号ViewHelper单引号,    单引号Description单引号,    单引号Errors单引号,    array(单引号HtmlTag单引号, array(单引号tag单引号 => 单引号dd单引号)),    array(单引号Label单引号, array(单引号tag单引号 => 单引号dt单引号)),));


          While addDecorator() and addDecorators() methods exist, typically you will be using setDecorators() unless you start out with very minimal decorators to begin with.

          When adding a decorator, you have the option to alias it. What this does is allow you to store the decorator using a different name -- which allows you to retrieve it from the stack by that name. This is primarily useful when you need to add two or more of the same type of decorator; in fact, in such a situation, if you do not alias, the last registered decorator of that type will overwrite all other instances! You accomplish aliasing by passing an array as the decorator type, with a single key/value pair with the alias as the key, and the decorator type as the value. For instance, if you needed to use two different HTML tags in your stack, you could do something like the following:

          $element->setDecorators(array(    单引号ViewHelper单引号,    单引号Description单引号,    单引号Errors单引号,    array(array(单引号elementDiv单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号div单引号)),    array(array(单引号td单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号)),    array(单引号Label单引号, array(单引号tag单引号 => 单引号td单引号)),));


          In the above example, the element content is wrapped in an HTML div, which is then in turn wrapped in a table data cel. The two are aliased as 单引号elementDiv单引号 and 单引号td单引号, respectively.

          Standard Decorators

          Now that we know how to manipulate the decorator stack and the individual decorators, what standard decorators are available?

            Callback: execute a specified PHP callback to return contentDescription: render the item单引号s description propertyDtDdWrapper: wrap content in a <dd> and prepend with an empty <dt>Errors: render an unordered list of the item单引号s errors, if anyFieldset: render the content provided in a fieldset, using the item单引号s legend property for a legend if availableFormElements: iterate through a form, sub form, or display group, rendering each item (which could be an element, display group, or sub form)Form: wrap content in a <form> tag, using the form object单引号s metadata as attributesHtmlTag: wrap content in an HTML tag, or prepend or append the content with a given tag (and optionally use either just the open or close tag)Image: render a form image based on the current elementLabel: render an element单引号s label (prepends by default)ViewHelper: render an element by utilizing a view helper. the view helper used is pulled from the element单引号s 单引号helper单引号 property, if available, but can also be specified explicitly by passing a 单引号helper单引号 option to the decorator. Replaces content by default.ViewScript: render an element by rendering a specified view script. Replaces content by default.

            Each of the above appends the content provided by default, unless otherwise specified.

            Example: Table Layout

            One common request is to be able to render a form as an HTML table. How can this be accomplished?

            For purposes of this example, we will assume that there should be one row per element. Standard elements will use two columns per row, one for the label and one for the element and any reported errors; buttons will be displayed in the second column with no label.

            For standard elements, you would set decorators like the following:

            $element->setDecorators(array(    单引号ViewHelper单引号,    单引号Errors单引号,    array(array(单引号data单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号class单引号 => 单引号element单引号)),    array(单引号Label单引号, array(单引号tag单引号 => 单引号td单引号),    array(array(单引号row单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号tr单引号)),));


            For button and image elements, we单引号d use the following:

            $element->setDecorators(array(    单引号ViewHelper单引号,    array(array(单引号data单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号class单引号 => 单引号element单引号)),    array(array(单引号label单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号placement单引号 => 单引号prepend单引号)),    array(array(单引号row单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号tr单引号)),));


            The form itself would look like this:

            $form->setDecorators(array(    单引号FormElements单引号,    array(单引号HtmlTag单引号, array(单引号tag单引号 => 单引号table单引号)),    单引号Form单引号,));


            The following output might then be generated:

            <form enctype=双引号application/x-www-form-urlencoded双引号 action=双引号双引号 method=双引号post双引号><table>    <tr>        <td><label for=双引号username双引号 class=双引号optional双引号>Username:</label></td>        <td class=双引号element双引号>            <input type=双引号text双引号 name=双引号username双引号 id=双引号username双引号 value=双引号双引号>        </td>    </tr>    <tr>        <td><label for=双引号firstname双引号 class=双引号optional双引号>First Name:</label></td>        <td class=双引号element双引号>            <input type=双引号text双引号 name=双引号firstname双引号 id=双引号firstname双引号 value=双引号双引号>        </td>    </tr>    <tr>        <td><label for=双引号lastname双引号 class=双引号optional双引号>Last Name:</label></td>        <td class=双引号element双引号>            <input type=双引号text双引号 name=双引号lastname双引号 id=双引号lastname双引号 value=双引号双引号>        </td>    </tr>    <tr>        <td></td>        <td class=双引号element双引号>            <input type=双引号submit双引号 name=双引号save双引号 id=双引号save双引号 value=双引号Save双引号>        </td>    </tr></table></form>


            Note: this does not accomodate for display groups and sub forms; hopefully, it gives enough of an idea that you can figure out how to do so.

            双引号That单引号s nice,双引号 you say, 双引号but I don单引号t really want to have to set those decorators for each and every form element.双引号 Well, you don单引号t have to, as there are a variety of methods to accomodate this.

            First, there单引号s the setElementDecorators() method of the form object. This method will set all decorators for all currently registered form elements (not elements registered after calling it):

            $form->setElementDecorators(array(    单引号ViewHelper单引号,    单引号Errors单引号,    array(array(单引号data单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号class单引号 => 单引号element单引号)),    array(单引号Label单引号, array(单引号tag单引号 => 单引号td单引号),    array(array(单引号row单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号tr单引号)),));


            You could do this once, and then loop through the form, looking for submit, reset, button, and image elements to set their decorators.

            Another easy option is subclassing the form object, and defining these as arrays which are passed to the elements:

            class My_Form_Registration extends Zend_Form{    public $elementDecorators = array(        单引号ViewHelper单引号,        单引号Errors单引号,        array(array(单引号data单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号class单引号 => 单引号element单引号)),        array(单引号Label单引号, array(单引号tag单引号 => 单引号td单引号),        array(array(单引号row单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号tr单引号)),    );    public $buttonDecorators = array(        单引号ViewHelper单引号,        array(array(单引号data单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号class单引号 => 单引号element单引号)),        array(array(单引号label单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号td单引号, 单引号placement单引号 => 单引号prepend单引号)),        array(array(单引号row单引号 => 单引号HtmlTag单引号), array(单引号tag单引号 => 单引号tr单引号)),    );    public function init()    {        $this->addElement(单引号text单引号, 单引号username单引号, array(            单引号decorators单引号 => $this->elementDecorators,            单引号label       => 单引号Username:单引号,        );        $this->addElement(单引号text单引号, 单引号firstname单引号, array(            单引号decorators单引号 => $this->elementDecorators,            单引号label       => 单引号First Name:单引号,        );        $this->addElement(单引号text单引号, 单引号lastname单引号, array(            单引号decorators单引号 => $this->elementDecorators,            单引号label       => 单引号Last Name:单引号,        );        $this->addElement(单引号submit单引号, 单引号save单引号, array(            单引号decorators单引号 => $this->buttonDecorators,            单引号label       => 单引号Save单引号,        );    }    public function loadDefaultDecorators()    {        $this->setDecorators(array(            单引号FormElements单引号,            array(单引号HtmlTag单引号, array(单引号tag单引号 => 单引号table单引号)),            单引号Form单引号,        ));    }}


            The above method is especially nice as it prevents the default decorators loading by providing decorators at instantiation time. It also has the advantage that you can modify your decorators in a single place. Should you choose to make the properties elementDecorators or buttonDecorators static, you could even inject the default decorators you want for the form prior to instantiating it, allowing for re-use with different decorator stacks.

            Finally, you could also create your own element subclasses that override the loadDefaultDecorators() methods -- allowing you to have different elements based on the type of output you plan to generate.

            Example: Full Customization Using the ViewScript Decorator

            What if you want to have arbitrary content mixed in with your form elements, or you have a complex markup you want to use? Decorators may be fine for the individual form elements, but for the form as a whole, they make little sense. Enter the ViewScript decorator.

            The ViewScript decorator will render a given view script as a partial, passing the form as the $form view variable. This allows you to pull out the metadata and/or elements you need and render them directly. When using one with a form object, it will also typically obviate the need for Display Groups, as you can do those manually.

            As an example, consider the following view script:

            <h4>Please register with us!</h4><form action=双引号<?= $this->escape($this->form->getAction() ?>双引号      method=双引号<?= $this->escape($this->form->getMethod() ?>双引号><fieldset>    <legend>Demographics</legend>    <p>        Please provide us the following information so we can know more about        you.    </p>    <?= $this->form->age ?>    <?= $this->form->nationality ?>    <?= $this->form->income ?></fieldset><fieldset>    <legend>User Information</legend>    <p>        Now please tell us who you are and how to contact you.    </p>    <?= $this->form->firstname ?>    <?= $this->form->lastname ?>    <?= $this->form->email ?>    <?= $this->form->address1 ?>    <?= $this->form->address2 ?>    <?= $this->form->city ?>    <?= $this->form->state ?>    <?= $this->form->postal ?>    <?= $this->form->phone ?></fieldset><?= $this->form->submit ?></form>


            If the above form was in the view script 双引号demogForm.phtml双引号, you could then attach it to your form as follows:

            $form->setDecorators(array(    array(单引号ViewScript单引号, array(单引号script单引号 => 单引号demogForm.phtml单引号))));


            As you can see, this method of rendering a form can be more verbose, but it also allows you to tweak the form almost infinitely while still gaining the advantages of error reporting, labeling, etc that decorators provide (by using the decorators associated with the elements).

            Creating a Custom Decorator

            Make no mistake about it: there will come a time when the standard decorators simply will not do the job. You may have markup that单引号s too complex to generate with a chain of decorators, you may want to cut down function calls to optimize your application, you may want to combine multiple discrete HTML elements as a single Zend_Form element, etc. At this time, you should start investigating custom decorators.

            Anatomy of a Decorator

            All decorators in Zend_Form implement Zend_Form_Decorator_Interface, which simply looks like this:

            interface Zend_Form_Decorator_Interface{    public function __construct($options = null);    public function setElement($element);    public function getElement();    public function setOptions(array $options);    public function setConfig(Zend_Config $config);    public function setOption($key, $value);    public function getOption($key);    public function getOptions();    public function removeOption($key);    public function clearOptions();    public function render($content);}


            For your convenience, most of these methods are stubbed in Zend_Form_Decorator_Abstract, meaning that all you need to do with your decorators is provide a render() method:

            class My_Form_Decorator_Foo extends Zend_Form_Decorator_Abstract{    public function render($content)    {        // ...        return $content    }}


            A decorator stores an instance of the current object as the 单引号element单引号. However, the element is not restricted to Zend_Form_Element objects, but can also be forms, display groups, or sub forms. As a result, you can have decorators that target aspects of any of these object types and their metadata. Retrieve the current 单引号element单引号 using getElement().

            If your decorator should be view aware, you can attempt to pull the view object from the element:

            $view = $this->getElement()->getView();


            If the returned value is null, you do not have a view.

            Two properties are also always set: the separator and placement. Your render method should make use of these when returning content. When extending Zend_Form_Decorator_Abstract, you can retrieve these using getSeparator() and getPlacement(), respectively; otherwise, check for them using getOption(), as they are passed as options typically. As an example:

            public function render($content){    // ...    $separator = $this->getSeparator();    $placement = $this->getPlacement();    switch ($placment) {        case 单引号APPEND单引号:            // append original content with new content            return $content . $separator . $newContent;        case 单引号PREPEND单引号:            // prepend original content with new content            return $newContent . $separator . $content;        default:            // replace otherwise            return $newContent;    }}


            Now that you have the tools for creating decorators, let单引号s tell the form and elements how to find them.

            Telling Your Form or Element About Your Decorators

            Creating custom decorators is great, but unless you tell your form or elements where to find them, they单引号re worthless. You need to tell your objects where to look for your decorators.

            Forms

            You can tell a form where to look for its decorators using addPrefixPath():

            // Basic usage:$form->addPrefixPath($prefix, $path, 单引号decorator单引号);// Example usage:$form->addPrefixPath(单引号My_Form_Decorator单引号, 单引号My/Form/Decorator/单引号, 单引号decorator单引号);


            The second argument, $path indicates a path to classes containing the given prefix. If that path is on your include_path, then you can use a relative path; if not, use a fully-qualified path to ensure that the plugin loader can find the classes.

            The third argument is the type of plugin path for which the path applies; in this case, we单引号re only looking at decorators, so we use the string 单引号decorator单引号; however, you can also use addPrefixPath() to set plugin paths for other plugin types, such as elements, validators, and filters.

            You can also setup decorator paths for the various items Zend_Form aggregates -- display groups, sub forms, and elements. This can be done by using the following methods:

              addElementPrefixPath($path, $prefix, 单引号decorator单引号)addDisplayGroupPrefixPath($path, $prefix)

              In each case, the setting will apply to any elements or display groups currently attached to the form, as well as those created or attached later. You may also pass an elementPrefixPath option during configuration; the value will be used for any elements created with the form. As examples:

              // Programmatically$form->addElementPrefixPath(单引号My_Form_Decorator单引号, 单引号My/Form/Decorator单引号, 单引号decorator单引号);$form->addDisplayGroupPrefixPath(单引号My_Form_Decorator单引号, 单引号My/Form/Decorator单引号);// at instantiation:$form = new Zend_Form(array(    单引号elementPrefixPath单引号 => array(        array(            单引号prefix单引号 => 单引号My_Form_Decorator单引号,             单引号path单引号   => 单引号My/Form/Decorator/单引号,             单引号type单引号   => 单引号decorator单引号        ),    ),));// Or using an INI config file:form.elementPrefixPath.my.prefix = 双引号My_Form_Decorator双引号form.elementPrefixPath.my.path   = 双引号My/Form/Decorator双引号form.elementPrefixPath.my.type   = 双引号decorator双引号// Or using an XML config file:<form>    <elementPrefixPath>        <my>            <prefix>My_Form_Decorator</prefix>            <path>My/Form/Decorator</path>            <type>decorator</type>        </my>    </elementPrefixPath></form>


              Elements

              To set a plugin path for an individual element, you can call addPrefixPath($prefix, $path, 单引号decorator单引号) on your element itself, or pass values via the prefixPath configuration key. This would be primarily useful if you know that only a single or subset of elements is using custom decorator plugins, or if you need some elements to use standard decorators and others to use overridden decorators.

              The use cases are almost exactly like with Zend_Form:

              // Basic usage:$element->addPrefixPath($prefix, $path, 单引号decorator单引号);// Example:$element->addPrefixPath(单引号My_Form_Decorator单引号, 单引号My/Form/Decorator单引号, 单引号decorator单引号);// Configuring at instantiation:$element = new Zend_Form_Element(单引号foo单引号, array(    单引号prefixPath单引号 => array(        array(            单引号type单引号   => 单引号decorator单引号,             单引号path单引号   => 单引号My/Form/Decorator/单引号,             单引号prefix单引号 => 单引号My_Form_Decorator单引号        ),    ),));// or creating with a form object:$form->addElement(单引号text单引号, 单引号foo单引号, array(    单引号prefixPath单引号 => array(        array(            单引号type单引号   => 单引号decorator单引号,             单引号path单引号   => 单引号My/Form/Decorator/单引号,             单引号prefix单引号 => 单引号My_Form_Decorator单引号        ),    ),));// With an INI config:form.foo.options.prefixPath.my.type   = 双引号decorator双引号form.foo.options.prefixPath.my.path   = 双引号My/Form/Decorator/双引号form.foo.options.prefixPath.my.prefix = 双引号My_Form_Decorator双引号// With an XML config:<form>    <element>        <options>            <prefixPath>                <my>                    <type>decorator</type>                    <path>My/Form/Decorator/</path>                    <prefix>My_Form_Decorator</prefix>                </my>            </prefixPath>        </options>    </element></form>


              Example: Grouped Checkboxes

              Now that you know how decorators work, how to write your own, and how to tell your objects where to find them, let单引号s try it all out.

              For our use case, we want to create a group of checkboxes referring to tags. The checkboxes will be in an array structure two levels deep, with the first level referring to a category, and the second being the checkbox value/label pairs. We want to group each category of tags grouped in a fieldset with the category name as the legend, and listed with the label trailing each checkbox.

              One other thing we want to do is ensure that the labels for each checkbox are translated.

              We单引号ll call our decorator something descriptive, like 单引号CategorizedCheckbox单引号, because we单引号re developers, and we单引号ll use our own creatively named class prefix of 单引号My_Form_Decorator单引号.

              To start off, we need a registered element if we want to do anything, and that element should extend Zend_Form_Element_Multi; that way we know that getValue() will return an array. Additionally, we单引号re going to make use of Zend_View view helpers, so we need to ensure that a view object is registered with the element. Finally, we单引号ll grab our translation object for later use.

              class My_Form_Decorator_CategorizedCheckbox extends Zend_Form_Decorator_Abstract{    public function render($content)    {        $element = $this->getElement();        if (!$element instanceof Zend_Form_Element_Multi) {            return $content;        }        if (null === ($view = $element->getView())) {            return $content;        }        $translator = $element->getTranslator();    }}


              Now that we have that out of the way, let单引号s do some work. First, we单引号ll initialize the new content we want to create. Then we单引号ll grab our current values so we can test to see if a given checkbox is checked later. Also, we need to get the base name of the element so we can use it with the individual checkboxes, as well as create our checkbox IDs. Finally, we can start iterating over our options:

              class My_Form_Decorator_CategorizedCheckbox extends Zend_Form_Decorator_Abstract{    public function render($content)    {        // ...        $html     = 单引号单引号;        $values   = (array) $element->getValue();        $baseName = $element->getName();        foreach ($element->getMultiOptions() as $category => $values) {        }    }}


              Now we get to the fun part: generating the markup. Since fieldsets wrap content, we单引号ll generate a list of checkboxes first, and then wrap them in the fieldset. We can do this using view helpers. This is also where we will translate our labels. Checkboxes need names and ids as well, so we单引号ll build them here, just prior to passing them to our formCheckbox() view helper. When all options are complete for a category, we单引号ll wrap them in a fieldset, using the translated category as the legend.

              class My_Form_Decorator_CategorizedCheckbox extends Zend_Form_Decorator_Abstract{    public function render($content)    {        // ...        foreach ($element->getMultiOptions() as $category => $values) {            $boxes = 单引号<ul class=双引号checkboxes双引号>单引号;            foreach ($values as $value => $label) {                if ($translator instanceof Zend_Translate) {                    $label = $translator->translate($label);                }                $boxName = $baseName . 单引号[单引号 . $value . 单引号]单引号;                $boxId   = $basename . 单引号-单引号 . $value;                $attribs = array(                    单引号id单引号      => $boxId,                    单引号checked单引号 => in_array($value, $values),                );                $boxes .= 单引号<li>单引号                       .  $view->formCheckbox($boxName, $value, $attribs)                       .  $view->formLabel($boxName, $label)                       .  单引号</li>单引号;            }            $boxes .= 单引号</ul>单引号;            $legend = ($translator instanceof Zend_Translate)                    ? $translator->translate($category)                    : ucfirst($category);            $attribs = array(单引号legend单引号 => $legend);            $html .= $view->fieldset($category, $boxes, $attribs);        }    }}


              Finally, we need to return the content. We单引号ll assume that if no placement is specified, we want to replace the content, and otherwise honor the placement.

              class My_Form_Decorator_CategorizedCheckbox extends Zend_Form_Decorator_Abstract{    public function render($content)    {        // ...        $placement = $this->getPlacement();        $separator = $this->getSeparator();        switch ($placement) {            case 单引号APPEND单引号:                return $content . $separator . $html;            case 单引号PREPEND单引号:                return $html . $separator . $content;            case null:            default:                return $html;        }    }}


              And that单引号s it! We can now set this as a decorator on an element, and we单引号re done!

              Other Ways to Customize Decorators

              Most decorators allow a variety of options; you will need to check the documentation to determine what options are available. Many of these options will allow you to customize the output, so providing values or modifying them is an easy way to customize your forms.

              You have several methods available for setting options:

                setOption($key, $value) allows you to set a single option at a timesetOptions(array $options) allows you to set several options at once; $options should be an array of key/value pairs.Finally, you can also pass an array of options or a Zend_Config object when adding a decorator to the element or form:
                // Pas 单引号tag单引号 and 单引号class单引号 options at construction time:$element->addDecorator(单引号HtmlTag单引号, array(单引号tag单引号 => 单引号div单引号, 单引号class单引号 => 单引号foo单引号));        
                View Helpers

                Another way to modify your decorators, and specifically the ViewHelper decorator, is to override your view helpers. Overriding view helpers with your own custom view helpers is covered in a previous tutorial, and is a viable option for customizing your forms as well.

                In Conclusion

                Decorators are simple classes that deliver complex functionality: generating complex markup from your elements. Hopefully, with the information provided in this tutorial, you can now see how to combine decorators and write custom decorators to achieve custom markup to suit your site and application.

                文章来源:http://it503.com/detail.PHP
                添加收藏到:

                关键词:Decorators with Zend_Form,php
上一篇:__toString()方法
下一篇:16号学习笔记
联系我们 | 关于我们 | rss订阅 | 网络社区 | 网站帮助 | 网站地图
Copyright(C) 2006-2007 it503 All Rights Reserved
本站如有转载或引用的文章涉及版权问题请速与我们联系 由于将本站资源用于商业用途而引起的纠纷,本站不负任何责任。
冀ICP备07500673号