Как получить доступ к неинъецированным сервисам напрямую в Symfony 4+? - PullRequest
0 голосов
/ 24 сентября 2019

Я пытаюсь обновить Symfony 2.8 до Symfony 4, и у меня возникают серьезные проблемы с внедрением служб.

Я ищу новый способ использования служб внутри контроллеров:

use App\Service\AuxiliarService;
class DefaultController extends AbstractController
{
    public function index(AuxiliarService $service)
    {
        $var = $service->MyFunction();
        ....

Этот способ работает нормально, но мне не нравится явный способ ссылаться на MyService в качестве параметра функции.Таким образом, мне даже не нужно регистрировать Сервис в services.yaml

. Любой способ использовать Сервисы, как в Symfony 2.8:

class DefaultController extends Controller
    {
        public function index()
        {
            $var = $this->get('AuxiliarService')->MyFunction(); /*Doesn't need to be explicit indicate before*/
            ....

С services.yaml

services:
    auxiliar_service:
        class:        AppBundle\Services\AuxiliarService
        arguments: 
            entityManager: "@doctrine.orm.entity_manager"
            container: "@service_container" #I need to call services inside the service

Таким образом, мне не нужно указывать Сервис в качестве параметра в функции Контроллера.В некоторых случаях внутри службы мне нужно вызывать более 10 служб в зависимости от данных, поэтому указывать их как параметр в функции раздражает.

Еще одно сомнение в Symfony 4 - как вызыватьСервис внутри другого Сервиса без указания аргумента или параметра.Это связано с тем, что я ввел контейнер службы для возможности вызова службы внутри службы:

$this->container->get('anotherService')

В Symfony 4 я думаю, что использование службы в коде стоит дороже (в коде), поскольку необходимо явно указатьукажите их, когда вы собираетесь их использовать.

1 Ответ

0 голосов
/ 24 сентября 2019

tldr; Вы можете достичь этого, используя Абоненты и локаторы услуг .

В вашем контроллере:

use App\Service\AuxiliarService;
class DefaultController extends AbstractController
{
    public function index(AuxiliarService $service)
    {
        $var = $service->MyFunction();
    }

    public static function getSubscribedServices()
    {
        return array_merge(parent::getSubscribedServices(), [
            // services you want to access through $this->get()
            'auxiliar_service' => AuxiliarService:class,
        ]);
    }
// rest of the implementation
}

Если ваш сервиснеобходимо реализовать аналогичный шаблон, вам нужно реализовать ServiceSubscriberInterface (AbstractController, который вы расширяете для своего контроллера, уже делает это для вас).

class AuxiliaryService implements ServiceSubscriberInterface
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    protected function has(string $id): bool
    {
        return $this->container->has($id);
    }

    protected function get(string $id)
    {
        return $this->container->get($id);
    }

    public static function getSubscribedServices()
    {
        return [
            // array_merge is not necessary here, because we are not extending another class. 
            'logger' => LoggerInterface::class,
            'service2' => AnotherService::class,
            'service3' => AndMore::class
        ];
    }
}

* 1016Как говорится, вы, вероятно, не делаете все правильно, если хотите продолжать в том же духе

До Symfony 4+ вы могли сделать $this->get('service'), потому что все эти контроллеры имели доступ к контейнеру. Передача контейнера зависимостей для этого - это анти-шаблон, и делать это не следует .

Если вы не объявляете свои зависимости, ваши зависимости скрыты .Пользователи класса не знают, что он использует, и сломать систему проще, изменив поведение одной из скрытых зависимостей.

Более того, Symfony обеспечивает автоматическое подключение и скомпилированный контейнер;Внедрение зависимостей проще и быстрее в реализации.

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

Попробуйте приспособиться к изменениям, это подойдетваше приложение и вы хорошо себя чувствуете в долгосрочной перспективе (даже если сейчас приносит небольшое количество боли).

...