ZF-9348: Zend_Form isValid() does not validate SubForm with equal named Child Element
Description
When adding a SubForm with Name foo and an Element to that SubForm which is named foo as well, isValid fails to validate the Elements Value.
Following is happening: the call
$data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
will convert
$data = array('foo'=> array('bar' => $wantedData));
$elementsBelongTo = foo[bar]
into
$data = $wantedData;
But only if isArray() === true.
So when a SubForm which (isArray() === true) by default, has a child with the same name
$subforname = 'baz'
$elementname = 'baz'
$elementsBelongTo = 'foo[bar]'
$data = array('foo' => array('bar' => array('baz' => 'Element Value')));
($data = array('baz' => 'Element Value')) === $this->_dissolveArrayValue($data, $elementsBelongTo);
and then later on
if (isset($data[$key])) {
/**
* yes because array('baz' => 'Element Value');
*/
$valid = $form->isValid($data[$key]) && $valid;
/**
* OOuuuchh
*/
}
My Statement is that _dissolveArrayValue should be called even when !isArray() because that does not matter anyway as ElementsBelongTo returns $formName when !isArray() and then _dissolveArrayValue will dissolve for $formName instead of $elementsBelongTo.
So now i know that this is wrong because $form->getElementsBelongTo() returns the name only when (true === $form->isArray() && null === $form->_elementsBelongTo)
So the right solution is
if (isset($data[$key]) && !$form->isArray()) {
/**
* now we can be sure that $this->_dissolveArrayValue did not dissolve anything
*/
$valid = $form->isValid($data[$key]) && $valid;
}
Word.
This patch definitely fixes the issue.
Index: tests/Zend/Form/FormTest.php
===================================================================
--- tests/Zend/Form/FormTest.php (Revision 21667)
+++ tests/Zend/Form/FormTest.php (Arbeitskopie)
@@ -1473,7 +1473,25 @@
$this->assertTrue($this->form->isValid($data));
}
+ public function testIsValidEqualSubFormAndElementName()
+ {
+ $this->form->addSubForm(new Zend_Form_SubForm(), 'foo')
+ ->foo->addElement('text', 'foo')
+ ->foo->setRequired(true)
+ ->addValidator('Identical',
+ false,
+ array('Foo Value'));
+ $foo = array('foo' =>
+ array('foo' => 'Foo Value'));
+ $this->assertTrue($this->form->isValid($foo));
+
+ $this->form->foo->setIsArray(false);
+
+ $this->assertTrue($this->form->isValid($foo));
+ }
+
+
// Display groups
public function testCanAddAndRetrieveSingleDisplayGroups()
Index: library/Zend/Form.php
===================================================================
--- library/Zend/Form.php (Revision 21667)
+++ library/Zend/Form.php (Arbeitskopie)
@@ -2044,7 +2044,7 @@
if (null !== $translator && !$form->hasTranslator()) {
$form->setTranslator($translator);
}
- if (isset($data[$key])) {
+ if (isset($data[$key]) && !$form->isArray()) {
$valid = $form->isValid($data[$key]) && $valid;
} else {
$valid = $form->isValid($data) && $valid;
And for Rob :)
public function testIsValidEqualSubFormAndElementName()
{
$this->form->addSubForm(new Zend_Form_SubForm(), 'foo')
->foo->addElement('text', 'foo')
->foo->setRequired(true)
->addValidator('Identical',
false,
array('Foo Value'));
$foo = array('foo' =>
array('foo' => 'Foo Value'));
$this->assertTrue($this->form->isValid($foo));
$this->form->foo->setIsArray(false);
$this->assertTrue($this->form->isValid($foo));
}
Comments
Posted by Christian Albrecht (alab) on 2010-03-29T06:06:57.000+0000
Updated the Test, checks now against $form->setIsArray(false) as well.
Posted by Matthew Weier O'Phinney (matthew) on 2010-03-31T09:18:06.000+0000
Patch applied to trunk and 1.10 release branch.