-
Notifications
You must be signed in to change notification settings - Fork 201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Missing documentation about autowiring #368
Comments
Well, this doc is perfectly valid today. The only change with autowiring is that you can remove the definition of the constructor arguments (the FactoryInterface implementation can be injected by the autowiring). I have a new feature in my TODO list which will make it much easier to use the library in alongside autoconfiguration. But it is not there yet |
I know the docs are still valid, but I think it's a pity to miss showing the new features. I think docs should be expanded to cover both options, the old ones and the new ones. app.menu.main:
class: Knp\Menu\MenuItem
factory: ['@App\Menu\Builder', createMenu]
tags:
- { name: knp_menu.menu, alias: main } Can I exploit somehow the autowiring/autoconfigure? |
+1 |
@garak only in my head. I know exactly how I want this to work for autoconfiguration, but I have not written the code yet (I need a few hours available for that but I'm quite busy these days) |
Sorry for bumping (I know it's not really nice), but I was wondering if there are some news here. |
This works, apparently: services:
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundle\Menu\:
resource: '../../src/AppBundle/Menu/*'
AppBundle\Menu\Builder:
tags:
- { name: knp_menu.menu_builder, method: mainMenu, alias: main } {{ knp_menu_render('main', { 'template': 'knpmenu/knp_menu.html.twig' }) }} But I couldn't get it working without the tag. If I try to render the menu like this {{ knp_menu_render('AppBundle:Builder:mainMenu', { 'template': 'knpmenu/knp_menu.html.twig' }) }}
|
This is my idea for autowiring menu builders: we can create an interface and add tag/alias to all classes implementing it. <?php
namespace Knp\Bundle\MenuBundle;
use Knp\Menu\ItemInterface;
interface MenuBuilderInterface
{
public function build(): ItemInterface;
public function getAlias(): string;
} |
I added support of autoconfigurable menu builder services in my apps using an interface, I think people following this issue might be interested in the code : // Here the usage
namespace App\Menu;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
class SidebarBuilder implements MenuBuilderInterface
{
private FactoryInterface $factory;
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
static public function getAlias(): string
{
return 'sidebar';
}
public function build(array $options): ItemInterface
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', ['route' => 'hompage']);
return $menu;
}
} The interface is inspired by the autoconfigurable Symfony 4.2 FormTypeExtensionInterface. I don't use multiple builders in a service but an interface like EventSubscriberInterface could be provided instead of the one I used to allow this usage. This works with a compiler pass adding menu builder services to those managed by the bundle (tagged by If the maintainers are ok with an autoconfigurable interface in the bundle I can make a merge request (not with this solution of course) How to setup (click here to show code)This is just how I did it, feel free to adapt the code to your use case if necessary. namespace App\Menu;
use Knp\Menu\ItemInterface;
// The interface enforce a statically available alias and a build method
interface MenuBuilderInterface
{
/**
* Statically available alias (like alias property in knp tags)
*/
static public function getAlias(): string;
/**
* Build method (like method property in knp tags)
*/
public function build(array $options): ItemInterface;
} namespace App\Compiler;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class RegisterMenuBuildersPass implements CompilerPassInterface
{
private string $tagName;
public function __construct(string $tagName)
{
$this->tagName = $tagName;
}
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('knp_menu.menu_provider.lazy')) {
return;
}
$providerDefinition = $container->getDefinition('knp_menu.menu_provider.lazy');
$builders = $providerDefinition->getArgument(0);
foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tag) {
$alias = $container->getDefinition($id)->getClass()::getAlias();
$builders[$alias] = [new ServiceClosureArgument(new Reference($id)), 'build'];
}
$providerDefinition->replaceArgument(0, $builders);
}
} namespace App;
use App\Compiler\RegisterMenuBuildersPass;
use App\Menu\MenuBuilderInterface;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function build(ContainerBuilder $container): void
{
// Tag name used to discover services using the menu builder interface
$menuBuilderTagName = 'app.menu_builder';
// Autoconfigure the discovery tag so you don't need to do it manually
$container->registerForAutoconfiguration(MenuBuilderInterface::class)
->addTag($menuBuilderTagName);
// Add the compiler pass to handle menu builders using our interface
$container->addCompilerPass(new RegisterMenuBuildersPass($menuBuilderTagName));
}
} |
@wryk yes please! |
I started the work a few years ago in #392, but I never finished it |
Current docs are still showing the old approach (e.g. the one working with Symfony < 3.4).
We need to cover also the new autowiring features of Symfony 3.4/4.0
The text was updated successfully, but these errors were encountered: