2013-07-29 37 views
0

如何访问捆绑器构造器中的服务?我试图创建一个系统,其中一个主题包可以自动本身的主题服务注册,见下文(比较简单的解决越好)小例子:Symfony:无法访问捆绑构造器中的服务

<?php 

namespace Organization\Theme\BasicBundle; 

use Symfony\Component\HttpKernel\Bundle\Bundle; 

class ThemeBasicBundle extends Bundle 
{ 
    public function __construct() { 
     $themes = $this->get('organization.themes'); 
     $themes->register(new Organization\Theme\BasicBundle\Entity\Theme(__DIR__)); 
    } 
} 

然而,这 - $>获取不起作用,这可能是因为不能保证所有捆绑包都已经被注册了,是否有任何捆绑注册“钩子”可以用来代替?是否有任何特殊的方法名称可以添加到捆绑类中,并在所有捆绑包实例化后执行?

服务类看起来是这样的:

<?php 

namespace Organization\Theme\BasicBundle; 

use Organization\Theme\BasicBundle\Entity\Theme; 

class ThemeService 
{ 
    private $themes = array(); 

    public function register(Theme $theme) { 
     $name = $theme->getName(); 

     if (in_array($name, array_keys($this->themes))) { 
      throw new Exception('Unable to register theme, another theme with the same name ('.$name.') is already registered.'); 
     } 

     $this->themes[$name] = $theme; 
    } 

    public function findAll() { 
     return $this->themes; 
    } 

    public function findByName(string $name) { 
     $result = null; 

     foreach($this->themes as $theme) { 
      if ($theme->getName() === $name) { 
       $result = $theme; 
      } 
     } 

     return $result; 
    } 
} 
+0

捆绑::启动被执行。你的问题是哪种答案。但是,在构建阶段执行此操作是正确的方法。 – Cerad

回答

2

尝试,它可以工作:):

<?php 

namespace Organization\Theme\BasicBundle; 

use Symfony\Component\HttpKernel\Bundle\Bundle; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 

class ThemeBasicBundle extends Bundle 
{ 
    public function build(ContainerBuilder $container) 
    { 
     parent::build($container); 

     $themes = $container->get('organization.themes'); 
     $themes->register(new Organization\Theme\BasicBundle\Entity\Template(__DIR__)); 
    } 
} 
+0

当我尝试这个时,我收到一个错误,指出无法找到服务“organization.themes”。 – Tirithen

+0

Rpg600的解决方案很好。 –

3

这是正常的,你不能访问到服务容器,因为服务不尚未编译。 要将标记服务注入到该包中,您需要创建一个新的编译器传递。

要创建编译器通道,需要实现CompilerPassInterface。

将该类放入该包的DependencyInjection/Compiler文件夹中。

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 

class CustomCompilerPass implements CompilerPassInterface 
{ 
    public function process(ContainerBuilder $container) 
    { 
     if ($container->has('organization.themes')) { 
      $container->getDefinition('organization.themes')->addMethodCall('register', array(new Organization\Theme\BasicBundle\Entity\Theme(__DIR__))); 
     } 
    } 
} 

然后覆盖您的包定义类的构建方法。

class ThemeBasicBundle extends Bundle 
{ 
    public function build(ContainerBuilder $container) 
    { 
     $container->addCompilerPass(new CustomCompilerPass()); 
    } 
} 

一些链接:集装箱建成后

http://symfony.com/doc/current/components/dependency_injection/compilation.html http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html http://symfony.com/doc/current/components/dependency_injection/tags.html

+0

这可以得到服务,但是当我尝试从控制器获取CompilerPass类中设置的值时,我遇到了服务属性被重置的问题,看起来当我得到另一个类的实例时来自控制器的服务。我想要做的是在实例化bundle时注册Theme实例,然后从控制器访问Theme实例。为什么服务类属性重置? – Tirithen

+0

@Tirithen看到我的编辑,你需要获得服务定义并使用addMethodCall方法。 – rpg600