DI и библиотеки

Обсуждаем, как правильно строить приложения
Ответить
wolfandman
Сообщения: 40
Зарегистрирован: 2012.06.04, 19:52

DI и библиотеки

Сообщение wolfandman »

Здравствуйте!
Осваиваю технику инверсии контроля. Не могу разобраться с парой вещей.

PaymentsComponent кладёт в очередь таск RequestJob.
RequestJob делает curl запросы через библиотеку Curl. Один инстанс библиотеки Curl создаётся для одного запроса (он имеет состояния).

Объясните, пожалуйста, как получать инстанс класса Curl в объекте RequestJob.
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI и библиотеки

Сообщение ElisDN »

wolfandman писал(а): 2020.09.24, 16:40 Объясните, пожалуйста, как получать инстанс класса Curl в объекте RequestJob.
Никак. Вместо этого разделяйте код на саму структуру Job с данными для помещения в очередь:

Код: Выделить всё

class RequestJob
{
    public string $url;

    public function __construct(string $url)
    {
        $this->url = $url;
    }
}
и на отдельный сервис-обработчик этой Job-ы, в котором уже доставайте клиент и делайте запрос:

Код: Выделить всё

class RequestJobHandler
{
    private HttpClient $client;

    public function __construct(HttpClient $client)
    {
        $this->client = $client;
    }

    public function __invoke(RequestJob $job): void
    {
        $response = $this->client->get($job->url);
        // ...
    }
}
И его уже доставайте из контейнера. Например, в таком приёмнике ообщений:

Код: Выделить всё

class Consumer
{
    private ContainerInterface $container;

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

    public function consume(object $job): void
    {
        $handler = $this->resolveHandler($job);
        $handler($job);
    }

    private function resolveHandler(object $job): callable
    {
        $name = get_class($job) . 'Handler';
        return $this->container->get($name);
    }
}
Тогда из самой RequestJob никаких сервисов дёргать не придётся.
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI и библиотеки

Сообщение ElisDN »

Если рассматривать yii2-queue, то можно для этого все свои Job-ы с данными:

Код: Выделить всё

class RequestJob extends Job 
{
    public string $url;

    public function __construct(string $url)
    {
        $this->url = $url;
    }
}
просто наследовать от класса:

Код: Выделить всё

abstract class Job implements \yii\queue\Job
{
    public function execute($queue): void
    {
        $handler = \Yii::createObject(static::class . 'Handler');
        $handler($this);
    }
}
который в execute вместо самоисполнения будет искать и запускать такой Handler, передавая ему себя.
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI и библиотеки

Сообщение ElisDN »

wolfandman писал(а): 2020.09.24, 16:40 Один инстанс библиотеки Curl создаётся для одного запроса (он имеет состояния).
Для контейнера желательно делать библиотеки без изменяемого при работе состояния.

Например, свой Curl с состоянием можно обернуть в компонент HttpClient без состояния:

Код: Выделить всё

class RequestJobHandler
{
    private HttpClient $client;

    public function __construct(HttpClient $client) {
        $this->client = $client;
    }

    public function __invoke(RequestJob $job): void {
        $response = $this->client->request($job->url);
    }
}
И пусть он внутри себя уже тольуо в методе request будет создавать свой инстанс Curl-а.

Но если всё-таки хочется использовать Curl с состоянием, то тогда для контейнера можно сделать фабрику без состояния и каждый инстанс делать уже через неё:

Код: Выделить всё

class RequestJobHandler
{
    private CurlFactory $factory;

    public function __construct(CurlFactory $factory) {
        $this->factory = $factory;
    }

    public function __invoke(RequestJob $job): void {
        $curl = $this->factory->create(...);
        $curl->get($job->url);
    }
}
wolfandman
Сообщения: 40
Зарегистрирован: 2012.06.04, 19:52

Re: DI и библиотеки

Сообщение wolfandman »

Дмитрий, огромное спасибо за ваше время и разъяснения с такими богатыми замечательными примерами!
Идея с ручным использованием контейнера приходила, но сначала переживал, что так делать наверно нехорошо.
Также про фабрику - супер!
Вопрос с решён с вашей помощью.
Спасибо!!
Ответить