Skip to content

Commit

Permalink
Prevent false deprecation error for n to m associations
Browse files Browse the repository at this point in the history
  • Loading branch information
jorrit committed Oct 1, 2020
1 parent b970f9d commit 90c6c5d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
33 changes: 32 additions & 1 deletion src/Controller/CRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,13 @@ private function checkParentChildAssociation(Request $request, object $object):
$propertyAccessor = PropertyAccess::createPropertyAccessor();
$propertyPath = new PropertyPath($this->admin->getParentAssociationMapping());

if ($parentAdmin->getObject($parentId) !== $propertyAccessor->getValue($object, $propertyPath)) {
$parentObject = $parentAdmin->getObject($parentId);
$objectParent = $propertyAccessor->getValue($object, $propertyPath);

// $objectParent may be an array or a Collection when the parent association is many to many.
$parentObjectMatches = self::equalsOrInList($parentObject, $objectParent);

if (!$parentObjectMatches) {
// NEXT_MAJOR: make this exception
@trigger_error(
'Accessing a child that isn\'t connected to a given parent is deprecated since sonata-project/admin-bundle 3.34 and won\'t be allowed in 4.0.',
Expand All @@ -1563,6 +1569,31 @@ private function checkParentChildAssociation(Request $request, object $object):
}
}

/**
* Checks whether $parentObject is equal to $childParentValue or part of it.
*
* @param object $needle Object to compare with $haystack
* @param object|iterable $haystack Object to compare with $needle
*
* @return bool true when $haystack equals $needle or $haystack is iterable and contains $needle
*/
private static function equalsOrInList(object $needle, $haystack): bool
{
if ($needle === $haystack) {
return true;
}

if (is_iterable($haystack)) {
foreach ($haystack as $haystackItem) {
if ($haystackItem === $needle) {
return true;
}
}
}

return false;
}

/**
* Sets the admin form theme to form view. Used for compatibility between Symfony versions.
*/
Expand Down
36 changes: 36 additions & 0 deletions tests/Controller/CRUDControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,42 @@ public function testDeleteActionInvalidCsrfToken(): void
}
}

public function testDeleteActionChildManyToMany(): void
{
$parent = new \stdClass();

$child = new \stdClass();
$child->parents = [$parent];

$parentAdmin = $this->createMock(PostAdmin::class);
$parentAdmin->method('getIdParameter')->willReturn('parent_id');

$childAdmin = $this->admin;
$childAdmin->method('getIdParameter')->willReturn('parent_id');

$parentAdmin->expects($this->once())
->method('getObject')
->willReturn($parent);

$childAdmin->expects($this->once())
->method('getObject')
->willReturn($child);

$childAdmin->expects($this->once())
->method('isChild')
->willReturn(true);

$childAdmin->expects($this->once())
->method('getParent')
->willReturn($parentAdmin);

$childAdmin->expects($this->exactly(2))
->method('getParentAssociationMapping')
->willReturn('parents');

$this->controller->deleteAction(1);
}

public function testEditActionNotFoundException(): void
{
$this->expectException(NotFoundHttpException::class);
Expand Down

0 comments on commit 90c6c5d

Please sign in to comment.