Skip to content

Commit

Permalink
Add support for ArrayAccess
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Nov 27, 2021
1 parent 8173cdb commit f6456b7
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 8 deletions.
9 changes: 4 additions & 5 deletions src/Admin/AdminHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

namespace Sonata\AdminBundle\Admin;

use Doctrine\Common\Collections\Collection;
use Sonata\AdminBundle\Exception\NoValueException;
use Sonata\AdminBundle\FieldDescription\FieldDescriptionInterface;
use Sonata\AdminBundle\Manipulator\ObjectManipulator;
Expand Down Expand Up @@ -167,10 +166,10 @@ public function appendFormFieldElement(AdminInterface $admin, object $subject, s

$collection = $this->propertyAccessor->getValue($subject, $path);

if (!($collection instanceof Collection)) {
if (!$collection instanceof \ArrayAccess && !\is_array($collection)) {
throw new \TypeError(sprintf(
'Collection must be an instance of %s, %s given.',
Collection::class,
'Collection must be an instance of %s or array, %s given.',
\ArrayAccess::class,
\is_object($collection) ? 'instance of "'.\get_class($collection).'"' : '"'.\gettype($collection).'"'
));
}
Expand All @@ -180,7 +179,7 @@ public function appendFormFieldElement(AdminInterface $admin, object $subject, s
explode('.', preg_replace('#\[\d*?]#', '', $path) ?? '')
);

$collection->add(new $modelClassName());
$collection[] = new $modelClassName();
$this->propertyAccessor->setValue($subject, $path, $collection);

$fieldDescription = null;
Expand Down
117 changes: 114 additions & 3 deletions tests/Admin/AdminHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public function testAppendFormFieldElement(): void
}
}

public function testAppendFormFieldElementWithoutFormFieldDescriptionInAdminAndNoCollectionClass(): void
public function testAppendFormFieldElementWithoutFormFieldDescriptionInAdminAndNoArrayAccess(): void
{
$admin = $this->createMock(AdminInterface::class);
$admin
Expand Down Expand Up @@ -329,7 +329,7 @@ public function testAppendFormFieldElementWithoutFormFieldDescriptionInAdminAndN
$admin->method('getFormBuilder')->willReturn($formBuilder);

$this->expectException(\TypeError::class);
$this->expectExceptionMessage(sprintf('Collection must be an instance of %s, "%s" given.', Collection::class, \gettype(null)));
$this->expectExceptionMessage(sprintf('Collection must be an instance of %s or array, "%s" given.', \ArrayAccess::class, \gettype(null)));
$this->helper->appendFormFieldElement($admin, $foo, 'test_bar');
}

Expand Down Expand Up @@ -444,6 +444,117 @@ public function setBar(Collection $bar): void
}
}

public function testAppendFormFieldElementWithArray(): void
{
$admin = $this->createMock(AdminInterface::class);
$admin
->method('getClass')
->willReturn(Foo::class);

$associationAdmin = $this->createMock(AdminInterface::class);
$associationAdmin
->method('getClass')
->willReturn(Bar::class);

$associationMapping = [
'fieldName' => 'bar',
'targetEntity' => Foo::class,
'sourceEntity' => Foo::class,
'isOwningSide' => false,
];

$fieldDescription = $this->createStub(FieldDescriptionInterface::class);
$fieldDescription->method('getAssociationAdmin')->willReturn($associationAdmin);
$fieldDescription->method('getAssociationMapping')->willReturn($associationMapping);
$fieldDescription->method('getParentAssociationMappings')->willReturn([]);

$admin
->method('getFormFieldDescription')
->willReturn($fieldDescription);

$associationAdmin
->method('getFormFieldDescriptions')
->willReturn([
'bar' => $fieldDescription,
]);

$admin
->method('hasFormFieldDescription')
->with($associationMapping['fieldName'])
->willReturn(false);

$request = new Request([], [
'test' => [
'bar' => [
[
'baz' => [
'baz' => true,
],
],
['_delete' => true],
],
],
]);

$admin
->method('getRequest')
->willReturn($request);

$foo = new class() {
/** @var Collection<int, Bar> */
private $bar;

public function __construct()
{
$this->bar = new ArrayCollection();
}

/** @return array<int, Bar> */
public function getBar(): array
{
return $this->bar->toArray();
}

/** @param array<int, Bar> $bar */
public function setBar(array $bar): void
{
$this->bar = new ArrayCollection($bar);
}
};

$admin
->method('hasSubject')
->willReturn(true);
$admin
->method('getSubject')
->willReturn($foo);

$dataMapper = $this->createStub(DataMapperInterface::class);
$formFactory = $this->createStub(FormFactoryInterface::class);
$eventDispatcher = $this->createStub(EventDispatcherInterface::class);
$formBuilder = new FormBuilder('test', \get_class($foo), $eventDispatcher, $formFactory);
$formBuilder->setRequestHandler(new HttpFoundationRequestHandler());
$childFormBuilder = new FormBuilder('bar', \stdClass::class, $eventDispatcher, $formFactory);
$childFormBuilder->setCompound(true);
$childFormBuilder->setDataMapper($dataMapper);
$subChildFormBuilder = new FormBuilder('baz', \stdClass::class, $eventDispatcher, $formFactory);
$subChildFormBuilder->setCompound(true);
$subChildFormBuilder->setDataMapper($dataMapper);
$childFormBuilder->add($subChildFormBuilder);

$formBuilder->setCompound(true);
$formBuilder->setDataMapper($dataMapper);
$formBuilder->add($childFormBuilder);

$admin->method('getFormBuilder')->willReturn($formBuilder);

$finalForm = $this->helper->appendFormFieldElement($admin, $foo, 'test_bar')[1];

foreach ($finalForm->get($childFormBuilder->getName()) as $childField) {
static::assertFalse($childField->has('_delete'));
}
}

public function testAppendFormFieldElementNested(): void
{
$admin = $this->createMock(AdminInterface::class);
Expand Down Expand Up @@ -498,7 +609,7 @@ public function testAppendFormFieldElementNested(): void
$admin->expects(static::once())->method('getFormBuilder')->willReturn($formBuilder);

$this->expectException(\TypeError::class);
$this->expectExceptionMessage(sprintf('Collection must be an instance of %s, "string" given.', Collection::class));
$this->expectExceptionMessage(sprintf('Collection must be an instance of %s or array, "string" given.', \ArrayAccess::class));

$this->helper->appendFormFieldElement($admin, $object, 'uniquePartOfId_sub_object_0_and_more_0_final_data');
}
Expand Down

0 comments on commit f6456b7

Please sign in to comment.