Skip to content

Commit 3a77700

Browse files
authored
Merge pull request #309 from kynx/nested-validation-group
Fix error validating form with nested custom fieldset
2 parents f8d0428 + 10e231b commit 3a77700

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

src/Form.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use function in_array;
2323
use function is_array;
2424
use function is_object;
25+
use function iterator_to_array;
2526
use function sprintf;
2627

2728
/**
@@ -536,12 +537,24 @@ public function getValidationGroup(): ?array
536537
*/
537538
protected function prepareValidationGroup(Fieldset $formOrFieldset, array $data, array &$validationGroup): void
538539
{
539-
foreach ($validationGroup as $key => &$value) {
540-
$fieldset = $formOrFieldset->iterator->get((string) $key);
540+
$this->prepareFieldsetValidationGroup($formOrFieldset, $data, $validationGroup);
541+
}
541542

542-
if (! $fieldset) {
543+
/**
544+
* @fixme This is here to preserve BC on `prepareValidationGroup` and can be removed on next major if that method's
545+
* signature is changed to accept a `FieldsetInterface`
546+
*/
547+
private function prepareFieldsetValidationGroup(
548+
FieldsetInterface $formOrFieldset,
549+
array $data,
550+
array &$validationGroup
551+
): void {
552+
$elements = iterator_to_array($formOrFieldset->getIterator());
553+
foreach ($validationGroup as $key => &$value) {
554+
if (! isset($elements[$key])) {
543555
continue;
544556
}
557+
$fieldset = $elements[$key];
545558

546559
if ($fieldset instanceof CollectionInterface) {
547560
if (! isset($data[$key]) && $fieldset->getCount() === 0) {
@@ -563,7 +576,7 @@ protected function prepareValidationGroup(Fieldset $formOrFieldset, array $data,
563576
if (! isset($data[$key])) {
564577
$data[$key] = [];
565578
}
566-
$this->prepareValidationGroup($fieldset, $data[$key], $validationGroup[$key]);
579+
$this->prepareFieldsetValidationGroup($fieldset, $data[$key], $validationGroup[$key]);
567580
}
568581
}
569582

test/FormTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Laminas\InputFilter\InputFilter;
2626
use Laminas\InputFilter\InputFilterInterface;
2727
use Laminas\InputFilter\InputInterface;
28+
use Laminas\Stdlib\PriorityList;
2829
use LaminasTest\Form\TestAsset\Entity\Category;
2930
use PHPUnit\Framework\Attributes\DataProvider;
3031
use PHPUnit\Framework\Attributes\Group;
@@ -607,6 +608,54 @@ public function testFormWithCollectionAndValidationGroupBindValuesToModel(): voi
607608
self::assertFalse(isset($model->foobar));
608609
}
609610

611+
public function testFormWithNestedCustomCollectionAndValidationGroupBindValuesToModel(): void
612+
{
613+
$model = new stdClass();
614+
$data = [
615+
'foo' => 'abcde',
616+
'top_level' => [
617+
'categories' => [
618+
[
619+
'name' => 'category',
620+
],
621+
],
622+
],
623+
];
624+
$this->populateForm();
625+
626+
$collection = self::createStub(CollectionInterface::class);
627+
$collection->method('getName')
628+
->willReturn('categories');
629+
$collection->method('getIterator')
630+
->willReturn(new PriorityList());
631+
$collection->method('getTargetElement')
632+
->willReturn(new TestAsset\CategoryFieldset());
633+
634+
$fieldset = new Fieldset('top_level');
635+
$fieldset->add($collection);
636+
637+
$this->form->add($fieldset);
638+
$this->form->setHydrator(new ObjectPropertyHydrator());
639+
$this->form->bind($model);
640+
$this->form->setData($data);
641+
$this->form->setValidationGroup([
642+
'foo',
643+
'top_level' => [
644+
'categories' => [
645+
'name',
646+
],
647+
],
648+
]);
649+
$this->form->isValid();
650+
651+
self::assertTrue(isset($model->top_level));
652+
self::assertIsArray($model->top_level);
653+
self::assertTrue(isset($model->top_level['categories']));
654+
self::assertIsArray($model->top_level['categories']);
655+
self::assertIsArray($model->top_level['categories'][0]);
656+
self::assertEquals('category', $model->top_level['categories'][0]['name']);
657+
}
658+
610659
public function testSettingValidationGroupWithoutCollectionBindsOnlyThoseValuesToModel(): void
611660
{
612661
$model = new stdClass();

0 commit comments

Comments
 (0)