Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions app/Menu/AdminMenuBuilder.php → app/Menu/AdminMenuListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,16 @@
namespace App\Menu;

use Knp\Menu\ItemInterface;
use Sylius\AdminUi\Knp\Menu\MenuBuilderInterface;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Sylius\AdminUi\Knp\Menu\Event\MenuBuilderEvent;
use Sylius\AdminUi\Knp\Menu\MenuBuilder;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsDecorator(decorates: 'sylius_admin_ui.knp.menu_builder')]
final class AdminMenuBuilder implements MenuBuilderInterface
#[AsEventListener(MenuBuilder::EVENT_NAME)]
final class AdminMenuListener
{
public function __construct(private MenuBuilderInterface $menuBuilder)
public function __invoke(MenuBuilderEvent $event): void
{
}

public function createMenu(array $options): ItemInterface
{
$menu = $this->menuBuilder->createMenu($options);
$menu = $event->getMenu();

$menu
->addChild('dashboard', [
Expand All @@ -38,8 +35,6 @@ public function createMenu(array $options): ItemInterface

$this->addLibrarySubMenu($menu);
$this->addConfigurationSubMenu($menu);

return $menu;
}

private function addLibrarySubMenu(ItemInterface $menu): void
Expand Down
34 changes: 13 additions & 21 deletions docs/cookbook/admin_panel/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,25 @@

</div>

To customize the admin menu, you need to decorate the `sylius_admin_ui.knp.menu_builder` service.
To customize the admin menu, you need to listen for the `sylius_admin_ui.menu.event.main` event. This way, you can implement
multiple listeners e.g. in different bounded contexts of your application.

```php
declare(strict_types=1);

namespace App\Menu;

use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Sylius\AdminUi\Knp\Menu\MenuBuilderInterface;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Sylius\AdminUi\Knp\Menu\Event\MenuBuilderEvent;
use Sylius\AdminUi\Knp\Menu\MenuBuilder;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsDecorator(decorates: 'sylius_admin_ui.knp.menu_builder')]
final readonly class MenuBuilder implements MenuBuilderInterface
#[AsEventListener(MenuBuilder::EVENT_NAME)]
final readonly class MenuListener
{
public function __construct(
private readonly FactoryInterface $factory,
) {
}

public function createMenu(array $options): ItemInterface
public function __invoke(MenuBuilderEvent $event): void
{
$menu = $this->factory->createItem('root');
$menu = $event->getMenu();

$menu
->addChild('dashboard', [
Expand All @@ -41,8 +37,6 @@ final readonly class MenuBuilder implements MenuBuilderInterface
->setLabel('sylius.ui.dashboard')
->setLabelAttribute('icon', 'tabler:dashboard')
;

return $menu;
}
}
```
Expand All @@ -59,18 +53,16 @@ Now you can add submenu items:

```php
// ...
#[AsDecorator(decorates: 'sylius_admin_ui.knp.menu_builder')]
final readonly class MenuBuilder implements MenuBuilderInterface
#[AsEventListener(MenuBuilder::EVENT_NAME)]
final readonly class MenuListener
{
// ...

public function createMenu(array $options): ItemInterface
public function __invoke(MenuBuilderEvent $event): void
{
$menu = $this->factory->createItem('root');
$menu = $event->getMenu();
// ...
$this->addLibrarySubMenu($menu);

return $menu;
}

private function addLibrarySubMenu(ItemInterface $menu): void
Expand Down
2 changes: 1 addition & 1 deletion src/AdminUi/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
$services = $configurator->services();

$services->set('sylius_admin_ui.knp.menu_builder', MenuBuilder::class)
->args([service('knp_menu.factory')])
->args([service('knp_menu.factory'), service('event_dispatcher')])
->tag(name: 'knp_menu.menu_builder', attributes: ['method' => 'createMenu', 'alias' => 'sylius_admin_ui.menu.sidebar'])
;
$services->alias(MenuBuilderInterface::class, 'sylius_admin_ui.knp.menu_builder');
Expand Down
37 changes: 37 additions & 0 deletions src/AdminUi/src/Knp/Menu/Event/MenuBuilderEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\AdminUi\Knp\Menu\Event;

use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Contracts\EventDispatcher\Event;

final class MenuBuilderEvent extends Event
{
public function __construct(
private readonly FactoryInterface $factory,
private readonly ItemInterface $menu,
) {
}

public function getFactory(): FactoryInterface
{
return $this->factory;
}

public function getMenu(): ItemInterface
{
return $this->menu;
}
}
19 changes: 16 additions & 3 deletions src/AdminUi/src/Knp/Menu/MenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,28 @@

use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Sylius\AdminUi\Knp\Menu\Event\MenuBuilderEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

final class MenuBuilder implements MenuBuilderInterface
{
public function __construct(private readonly FactoryInterface $factory)
{
public const EVENT_NAME = 'sylius_admin_ui.menu.event.main';

public function __construct(
private readonly FactoryInterface $factory,
private readonly EventDispatcherInterface $eventDispatcher,
) {
}

public function createMenu(array $options): ItemInterface
{
return $this->factory->createItem('root');
$root = $this->factory->createItem('root');

$this->eventDispatcher->dispatch(
new MenuBuilderEvent($this->factory, $root),
self::EVENT_NAME,
);

return $root;
}
}
45 changes: 45 additions & 0 deletions src/AdminUi/tests/Unit/Knp/Menu/MenuBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Tests\Sylius\AdminUi\Unit\Knp\Menu;

use Knp\Menu\FactoryInterface;
use Knp\Menu\MenuItem;
use PHPUnit\Framework\TestCase;
use Sylius\AdminUi\Knp\Menu\Event\MenuBuilderEvent;
use Sylius\AdminUi\Knp\Menu\MenuBuilder;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

final class MenuBuilderTest extends TestCase
{
public function testItCreatesMenuRootAndThrowsEvent(): void
{
$factory = $this->createMock(FactoryInterface::class);
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
$menuBuilder = new MenuBuilder($factory, $eventDispatcher);

$root = new MenuItem('root', $factory);

$factory
->expects($this->once())
->method('createItem')
->with('root')
->willReturn($root)
;

$event = new MenuBuilderEvent($factory, $root);
$eventDispatcher->expects($this->once())->method('dispatch')->with($event, 'sylius_admin_ui.menu.event.main');

self::assertSame($root, $menuBuilder->createMenu([]));
}
}
13 changes: 13 additions & 0 deletions tests/Functional/BookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,17 @@ public function testRemovingBook(): void

$this->assertCount(0, BookFactory::all());
}

public function testShowingMenu(): void
{
$this->client->request('GET', '/admin/books');

self::assertSelectorExists('#sidebar-menu');

self::assertAnySelectorTextContains('#sidebar-menu [href="#navbar-library"]', 'Library');
self::assertAnySelectorTextContains('#sidebar-menu [href="#navbar-configuration"]', 'Configuration');
self::assertAnySelectorTextContains('#sidebar-menu [href="/admin/conferences"]', 'Conferences');
self::assertAnySelectorTextContains('#sidebar-menu [href="/admin/talks"]', 'Talks');
self::assertAnySelectorTextContains('#sidebar-menu [href="/admin/speakers"]', 'Speakers');
}
}