【发布时间】:2019-11-28 09:29:32
【问题描述】:
使用激活自动装配的 Symfony 4.4,我想使用设计模式 FactoryMethod 实例化一个类。
实例化的类是一个将自动装配的参数传递给构造函数的服务。
如果在工厂方法内部实例化每种类型的类的构造函数都相同,则效果很好。
但是,每个要实例化的服务都必须自动装配一些特定的服务才能工作。
我发现我们可以使用“setter 依赖注入”。描述它的文章:
- https://symfonycasts.com/screencast/symfony-fundamentals/logger-trait
- https://symfony.com/doc/4.4/service_container/injection_types.html#setter-injection
我试图实现setter依赖注入,但里面的代码从未执行过。
考虑到文章,我们应该在调用 __construct 方法后立即使用 PHPDoc“@required”输入设置器(据我了解)。
它不适用于我的代码(见下文)。
我的实现是否正确?
有没有更好的方法?
我的代码如下:
// Controller
/**
*@Route("/my_action/{param}")
*/
public function my_action (ThingManagerFactory $thingManagerFactory, $param)
{
$thingManager = $thingManagerFactory->get($param);
$thingManager->doSomething();
}
// ThingManagerFactory
class ThingManagerFactory
{
private $firstManager;
private $secondManager;
private $thirdManager;
public function __construct(FirstManager $firstManager, SecondManager $secondManager, ThirdManager $thirdManager)
{
$this->firstManager = $firstManager;
$this->secondManager = $secondManager;
$this->thirdManager = $thirdManager;
}
public function get($param): ThingManagerInterface
{
if($param == 1) {
return new Thing1Manager(
$this->firstManager,
$this->secondManager,
$this->thirdManager,
);
} elseif($param == 2) {
return new Thing2Manager(
$this->firstManager,
$this->secondManager,
$this->thirdManager,
);
}
throw new \InvalidArgumentException("...");
}
}
// ThingManagerInterface
interface ThingManagerInterface
{
public function __construct(
$this->firstManager,
$this->secondManager,
$this->thirdManager,
);
public function doSomething();
}
// Thing1Manager
class Thing1Manager implements ThingManagerInterface
{
(...)
private $spec1Manager;
public function __construct(
$this->firstManager,
$this->secondManager,
$this->thirdManager,
)
{
(...)
}
/**
* @required
*/
public function setSpecificManager(Spec1Manager $spec1Manager)
{
// this code is never called
$this->spec1Manager = $spec1Manager;
}
public function doSomething()
{
// we pass here before going into setSpecificManager
(...)
}
}
// Thing2Manager class
// is similar to Thing1Manager with multiple other specific managers.
感谢您的帮助。
【问题讨论】:
-
'@required' 参数与 Symfony 容器一起工作。新运营商对此一无所知。你的导师可能在谈论service locators。但是您确实需要向他/她/其他人询问更多详细信息。
-
事实上,我正在努力做到这里所说的:autowiring other methods.
-
是的,但 autowire 只能在 Symfony 服务容器中工作。 return new Thing1Manager() 不会自动调用 Thing1Manager::setSpecificManager。使用服务定位器(基本上是 Symfony 容器),您将返回 $serviceLocator->get($param) ,它会负责注入所有依赖项。
-
我不明白必须在哪里定义服务定位器。我是否必须在每个 ThingXManager 中使用每个人需要的特定服务来定义它?或者在控制器中忘记编写 FactoryMethod 类?我应该把“return $serviceLocator->get($param)”放在哪里?感谢您的帮助。
-
当尝试在 Thing1Manager 中添加服务定位器时: public static function getSubscribedServices() { return [ 'App\Manager\Spec1Manager' => Spec1Manager::class ];我收到以下错误:编译容器时,“App\Manager\Spec1Manager”服务或别名已被删除或内联。您应该将其公开,或者直接停止使用容器并改用依赖注入。
标签: php symfony design-patterns