2011-05-25 56 views
50

我正在建立一个网站,很大程度上依赖于第三方API,所以我认为将API封装器打包为服务是有意义的,但是我已经开始发现有权访问的实例它在控制器之外,比如在实体存储库中。 与此相关的是能够访问控制器之外的配置值(例如在实体存储库中)将是有用的。如何使用Symfony2访问控制器之外的服务?

任何人都可以告诉我,如果这是可能的,如果不是有建议的方法做这种事情?

感谢您的任何帮助

回答

73

Symfony分布严重依赖于依赖注入。这意味着通常,依赖关系通过构造函数,设置器或通过其他方式(如对属性的反射)直接注入到对象中。您的API包装服务是您的应用程序的其他对象的依赖项。这就是说,将这个服务注入到一个实体库的构造函数中是相当困难的,因为它已经需要一些其他参数了,​​我认为它不可能被注入,因为我们要求一个存储库的方式实体。

你可以做的是创建另一个服务,负责完成你将要在实体存储库中完成的工作。这样,您将能够注入将用于检索实体存储库的实体管理器,自定义服务以及保存配置值的其他服务(还有其他方式可以共享配置值)。

在我的使用案例中,我使用了包装Facebook API调用的Facebook帮助器服务。这个服务然后被注入我需要的地方。我的实体仓库只负责进行数据库调用,因此它只接收它需要的参数,而不是整个依赖项。因此,它不会收到助手,而只会收到请求所需的参数,例如Facebook用户标识。在我看来,这是做这件事的方式,因为我认为实体存储库不应该对这样的辅助对象有依赖关系。

这里使用YAML作为配置一个小例子:

# app/config/config.yml 
services: 
    yourapp.configuration_container: 
    class: Application/AcmeBundle/Common/ConfigurationContainer 
    # You could inject configurations here  

    yourapp.api_wrapper: 
    class: Application/AcmeBundle/Service/ApiWrapperService 
    # Inject other arguments if needed and update constructor in consequence  

    yourapp.data_access: 
    class: Application/AcmeBundle/Data/Access/DatabaseAccessService 
    arguments: 
     entityManager: "@doctrine.orm.entity_manager" 
     apiWrapperService: "@yourapp.api_wrapper" 
     configuration: "@yourapp.configuration_container" 

# Application/AcmeBundle/Common/ConfigurationContainer.php 
public ConfigurationContainer 
{ 
    public function __construct() 
    { 
     // Initialize your configuration values or inject them in the constructor 
    } 
}   

# Application/AcmeBundle/Service/ApiWrapperService.php 
public ApiWrapperService 
{ 
    public function __construct() 
    { 
     // Do some stuff 
    } 
} 

# Application/AcmeBundle/Data/Access/DatabaseAccessService.php 
public DatabaseAccessService 
{ 
    public function __construct(EntityManager $entityManager, ApiWrapperService $apiWrapperService, ConfigurationContainer $configuration) 
    { 
     ... 
    } 
} 

的符号(@)在config.yml文件指的Symfony应该注入另一服务中,具有后at符号所定义的ID,而不是一个简单的字符串。正如我之前所说的,对于配置值来说,还有其他方法可以实现像使用参数或bundle扩展一样的目标。使用包扩展,您可以将配置值直接定义到config.yml中,并且您的包将会读取它们。

总之,这应该给你注射服务的总体思路。这里有一个关于这个主题的文档的小列表。许多链接使用XML服务定义而不是YAML定义,但您应该能够很容易地理解它们。

  1. Symfony Official DI
  2. Fabien Potencier's articles on DI
  3. Richard Miller's articles on DI(请在自己的博客为其他DI篇)

注意到,我给的配置工作的Symfony2的Beta1的。我没有更新到Beta2,所以可能有些东西因为它们在Beta2版本中不起作用。

我希望这可以帮助您为问题定义最终解决方案。如果您想要澄清或其他任何问题,请不要犹豫提出其他问题。

问候, 马特

+0

这是巨大的帮助,我已经将我的API服务注入到了我的数据库服务中,这非常好,我仍然不清楚如何最好地继续配置。如果我解释我想要做什么,可能是最好的。我正在构建一个可跨多个域使用的站点,每个站点都将作为具有自己的yaml配置文件的环境存在。在配置文件中将是一个站点ID,我想要的是能够调用getUsers()例如,并从配置中获取站点ID,并自动向查询中添加“where site_id = x”。这是可能的,或者我应该通过ID作为参数? – pogo 2011-05-25 17:57:32

+1

刚刚意识到您链接的Symfony文章解释了如何做到这一点,再次感谢您的帮助。这一直强调了我几天,所以有一个解决方案是很好的。 – pogo 2011-05-25 18:02:19

+0

很高兴它有帮助,你现在有一个解决你的问题:)的确,我链接的文章更加明确如何使用参数和类似的东西。祝你工作顺利。 – Matt 2011-05-25 20:08:49

0

我想包这种行为的Symfony的服务(如经理)。 我不会在实体存储库中注入任何参数或逻辑,因为它们应该主要用于使用对象管理器查询来获取数据。 我会把逻辑放在服务中,如果服务需要数据库访问,它会调用实体存储库来获取数据。

相关问题