我有几个服务:DieselCaseService,CarloanCaseService LvCaseService。
控制器决定要获取的服务。
$type = $quickCheck["type"];
/**
* @var $caseService \App\Service\Cases\CaseInterface
*/
$type = 'diesel; // for test purposes
$caseService = $this->get('case_service.' . $type);
服务别名的声明如下:
case_service.diesel:
alias: App\Service\Cases\DieselCaseService
public: true
class DieselCaseService implements CaseInterface
{
.
.
.
}
如果我尝试获取DieselCaseService,则会收到错误消息
找不到服务“ case_service.diesel”:即使该服务存在于
应用程序的容器,容器内部
“ App \ Controller \ Api \ AccountController”是一个较小的服务定位器 只知道“教义”,“ form.factory”,
“ fos_rest.view_handler”,“ http_kernel”,“ parameter_bag”,
“ request_stack”,“路由器”,“ security.authorization_checker”,
“ security.csrf.token_manager”,“ security.token_storage”,“序列化器”,
“会话”,“模板”和“树枝”服务。尝试使用依赖项
而是注射。
我该怎么办?我不想将所有服务注入到控制器中
答案 0 :(得分:3)
对于任何“按键具有相同类型的多个实例”的情况,可以使用自动装配的数组。
App\
名称空间的自动发现服务services:
_defaults:
autowire: true
App\:
resource: ../src
<?php
namespace App\Controller\Api;
use App\Service\Cases\DieselCaseService
final class AccountController
{
/**
* @var CaseInterface[]
*/
private $cases;
/**
* @param CaseInterface[] $cases
*/
public function __construct(array $cases)
{
foreach ($cases as $case) {
$this->cases[$case->getName()] = $cases;
}
}
public function someAction(): void
{
$dieselCase = $this->cases['diesel']; // @todo maybe add validation for exisiting key
$dieselCase->anyMethod();
}
}
自动接线阵列功能不在Symfony核心中。这有可能要感谢编译器传递。您可以编写自己的代码或使用以下代码:
use Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutowireArrayParameterCompilerPass;
final class AppKernel extends Kernel
{
protected function build(ContainerBuilder $containerBuilder): void
{
$containerBuilder->addCompilerPass(new AutowireArrayParameterCompilerPass);
}
}
就是这样! :)
我在所有项目中都使用了它,它的工作就像一个魅力。
在我写的post about autowired arrays中阅读更多内容。
答案 1 :(得分:0)
一些下雨的星期天下午代码。这个问题基本上是其他几个问题的重复,但是我认为有足够的活动部分值得提供一些具体的解决方案。
首先定义案例,以确保我们都在同一页面上
interface CaseInterface { }
class DieselCaseService implements CaseInterface {}
class CarloanCaseService implements CaseInterface{}
回答问题的最简单方法是将案例服务直接添加到控制器的容器中:
class CaseController extends AbstractController
{
public function action1()
{
$case = $this->get(DieselCaseService::class);
return new Response(get_class($case));
}
// https://symfony.com/doc/current/service_container/service_subscribers_locators.html#including-services
public static function getSubscribedServices()
{
return array_merge(parent::getSubscribedServices(), [
// ...
DieselCaseService::class => DieselCaseService::class,
CarloanCaseService::class => CarloanCaseService::class,
]);
}
}
我对您的问题所做的唯一更改是使用类名作为服务ID,而不是诸如“ case_service.diesel”之类的东西。您当然可以调整代码以使用您的ID,但类名更为标准。请注意,在services.yaml中不需要任何条目即可使它起作用。
上面的代码有两个问题,可能有或没有问题。首先是只有一个控制器可以访问案例服务。这可能就是您所需要的。第二个潜在问题是您需要明确列出所有案例服务。再次可以,但是自动选择实现案例接口的服务可能会很好。
这并不难,但确实需要遵循所有步骤。
开始定义案例定位符:
use Symfony\Component\DependencyInjection\ServiceLocator;
class CaseLocator extends ServiceLocator
{
}
现在,我们需要一些代码来查找所有案例服务并将其注入定位器。有几种方法,但也许最直接的方法是使用Kernel类。
# src/Kernel.php
// Make the kernel a compiler pass by implementing the pass interface
class Kernel extends BaseKernel implements CompilerPassInterface
{
protected function build(ContainerBuilder $container)
{
// Tag all case interface classes for later use
$container->registerForAutoconfiguration(CaseInterface::class)->addTag('case');
}
// and this is the actual compiler pass code
public function process(ContainerBuilder $container)
{
// Add all the cases to the case locator
$caseIds = [];
foreach ($container->findTaggedServiceIds('case') as $id => $tags) {
$caseIds[$id] = new Reference($id);
}
$caseLocator = $container->getDefinition(CaseLocator::class);
$caseLocator->setArguments([$caseIds]);
}
如果执行上述所有步骤,则可以将案例定位器注入碰巧需要它的任何控制器(或其他服务)中:
class CaseController extends AbstractController
{
public function action2(CaseLocator $caseLocator)
{
$case = $caseLocator->get(CarloanCaseService::class);
return new Response(get_class($case));
}
再一次,无需对您的services.yaml进行任何更改即可使所有这些正常工作。
答案 2 :(得分:-1)
我已经创建了包装器服务
<?php
namespace App;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ServiceFactory
{
/** @var ContainerInterface */
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getService($alias)
{
return $this->container->get($alias);
}
/**
* @param $alias
* @return bool
*/
public function hasService($alias)
{
return $this->container->has($alias);
}
}
比我将这项服务注入控制器
public function saveRegisterData(Request $request, AccountService $accountService, ServiceFactory $serviceFactory)
{
.
.
.
if (!$serviceFactory->hasService('case_service.'.$type)) {
throw new \LogicException("no valid case_service found");
}
/**
* @var $caseService \App\Service\Cases\CaseInterface
*/
$caseService = $serviceFactory->getService('case_service.' . $type);
.
.
.
}