Хобрук: Ваш путь к мастерству в программировании

Symfony, как получить контейнер в моем сервисе

У меня есть проект symfony, и внутри этого проекта у меня есть большой собственный сервис, который огромен и сложен, с собственными зависимостями и т. д. И я хочу создать фасад для этой службы с целью использования моей службы в controllers, например:

$myService = $this->container->get('service_from_my_domain');

Мой вопрос - как внутри моего фасада я могу получить доступ к container зависимостям службы. Я знаю только 1 способ - это внедрить зависимость в сервис в конфиге yaml.
Но есть ли другой способ сделать это? Нравиться:

$dependency = Container::getInstance()->get('my_dependency_service');

Я нашел этот ответ, но использование глобальной переменной похоже на прошлое...

PS: я не хочу внедрять зависимость через конфигурацию yaml (не внедрение конструктора и не введение сеттера), потому что мне не нужен IoC (инверсия контроля) здесь.


  • Я нашел много вопросов с таким же названием, но это о другой проблеме, поэтому, пожалуйста, обратите внимание, прежде чем помечать этот вопрос как дубликат. 30.08.2017
  • Я не понимаю, зачем вам вообще нужен контейнер, если вы не хотите использовать IoC и DI? 30.08.2017
  • Container::getInstance() использует глобальный объект. На самом деле, если вы хотите получить глобальный доступ к контейнеру, вам по определению нужно использовать глобал. Назовите это фасадом, как это делает Laravel, если вам от этого станет легче, но это все же глобальный элемент. 30.08.2017
  • @RamyNasr Мне нужен контейнер, потому что я должен работать с другими службами... 30.08.2017
  • Это совсем не рекомендуется. но вы можете внедрить контейнер в эту службу бога, которую хотите использовать, используя '@service_container' в service.yml 30.08.2017
  • @RamyNasr Но я не хочу вводить сервис. Внедрение означает, что вы можете передать instance1 или instance2, поскольку этот экземпляр реализует интерфейс внедрения, но мне нужно использовать определенный класс в моей службе, не заменяя возможность. 30.08.2017
  • @RamyNasr DI - это IoC, но мне нужно, чтобы поведение высокого уровня зависело от поведения низкого уровня. Мне не нужен поддельный IoC, описанный здесь app.pluralsight.com/ 30.08.2017
  • IoC НЕ обязательно означает, что услуги могут быть взаимозаменяемыми. Вы можете легко применить определенный класс или интерфейс при реализации своих служб public function __construct(verySpecificServiceToBeInjected $service) {}. Либо я не понимаю, что вы говорите, либо ваше понимание IoC и DI полностью отличается от моего. 05.09.2017
  • @RamyNasr Когда вы используете verySpecificServiceToBeInjected, вы очень далеки от IoC, потому что здесь нет инверсии ... Ваше поведение на верхнем уровне зависит от поведения verySpecificServiceToBeInjected на низком уровне ... 05.09.2017
  • @VladimirKovpak разве это не то, что ты сказал, что хочешь сделать? Во всяком случае, кажется, много путаницы. Я дам вам понять, что лучше для вас. Спасибо :) 05.09.2017
  • @RamyNasr Да, это именно то, что я пытаюсь найти, но без использования __construct(verySpecificServiceToBeInjected $service) без этого псевдо IoC ... 05.09.2017
  • Пример, который я привел, вообще не был IoC. Это просто способ сделать зависимость видимой заранее. получение службы, от которой вы зависите, в середине кода может означать, что ваша зависимость скрыта глубоко, и другие разработчики могут не заметить ее сразу. 06.09.2017

Ответы:


1

ты можешь сделать вот так

services:
     kernel.listener.acme_listener:
          class: Acme\AcmeBundle\EventListener\AcmeListener
          arguments:
                - @service_container
          tags:
                - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

ваш слушатель

use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class AcmeListener
 {
    /**
     * @var Container
     */
     private $container;

    /**
     * Constructor
     *
     * @param Container $container
     */
   public function __construct(Container $container)
    {
        $this->container = $container;
    }

   public function onKernelController(FilterControllerEvent $event)
    {
        $this->container->...
    }
 }
30.08.2017
  • Я не хочу вводить зависимость через конфигурацию yaml. 30.08.2017
  • Добавить сервис.yml 30.08.2017
  • Мне не нужен ДИ. Мне нужно получить контейнер в моем сервисе без DI. 30.08.2017

  • 2

    Если вы действительно хотите повеселиться и поэкспериментировать с кодом, вы можете сделать что-то вроде этого...

    Создайте класс Facade, который необходимо инициализировать при запуске приложения. Итак, в app.php сразу после строки $kernel = new AppKernel('prod', false); выполните инициализацию Facade:

    $kernel->boot();
    $container = $kernel->getContainer();
    \MyBundle\Facade::init($container);
    

    И вот код для класса Facade:

    <?php
    
    namespace MyBundle;
    
    
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    class Facade
    {
        /**
         * self|null
         */
        private static $instance = null;
    
        /**
         * ContainerInterface
         */
        private static $myContainer;
    
        /**
         * @param ContainerInterface $container
         */
        private function __construct(ContainerInterface $container)
        {
            self::$myContainer = $container;
        }
    
        /**
         * @param string $serviceId
         *
         * @return object
         * @throws \Exception
         */
        public static function create($serviceId)
        {
            if (null === self::$instance) {
                throw new \Exception("Facade is not instantiated");
            }
    
            return self::$myContainer->get($serviceId);
        }
    
        /**
         * @param ContainerInterface $container
         *
         * @return null|Facade
         */
        public static function init(ContainerInterface $container)
        {
            if (null === self::$instance) {
                self::$instance = new self($container);
            }
    
            return self::$instance;
        }
    }
    

    И везде, где вам нужен какой-то сервис, вы создаете его таким образом:

    $service = \MyBundle\Facade::create('my_dependency_service');


    Но, если вы спросите меня, я бы создал службу Facade, в конструктор которой был бы внедрен контейнер. И у вас будет какой-то метод для создания службы (Facade::create($serviceId)), который будет запрашивать у контейнера данный идентификатор службы.

    30.08.2017
  • Это единственный способ заставить контейнер работать с new Controller() .. грустно :( 21.01.2020

  • 3

    Я создал консольное приложение, используя Symfony 5.

    Внедрить сервис в Symfony 5 так же просто, как __construct(ServiceClass $service_name) (подсказка типа), и все это сервис. Но в одном случае я не мог внедрить зависимость в конструктор, потому что служба зависимостей обусловлена ​​параметрами, заданными в командной строке.

    Вот как я внедрил нужный сервис на лету.

    <?php
    
    namespace App\Command;
    
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    use App\Kernel;
    
    class MyCommand extends Command {
        protected static $defaultName = 'app:my-command';
        private $container;
    
        public function __construct(Kernel $kernel) {
            $this->container = $kernel->getContainer();
            //...
            parent::__construct();
        }
    
        protected function configure() {
            // ...
        }
    
        protected function execute(InputInterface $input, OutputInterface $output) {
            //...
            // read the parameters given in the cmd and decide what class is
            // gona be injected.
            // $service_name = "App\\My\\Namespace\\ServiceClassName"
            $service = $this->container->get($service_name);
            $service->doSomething();
    
            return Command::SUCCESS;
        }
    }
    
    01.01.2021
    Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

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

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

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..