Динамически получить экземпляр службы в контроллере по некоторому значению - PullRequest
0 голосов
/ 28 мая 2020

Я хочу получить экземпляр службы в контроллере (symfony 4) только по значению, которое может выглядеть следующим образом: $provider = 'youtube'

Это моя настройка:

Class videoProvider {
//Here I have all common methods for all services
}

Class YoutubeService extends videoProvider {}

Class OtherVideoService extends videoProvider {}

Теперь вопрос в том, как это сделать. Если $provider = 'youtube' Тогда воспользуйтесь сервисом YouTube new YoutubeService () и go на. Но что делать, если службы не существует? Что тогда?

Это вообще возможно?

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Можно сделать что-то вроде этого

  • Создайте папку с именем Provider
  • Создайте интерфейс, например, VideoProviderInterface, и поместите в папку
  • В ваш интерфейс добавьте метод getProviderName(): string
  • Создайте своих провайдеров, поместите их в папку и реализуйте интерфейс
  • В свой services.yaml добавьте параметр _instanceof: и добавьте в свой интерфейс какой-нибудь тег
  • Исключите папки вашего провайдера из опции App\: в services.yaml
  • Create class, ProviderManager и вставьте ваш локатор сервиса

Более подробную информацию вы можете найти здесь

services.yaml

_instanceof:
    App\Provider\VideoProviderInterface:
        tags: ['app.provider']

App\Provider\:
    resource: '../../src/Provider/*'

App\Provider\ProviderManager:
    arguments:
        - !tagged_locator { tag: 'app.provider', default_index_method: 'getProviderName' }

App\:
    resource: '../src/*'
    exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php,Provider}'

VideoProviderInterface

<?php

namespace App\Provider;

interface VideoProviderInterface
{
    public function getProviderName(): string
}

ProviderManager

<?php

namespace App\Provider;

use Symfony\Component\DependencyInjection\ServiceLocator;

class ProviderManager
{
    /**
     * @var ServiceLocator
     */
    private $serviceLocator;

    public function __construct(ServiceLocator $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function findByName(string $name): ?VideoProviderInterface
    {
        return $this->serviceLocator->has($name) ? $this->serviceLocator->get($name) : null;
    }    
}
1 голос
/ 28 мая 2020

$this->container->has('my-service-name') и $this->container->get('my-service-name') в контроллере, вероятно, то, что вы ищете. My-service-name - это имя, которое вы даете службе в конфигурации службы и убедитесь, что ваша служба - publi c.

Пример конфигурации ( см. Do c здесь )

# this is the service's name
site_video_provider.youtube:
    public: true
    class: App\Provider\YoutubeService
    [...]

Затем в контроллере или любых классах, поддерживающих контейнер: ( см. Do c здесь )

$service_name = 'site_video_provider.'.$provider;
if($this->container->has($service_name)){
   $service = $this->container->get($service_name);
}
...