Symfony: невозможно получить доступ к сервису внутри конструктора пакета

Как я могу получить доступ к сервису внутри конструктора Bundle? Я пытаюсь создать систему, в которой набор тем может автоматически регистрироваться в службе тем, см. небольшой пример ниже (чем проще решение, тем лучше):

<?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__));
    }
}

Однако $this->get не работает, это может быть связано с тем, что нет гарантии, что все пакеты уже зарегистрированы. Существуют ли какие-либо «крючки» для регистрации после пакета, которые я могу использовать вместо этого? Существуют ли какие-либо специальные имена методов, которые я могу добавить в класс пакета, который запускается после создания экземпляра всех пакетов?

Класс обслуживания выглядит следующим образом:

<?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;
    }
}

person tirithen    schedule 29.07.2013    source источник
comment
Bundle::boot запускается после сборки контейнера. Какой вид отвечает на ваш вопрос. Тем не менее, делать это на этапе сборки — правильный подход.   -  person Cerad    schedule 29.07.2013


Ответы (2)


Это нормально, что вы не можете получить доступ к контейнеру службы, потому что службы еще не скомпилированы. Чтобы внедрить помеченные сервисы в этот пакет, вам нужно создать новый проход компилятора.

Чтобы создать проход компилятора, необходимо реализовать 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

person rpg600    schedule 29.07.2013
comment
Это работает для получения службы, но у меня возникают проблемы со сбросом свойств службы, когда я пытаюсь получить значения, которые я установил в классе CompilerPass из контроллера, кажется, что я получаю другой экземпляр класса при получении обслуживание от контроллера. Что я хочу сделать, так это зарегистрировать экземпляры темы при создании экземпляра пакета, а затем получить доступ к экземплярам темы из контроллера. Почему свойства класса обслуживания сбрасываются? - person tirithen; 29.07.2013
comment
@Tirithen Смотрите мое редактирование, вам нужно получить определение службы и использовать метод addMethodCall. - person rpg600; 29.07.2013

Попробуйте, чтобы это сработало :) :

<?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__));
    }
}
person Léo Benoist    schedule 29.07.2013
comment
Когда я попробовал это, я получил сообщение об ошибке, в котором говорилось, что сервисная организация.темы не может быть найдена. - person tirithen; 29.07.2013