Skip to content

Commit

Permalink
Fix: active state in side menu for nested child admins (#8173)
Browse files Browse the repository at this point in the history
Co-authored-by: jaap <[email protected]>
  • Loading branch information
VincentLanglet and fastnloud authored Apr 10, 2024
1 parent f01fcd0 commit 58a5492
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 18 deletions.
43 changes: 27 additions & 16 deletions src/Menu/Matcher/Voter/AdminVoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,43 @@ public function __construct(

public function matchItem(ItemInterface $item): ?bool
{
$admin = $item->getExtra('admin');

$request = $this->requestStack->getMainRequest();
if (null === $request) {
return null;
}

if ($admin instanceof AdminInterface
$admin = $item->getExtra('admin');
if (
$admin instanceof AdminInterface
&& $admin->hasRoute('list') && $admin->hasAccess('list')
&& null !== $request
&& $this->match($admin, $request->get('_sonata_admin'))
) {
$requestCode = $request->get('_sonata_admin');

if ($admin->getCode() === $requestCode) {
return true;
}

foreach ($admin->getChildren() as $child) {
if ($child->getBaseCodeRoute() === $requestCode) {
return true;
}
}
return true;
}

$route = $item->getExtra('route');
if (null !== $route && null !== $request && $route === $request->get('_route')) {
if (null !== $route && $route === $request->get('_route')) {
return true;
}

return null;
}

/**
* @param AdminInterface<object> $admin
*/
private function match(AdminInterface $admin, mixed $requestCode): bool
{
if ($admin->getBaseCodeRoute() === $requestCode) {
return true;
}

foreach ($admin->getChildren() as $child) {
if ($this->match($child, $requestCode)) {
return true;
}
}

return false;
}
}
50 changes: 48 additions & 2 deletions tests/Menu/Matcher/Voter/AdminVoterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public function provideMatchingCases(): iterable
yield 'has admin' => [$this->getAdmin('_sonata_admin', true, true), '_sonata_admin', null, true];
yield 'has child admin' => [$this->getChildAdmin('_sonata_admin', '_sonata_child_admin', true, true), '_sonata_admin|_sonata_child_admin', null, true];
yield 'has bad child admin' => [$this->getChildAdmin('_sonata_admin', '_sonata_child_admin', true, true), '_sonata_admin|_sonata_child_admin_unexpected', null, null];
yield 'has nested child admin' => [$this->getNestedChildAdmin('_sonata_admin', '_sonata_child_admin', '_sonata_nested_child_admin', true, true), '_sonata_admin|_sonata_child_admin|_sonata_nested_child_admin', null, true];
yield 'has bad nested child admin' => [$this->getNestedChildAdmin('_sonata_admin', '_sonata_child_admin', '_sonata_nested_child_admin', true, true), '_sonata_admin|_sonata_child_admin|_sonata_nested_child_admin_unexpected', null, null];
yield 'direct link' => ['admin_post', null, 'admin_post', true];
yield 'no direct link' => ['admin_post', null, 'admin_blog', null];
}
Expand All @@ -81,7 +83,7 @@ private function getAdmin(string $code, bool $list = false, bool $granted = fals
->with('list')
->willReturn($granted);
$admin
->method('getCode')
->method('getBaseCodeRoute')
->willReturn($code);
$admin
->method('getChildren')
Expand Down Expand Up @@ -109,7 +111,7 @@ private function getChildAdmin(
->with('list')
->willReturn($granted);
$parentAdmin
->method('getCode')
->method('getBaseCodeRoute')
->willReturn($parentCode);

$childAdmin = $this->createMock(AdminInterface::class);
Expand All @@ -123,4 +125,48 @@ private function getChildAdmin(

return $parentAdmin;
}

/**
* @return AdminInterface<object>
*/
private function getNestedChildAdmin(
string $grandParentCode,
string $parentCode,
string $childCode,
bool $list = false,
bool $granted = false
): AdminInterface {
$grandParentAdmin = $this->createMock(AdminInterface::class);
$grandParentAdmin
->method('hasRoute')
->with('list')
->willReturn($list);
$grandParentAdmin
->method('hasAccess')
->with('list')
->willReturn($granted);
$grandParentAdmin
->method('getBaseCodeRoute')
->willReturn($grandParentCode);

$parentAdmin = $this->createMock(AdminInterface::class);
$parentAdmin
->method('getBaseCodeRoute')
->willReturn(sprintf('%s|%s', $grandParentCode, $parentCode));

$grandParentAdmin
->method('getChildren')
->willReturn([$parentAdmin]);

$childAdmin = $this->createMock(AdminInterface::class);
$childAdmin
->method('getBaseCodeRoute')
->willReturn(sprintf('%s|%s|%s', $grandParentCode, $parentCode, $childCode));

$parentAdmin
->method('getChildren')
->willReturn([$childAdmin]);

return $grandParentAdmin;
}
}

0 comments on commit 58a5492

Please sign in to comment.