问题很简单但...... 所以我们有主要服务:
class ManagerOne {}
并且我们想要在主服务中使用其他几项服务:
class ServiceOne{}
class ServiceTwo{}
class ServiceThree{}
class ServiceFour{}
...
每个都命名为(在services.yml中)
service.one
service.two
service.three
service.four
...
服务的位置不同,不在一个文件夹中(但我不认为这对自定义自动加载器来说是一个很大的麻烦)。
关于手册,我们可以通过主服务(ManagerOne)中的__construct()注入它们,但是如果我们需要注入20个这样的服务呢?或者只使用我们需要的东西。在服务中将它们描述为简单注入? O.o我认为这不是一个好主意....我们也可以注入容器,就是这样。但!到处都有人说注入容器最差的解决方案。
我想要什么。我需要ManagerOne服务的方法,它将通过'service.name'或'path'加载我需要的服务,并且检查'服务存在'。
答案 0 :(得分:4)
您可以使用service tagging并标记要在ManagerOne
课程中使用的每项服务。并使用构造函数依赖注入或方法注入。
示例:
首先,您需要编译器传递来收集标记服务:
namespace ...\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ExamplePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition("manager.one")) {
return;
}
$services = array();
foreach ($container->findTaggedServiceIds('managed_service') as $serviceId => $tag) {
$alias = isset($tag[0]['alias'])
? $tag[0]['alias']
: $serviceId;
// Flip, because we want tag aliases (= type identifiers) as keys
$services[$alias] = new Reference($serviceId);
}
$container->getDefinition('manager.one')->replaceArgument(0, $services);
}
}
然后,您需要将编译器传递添加到bundle类:
namespace Example\ExampleBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use ...\DependencyInjection\Compiler\ExamplePass;
class ExampleBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ExamplePass());
}
}
现在您可以使用您的服务:
# services.yml
manager.one:
class: ManagerClass
arguments:
- [] # will be replaced by our compiler pass
services.one:
class: ServiceOne
tags:
- { name: managed_service, alias: service_one }
services.two:
class: ServiceTwo
tags:
- { name: managed_service, alias: service_two }
但请注意,如果您找到经理,将自动创建所有服务类。如果这是性能缺陷,您只能将服务ID(不是Reference)传递给管理类。添加@service_container
作为第二个参数,并根据需要创建服务。
答案 1 :(得分:0)
自2017年起,Symfony 3.3 和Symplify\PackageBuilder变得更加容易。
感谢此套餐,您可以:
CompilerPass
让我们来看看你的例子
假设您有
UpdateManager
班级UpdaterInterface
# app/config/services.yml
services:
_defaults:
autowire: true
App\:
resource: ../../src/App
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symplify\PackageBuilder\Adapter\Symfony\DependencyInjection\DefinitionCollector;
final class CollectorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $containerBuilder)
{
DefinitionCollector::loadCollectorWithType(
$containerBuilder,
UpdateManager::class,
UpdaterInterface::class,
'addUpdater'
);
}
}
它收集UpdaterInterface
类型的所有服务
并通过addUpdater()
方法将其添加到UpdateManager
。
namespace App;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
final class UpdaterBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new CollectorCompilerPass);
}
}
这就是全部!
只需创建实现UpdaterInterface
的类,它就会被加载到UpdateManager
。
享受!