Skip to content

Commit

Permalink
Merge pull request #212 from riul88/hotfix/33
Browse files Browse the repository at this point in the history
Fixes #33 Collection has empty bonded nested objects
  • Loading branch information
Slamdunk authored Mar 23, 2023
2 parents 91dd0e8 + c815e31 commit 3c32741
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 7 deletions.
8 changes: 3 additions & 5 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@
<code>is_string($entity)</code>
</RedundantConditionGivenDocblockType>
</file>
<file src="src/Annotation/AnnotationBuilder.php">
<DeprecatedMethod>
<code><![CDATA[AnnotationRegistry::registerLoader('class_exists')]]></code>
</DeprecatedMethod>
</file>
<file src="src/Annotation/AttributeBuilder.php">
<NullArgument>
<code>$annotations</code>
Expand Down Expand Up @@ -363,6 +358,9 @@
</PossiblyNullArgument>
</file>
<file src="test/Annotation/AbstractBuilderTestCase.php">
<DocblockTypeContradiction>
<code>assertNotNull</code>
</DocblockTypeContradiction>
<PossiblyUndefinedMethod>
<code>allowEmpty</code>
<code>getFilterChain</code>
Expand Down
1 change: 1 addition & 0 deletions src/Annotation/ElementAnnotationsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public function handleComposedObjectAnnotation(EventInterface $e): void

$elementSpec['spec']['options']['target_element'] = $specification;
$elementSpec['spec']['options']['target_element']['options']['input_filter_spec'] = $inputFilter;
$elementSpec['spec']['options']['target_element']['options']['target_type'] = $class;

if (isset($specification['hydrator'])) {
$elementSpec['spec']['hydrator'] = $specification['hydrator'];
Expand Down
11 changes: 10 additions & 1 deletion src/Element/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@
use Laminas\Form\Fieldset;
use Laminas\Form\FieldsetInterface;
use Laminas\Form\FormInterface;
use Laminas\Form\InputFilterProviderFieldset;
use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\Exception\InvalidArgumentException;
use Traversable;

use function assert;
use function class_exists;
use function count;
use function gettype;
use function is_array;
use function is_int;
use function is_object;
use function is_string;
use function iterator_to_array;
use function max;
use function sprintf;
Expand Down Expand Up @@ -163,7 +166,7 @@ public function allowObjectBinding($object): bool
* Set the object used by the hydrator
* In this case the "object" is a collection of objects
*
* @param iterable $object
* @param iterable $object
* @return $this
* @throws Exception\InvalidArgumentException
*/
Expand Down Expand Up @@ -533,6 +536,12 @@ public function extract(): array
protected function createNewTargetElementInstance(): ElementInterface
{
assert($this->targetElement !== null);
if ($this->targetElement instanceof InputFilterProviderFieldset) {
if (null !== ($type = $this->targetElement->getOption('target_type'))) {
assert(is_string($type) && class_exists($type));
$this->targetElement->setObject(new $type());
}
}
return clone $this->targetElement;
}

Expand Down
41 changes: 40 additions & 1 deletion test/Annotation/AbstractBuilderTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
use LaminasTest\Form\ErrorHandler;
use LaminasTest\Form\TestAsset;
use LaminasTest\Form\TestAsset\Annotation\Entity;
use LaminasTest\Form\TestAsset\Annotation\EntityObjectPropertyHydrator;
use LaminasTest\Form\TestAsset\Annotation\Form;
use LaminasTest\Form\TestAsset\Annotation\InputFilter;
use LaminasTest\Form\TestAsset\Annotation\InputFilterInput;
use PHPUnit\Framework\TestCase;
use Throwable;

use function count;
use function getenv;

abstract class AbstractBuilderTestCase extends TestCase
Expand Down Expand Up @@ -261,7 +263,44 @@ public function testAllowsComposingMultipleChildEntities(): void
self::assertTrue($target->has('username'));
self::assertTrue($target->has('password'));
self::assertInstanceOf(InputFilterProviderFieldset::class, $target);
$filterSpec = $target->getInputFilterSpecification();
$this->validateEntityFilterSpec($target->getInputFilterSpecification());
}

public function testAllowsComposingMultipleChildEntitiesWithEntityBind(): void
{
$entity = new TestAsset\Annotation\EntityComposingMultipleEntitiesObjectPropertyHydrator();
$builder = $this->createBuilder();
$form = $builder->createForm($entity);

self::assertTrue($form->has('child'));
$child = $form->get('child');
self::assertInstanceOf(Collection::class, $child);
$target = $child->getTargetElement();
self::assertInstanceOf(FieldsetInterface::class, $target);
self::assertTrue($target->has('username'));
self::assertTrue($target->has('password'));
self::assertInstanceOf(InputFilterProviderFieldset::class, $target);
$this->validateEntityFilterSpec($target->getInputFilterSpecification());

self::assertNull($entity->child);
$form->bind($entity);
$form->setData([
'child' => [
'0' => ['password' => '[email protected]', 'username' => 'user'],
'1' => ['password' => '[email protected]', 'username' => 'user2'],
],
]);
self::assertTrue($form->isValid());
self::assertNotNull($entity->child);
self::assertEquals(2, count($entity->child));
self::assertInstanceOf(EntityObjectPropertyHydrator::class, $entity->child[0]);
self::assertEquals('[email protected]', $entity->child[0]->password);
self::assertEquals('user', $entity->child[0]->username);
self::assertInstanceOf(EntityObjectPropertyHydrator::class, $entity->child[1]);
}

protected function validateEntityFilterSpec(array $filterSpec): void
{
self::assertArrayHasKey('username', $filterSpec);
self::assertArrayHasKey('password', $filterSpec);
$usernameFilterSpec = $filterSpec['username'];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace LaminasTest\Form\TestAsset\Annotation;

use Laminas\Form\Annotation;
use Laminas\Hydrator\ObjectPropertyHydrator;

/**
* @Annotation\Name("hierarchical")
* @Annotation\Hydrator("Laminas\Hydrator\ObjectPropertyHydrator")
*/
#[Annotation\Name("hierarchical")]
#[Annotation\Hydrator(ObjectPropertyHydrator::class)]
class EntityComposingMultipleEntitiesObjectPropertyHydrator
{
/**
* @var null|list<EntityObjectPropertyHydrator>
* @Annotation\ComposedObject("LaminasTest\Form\TestAsset\Annotation\EntityObjectPropertyHydrator", isCollection=true)
*/
#[Annotation\ComposedObject(
EntityObjectPropertyHydrator::class,
isCollection: true,
options: ['create_new_objects' => true]
)]
public ?array $child = null;
}
16 changes: 16 additions & 0 deletions test/TestAsset/Annotation/EntityObjectPropertyHydrator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace LaminasTest\Form\TestAsset\Annotation;

use Laminas\Form\Annotation;
use Laminas\Hydrator\ObjectPropertyHydrator;

/**
* @Annotation\Hydrator("Laminas\Hydrator\ObjectPropertyHydrator")
*/
#[Annotation\Hydrator(ObjectPropertyHydrator::class)]
class EntityObjectPropertyHydrator extends Entity
{
}

0 comments on commit 3c32741

Please sign in to comment.