例如,我有一些界面:
interface ISmsRepository {
public function send(SmsMessage $sms);
}
我已经实现了这个类:
class SmsRepository implements ISmsRepository{/**some implementation*/}
现在我想实现SmsRepository类的装饰器:
class QueueSmsRepository implements ISmsRepository{
/**
* @var ISmsRepository
*/
private $smsRepository;
public function __construct(ISmsRepository $repository) {
$this->smsRepository = $repository;
}
public function send(SmsMessage $sms) {
//some addable actions
$this->smsRepository->send($sms);
}
}
我可以使用多个装饰器。我如何在配置中描述它?我试着这样做:
<service id="manyrus.sms_bundle.decorated.epochta.sms_repository"
class="Manyrus\SmsBundle\Lib\Decorators\QueueSmsRepository">
<argument type="service" id="manyrus.sms_bundle.decorated.epochta.sms_repository"/>
</service>
但我有一个错误:
检测到服务“manyrus.sms_bundle.decorated.epochta.sms_repository”的循环引用,路径:“manyrus.sms_bundle.decorated.epochta.sms_repository - &gt; manyrus.sms_bundle.decorated.epochta.sms_repository”。
我不知道该怎么办。现在,我看到只有一个退出这种情况 - 创建服务,它将装饰我的SmsRepository。你有什么想法吗?
答案 0 :(得分:1)
您可以使用decorating-services而无需使用编译器传递。
<service id="manyrus_decorated"
class="Manyrus\SmsBundle\Lib\SmsRepository">
<argument />
</service>
<service id="manyrus_decorator" class="Manyrus\SmsBundle\Lib\Decorators\QueueSmsRepository" decorates="manyrus_decorated" public="false">
<argument type="service" id="manyrus_decorator.inner" />
</service>
然后您仍然使用原始服务名称:
manyrus_decorated
答案 1 :(得分:0)
您必须手动更改某些定义。您可以直接在扩展文件中执行此操作,但如果您希望其他捆绑包能够添加装饰器,我建议您使用compiler pass:
// ../DependencyInjection/Compiler/DecorateSmsRepository.php
namespace Manyrus\SmsBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class DecorateSmsRepository implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$repositoryId = 'manyrus.sms_bundle.decorated.epochta.sms_repository';
if (!$container->hasDefinition($repositoryId)) {
return;
}
$definition = $container->getDefinition($repositoryId);
// Retrieve the ids of the services tagged with "manyrus.sms_bundle.sms_repository.decorator".
$taggedServices = $container->findTaggedServiceIds(
'manyrus.sms_bundle.sms_repository.decorator'
);
foreach ($taggedServices as $id => $attributes) {
// Replace the first argument passed to the constructor by the decorator.
$definition->replaceArgument(0, new Reference($id));
// Chain the decorator mechanism.
$definition = $container->getDefinition($id);
$repositoryId = $id;
}
// Set an alias on the last decorator (this will be the service you want to use).
$container->setAlias(
'manyrus.sms_bundle.decorated.epochta.decorated_sms_repository',
new Alias($repositoryId, false)
);
}
}
您的服务定义应为:
<service id="manyrus.sms_bundle.decorated.epochta.sms_repository"
class="Manyrus\SmsBundle\Lib\SmsRepository">
<argument />
</service>
<service id="manyrus.sms_bundle.decorated.epochta.sms_repository.decorator.queue"
class="Manyrus\SmsBundle\Lib\Decorators\QueueSmsRepository">
<argument />
<tag name="manyrus.sms_bundle.sms_repository.decorator" />
</service>
最后要做的是在捆绑文件中注册编译器传递:
// ../ManyrusSmsBundle.php
namespace Manyrus\SmsBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Manyrus\SmsBundle\DependencyInjection\Compiler\DecorateSmsRepository;
class DaOAuthClientBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new DecorateSmsRepository());
}
}
然后您可以使用服务manyrus.sms_bundle.decorated.epochta.decorated_sms_repository
。