2013-07-29 61 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