在Symfony 3.x中,我们使用API层将Doctrine实体作为JSON响应(使用JMSSerializer和FOSRestBundle)提供 - 将它想象成某种Symfony序列化组件的自定义ObjectNormalizers。
其中一些API类需要容器识别。目前我们使用全局abstract class ApiWrapper implements ContainerAwareInterface
{
use ContainerAwareTrait;
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container
}
}
,这是出于很多原因的不良做法。
这是我到目前为止所尝试的(非常简化):
抽象类
protected class BaseApi extends ApiWrapper
{
//...some stuff
}
BaseClass的
protected class MyApi1 extends BaseApi
{
protected $entity;
public function __construct(SomeEntityClass $entity) {
$this->entity = $entity;
}
}
RealApiClass1
protected class MyApi2 extends BaseApi
{
protected $entity;
public function __construct(AnotherEntityClass $entity) {
$this->entity = $entity;
}
}
RealApiClass2
services:
bundle.api_wrapper:
class: ApiWrapper
abstract: true
shared: false // to make sure to get a new instance everytime it's called
calls:
- [ setContainer, [ @service_container ] ]
bundle.base_api:
class: BaseApi
parent: api_wrapper
bundle.my_api:
class: MyApi
parent: base_api
services.yml
$myApi = new MyApi1($myEntity);
控制器
$myApi
我可以看到null
有一个属性容器,但它提供了@media (max-width:600px) {
.red,
.blue { width: 100%; }
}
。
在这种情况下,有没有办法共享容器?
答案 0 :(得分:3)
无论您如何配置服务,将实体映射到其api类都会有点痛苦。这样做的一种方法是使用工厂来实际创建api类。这样可以更容易配置。
此代码尚未经过测试,因此可能会出现一些语法错误。
class ApiFactory
{
$container;
public function __construct($container) {
$this->container = $container;
}
public function create($entity) {
$api = null;
switch(get_class($entity)) { // Map entity to api class
case MyEntity1::class :
$api = new MyApi1($entity);
break;
case MyEntity2::class :
$api = new MyApi2($entity);
break;
default:
throw new Exception('Oops');
}
// Steal a trick from the controller resolver
if ($api instanceof ContainerAwareInterface) {
$api->setContainer($this->container);
}
return $api;
}
}
请注意,您的抽象ApiWrapper类并不是真正需要的。如果特定的api需要容器,那么只需让它实现容器感知接口并添加特征。
// Usage in a controller
$apiFactory = $this->get('my_api_factory');
$api = $apiFactory->create($myEntity);
// services.yml
services:
my_api_factory:
class: ApiFactory
arguments: ['@service_container']
您使用了许多变体。我认为最好为每个api定义一个服务,并注入它需要的确切依赖项而不是容器。您可以使用api的类名称命名每个api服务。然后,您的api工厂将使用实体类名称从容器中提取所需的完全配置的api以生成密钥。
答案 1 :(得分:1)
在控制器中,您必须通过容器检索API,例如:
控制器
$myApi = $this->get('bundle.my_api');