ZF-4841: Zend_Form_Decorator_Label->setTag() produces invalid XHMTL

Description

Description:

The tag "option" does not appear to be cleared properly when setTag is used and is rendered as an html property.


$start_date = new Zend_Form_Element_Text('start_date', array('label' => 'Start Date'));
$start_date->getDecorator('label')->setTag('div');
$form->addElement($start_date);

Produces:


Start Date

Index: Form/Decorator/Label.php
===================================================================
--- Form/Decorator/Label.php    (revision 12325)
+++ Form/Decorator/Label.php    (working copy)
@@ -289,6 +289,10 @@
         }   
 
         if (!empty($label)) {
+           if (!empty($tag) && isset($options['tag'])) {
+               unset($options['tag']);
+           }
+
             $options['class'] = $class;
             $label = $view->formLabel($element->getFullyQualifiedName(), trim($label), $options); 
         } else {

Comments

I encounter this problem as well, and not only with the Label decorator. Setting a tag on an HtmlTag decorator instance will render some invalid HTML code, with the tag attribute being rendered.

This doesn't happen when no tag is defined (the default one is used instead) because the getTag() method of the decorator (called in the render() method) will try to get this attribute from the options, set it in the object property with the setTag() method, and then explicitly remove the "tag" attribute from the options using removeOption().

The patch I made is slightly different to yours, as the setTag() method now sets the provided tag in the options instead of the class property, and then it will be the getTag() option which will do the same job as it did. I did that to ensure that the default "dt" tag option is never used between the time the object is instantiated and the time it is rendered.


Index: Form/Decorator/Label.php
===================================================================
--- Form/Decorator/Label.php    (revision 13615)
+++ Form/Decorator/Label.php    (working copy)
@@ -101,7 +101,7 @@
         if (empty($tag)) {
             $this->_tag = null;
         } else {
-            $this->_tag = (string) $tag;
+            $this->setOption('tag', (string) $tag);
         }
         return $this;
     }
@@ -117,7 +117,7 @@
             $tag = $this->getOption('tag');
             if (null !== $tag) {
                 $this->removeOption('tag');
-                $this->setTag($tag);
+                $this->_tag = $tag;
             }
             return $tag;
         }
 

This issue has a root cause that is not addressed by either of the fixes above.

The getTag() method checks the options array for a tag option and correctly removes it if found. However, when there is an explicit call to setTag(), the tag option is not removed.

If the intention is to clear the tag, this causes a problem as the getTag() method will restore the original tag from the options array if it has been supplied.

If the intention is to change the tag, the 'tag' option is still passed to the HtmlTag decorator and rendered as an attribute.

Since, by default, the decorator is initialised by Zend_Form_Element with a tag option of 'dt', this affects the most common use case.

The fix is to remove the 'tag' option (if it exists) whenever setTag() is called. Patch for Label.php and LabelTest.php attached.

Index: Label.php

--- Label.php (revision 19044) +++ Label.php (working copy) @@ -103,6 +103,8 @@ } else { $this->_tag = (string) $tag; } + $this->removeOption('tag'); + return $this; }

Patch from Steve applied to trunk and 1.9 release branch.