2014-11-15 3 views
0

Я объясню пример: Существует 2 пучка: Foo\SecurityBundle и Foo\MenuBundle.
Foo\MenuBundle имеет класс меню, который выглядит следующим образом:Как определить дополнительные зависимости для отдельных пакетов?

namespace Foo\MenuBundle; 

use Foo\SecurityBundle\MenuSecurer; //note this 
class Menu{ 
    protected $securer; 
    public function __construct(MenuSecurer $securer = null){ 
     $this->securer = $securer; 
    } 

    public function buildMenu(){ 
     //build the $menu ... 
     //... 
     if($this->securer != null) 
      $securer->secure($menu); 
    } 

} 

расслоение безопасности будет автоматически вводить $ menuSecurer, если он установлен, однако проблема Когда пакет безопасности не установлен, то это классы также не определены, поэтому я не могу use Foo\SecurityBundle... в MenuBundle, хотя я действительно не использую его. Каков правильный путь?

+0

Уточнение: вопрос в основном касается оператора использования и используемого, но потенциально не объявленного интерфейса. – user2268997

+0

Не может быть хорошего решения. Вы можете либо убедиться, что ваш пакет имеет зависимость от того, который содержит интерфейс, либо вы можете полностью разделить интерфейсы на отдельный комплект и потребовать его. Или, может быть, я неправильно понимаю реальную проблему. – ChadSikorra

+0

@ChadSikorra: да, это действительно моя проблема. Что я сейчас делаю: создайте две отдельные службы, одну без дополнительной зависимости и одну без нее. Затем я меняю определение службы, используя пересылку компилятора в пакете Dependee Bundle. – user2268997

ответ

1

Существует раздел в фреймворка документации, связанную с этой этой ситуацией: http://symfony.com/doc/current/book/service_container.html#optional-dependencies-setter-injection

Если у вас есть дополнительные зависимости для класса, а затем «сеттер инъекция» может быть лучшим вариантом.

Согласно этому вашему классу может выглядеть следующим образом:

namespace Foo\MenuBundle; 

class Menu{ 
    protected $securer; 

    public function setSecurer($securer) { 
     $this->securer = $securer; 
    } 

    public function buildMenu(){ 
     //build the $menu ... 
     //... 
     if($this->securer != null) 
      $securer->secure($menu); 
    } 

} 

# config.yml 
menu_service: 
    class: Foo\MenuBundle\Menu 
    calls: 
     - [setMailer, ["@securer"]] 

Что-то вроде этого ... К сожалению, вы все еще не можете быть использовать заявление без интерфейса вы знаете, существуют.

1

Существует довольно много способов сделать это, но я думаю, что хорошим подходом было бы добавить параметр конфигурации для класса/службы, который должен быть введен в первый аргумент конструктора.

Например, в классе Foo\MenuBundle\Menu (при условии, что это уже определено как услуга) вы можете добавить дополнительный элемент в конфигурацию пакета для определения службы по умолчанию для $securer, а затем, при необходимости, переопределить ее в конфигурации ,

В классе конфигурации (DependecyInjection\Configuration.php):

public function getConfigTreeBuilder() 
{ 
    $treeBuilder = new TreeBuilder(); 
    $rootNode = $treeBuilder->root('foo_menu'); 
    $rootNode 
     ->children() 
      ->arrayNode('service') 
       ->addDefaultsIfNotSet() 
       ->children() 
        ->scalarNode('menu_securer')->defaultValue('foo_security.menu_securer')->end() 
       >end() 
      ->end() 
     ->end(); 

    return $treeBuilder; 
} 

В классе расширения (DependecyInjection\FooMenuExtension.php):

use Symfony\Component\DependencyInjection\Reference; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\Config\FileLocator; 
use Symfony\Component\HttpKernel\DependencyInjection\Extension; 
use Symfony\Component\DependencyInjection\Loader; 

// ... 

public function load(array $configs, ContainerBuilder $container) 
{ 
    $configuration = new Configuration(); 
    $config = $this->processConfiguration($configuration, $configs); 

    $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 

    // This is what sets 'foo_menu.menu_securer' to the service you want 
    foreach ($config['service'] as $key => $service) { 
     $container->setAlias($this->getAlias() . '.' . $key, $service); 
    } 

    $loader->load('services.xml'); 

    $container->getDefinition('foo_menu.menu.menu') 
     ->replaceArgument(0, new Reference('foo_menu.menu_securer')); 
} 

И ваше определение услуг будет просто выглядеть примерно так ...

<service id="foo_menu.menu.menu" class="%foo_menu.menu.menu.class%"> 
    <argument /> <!-- foo_menu.menu_securer --> 
</service> 

Теперь в вашем config.yml вы c просто переключитесь из услугу, которую вы хотите использовать, определив его в под ...

foo_menu: 
    service: 
     menu_securer: 'some_other.service' 

Edit: Что касается типа намекая, как уже упоминалось, Маркус, вероятно, было бы хорошей идеей, чтобы реализовать интерфейс, что $securer должен реализовывать.

Смежные вопросы