Может войдёшь?
Черновики Написать статью Профиль

Командная шина

перевод документация 5.х

  1. 1. Введение
  2. 2. Создание команд
  3. 3. Выполнение команд
    1. 3.1. Передача параметров в запросах
  4. 4. Очередь команд
  5. 5. Конвейер команд
Этот перевод актуален для англоязычной документации на (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Данная статья документации актуальна только для версии 5.0 и была удалена в версии 5.1.

Введение

Командная шина Laravel предоставляет удобный способ инкапсуляции задач вашего приложения в простые и понятные «команды». Чтобы понять назначение команд, давайте представим, что мы создаём приложение, которое позволяет пользователям покупать подкасты.

Когда пользователь покупает подкаст, должно произойти несколько событий. Например, мы должны снять деньги с карты пользователя, добавить запись о покупке в нашу базу данных и послать электронное письмо с подтверждением покупки. Возможно, мы также должны выполнить некоторые проверки, например, разрешено ли пользователю вообще покупать подкасты.

Мы могли бы поместить всю эту логику в метод контроллера. Однако у этого подхода есть несколько недостатков. Во-первых, наш контроллер, вероятно, обрабатывает и несколько других входящих HTTP-действий, поэтому включение сложной логики в каждый метод контроллера приведёт к его быстрому разрастанию, и его будет сложно читать. Во-вторых, будет трудно снова использовать логику покупки подкаста за пределами контекста контроллера. В-третьих, будет сложнее проводить юнит-тесты команд, поскольку нам придётся также генерировать заглушки для HTTP-запросов и выполнять полноценный запрос к приложению, чтобы протестировать логику покупки подкаста.

Вместо размещения этой логики в контроллере, мы можем принять решение инкапсулировать её в объект «команды», такой как команда PHPPurchasePodcast.

Создание команд

Командная строка Artisan может генерировать новые классы команды, используя команду shmake:command:

shphp artisan make:command PurchasePodcast

Только что сгенерированный класс будет помещён в каталог app/Commands. По умолчанию команда содержит два метода: конструктор и метод PHPhandle. Конструктор позволяет вам передавать любые соответствующие объекты команде, в то время как метод PHPhandle выполняет команду. Например:

PHP
class PurchasePodcast extends Command implements SelfHandling {

  protected 
$user$podcast;

  
/**
   * Создание нового экземпляра команды.
   *
   * @return void
   */
  
public function __construct(User $userPodcast $podcast)
  {
    
$this->user $user;
    
$this->podcast $podcast;
  }

  
/**
   * Выполнение команды.
   *
   * @return void
   */
  
public function handle()
  {
    
// Логика покупки подкаста...

    
event(new PodcastWasPurchased($this->user$this->podcast));
  }

}

Метод PHPhandle может использовать указание типов зависимостей, и они будут автоматически внедрены сервис-контейнером.

PHP
/**
 * Выполнение команды.
 *
 * @return void
 */
public function handle(BillingGateway $billing)
{
  
// Логика покупки подкаста...
}

Выполнение команд

Как выполнить только что созданную команду? Можно непосредственно вызвать метод PHPhandle. Однако, выполнение команд через «командную шину» Laravel имеет ряд преимуществ, которые мы обсудим далее.

Если вы посмотрите на основной контроллер своего приложения, то вы заметите типаж PHPDispatchesCommands. Он позволяет вызывать метод PHPdispatch из любого контроллера.

PHP
public function purchasePodcast($podcastId)
{
  
$this->dispatch(
    new 
PurchasePodcast(Auth::user(), Podcast::findOrFail($podcastId))
  );
}

Командная шина займётся выполнением команды и вызовом IoC-контейнера для внедрения любых необходимых зависимостей в метод PHPhandle.

Вы можете добавить типаж Illuminate\Foundation\Bus\DispatchesCommands в любой класс. Если вы хотите получить экземпляр командной шины через конструктор какого-либо из ваших классов, вы можете указать тип интерфейса PHPIlluminate\Contracts\Bus\Dispatcher. Наконец, вы можете просто использовать фасад PHPBus, чтобы быстро выполнить команду:

PHP
Bus::dispatch(
  new 
PurchasePodcast(Auth::user(), Podcast::findOrFail($podcastId))
);

Передача параметров в запросах

Передача переменных HTTP-запроса в команды очень распространена. Поэтому, вместо того чтобы делать это вручную для каждого запроса, Laravel предоставляет некоторые вспомогательные методы. Давайте взглянем на метод PHPdispatchFrom, доступный в типаже PHPDispatchesCommands:

PHP
$this->dispatchFrom('Command\Class\Name'$request);

Этот метод проверяет конструктор класса команды, который он получил первым аргументом, и затем извлекает переменные из HTTP-запроса (или любого другого объекта типа PHPArrayAccess), чтобы заполнить необходимые параметры конструктора команды. Так, если наш класс команды примет аргумент PHPfirstName в своём конструкторе, то командная шина попытается получить параметр PHPfirstName из HTTP-запроса.

Вы можете также передать массив как третий аргумент метода PHPdispatchFrom. Этот массив будет использоваться, чтобы заполнить любые параметры конструктора, которые не доступны из запроса:

PHP
$this->dispatchFrom('Command\Class\Name'$request, [
  
'firstName' => 'Taylor',
]);

Очередь команд

Командная шина предназначена не только для синхронных задач, которые работают во время прохождения текущего запроса. Она также служит основным методом создания очередей задач в Laravel. Так как же заставить командную шину поставить нашу задачу в очередь для фоновой обработки вместо того, чтобы выполнить её синхронно? Очень просто. Во-первых, при генерации новой команды, просто добавьте к команде флаг sh--queued:

shphp artisan make:command PurchasePodcast --queued

И вы увидите, это добавляет ещё несколько функций к команде, а именно, интерфейс Illuminate\Contracts\Queue\ShouldBeQueued и типаж PHPSerializesModels. С помощью них командная шина ставит команды в очередь, а также корректно сериализует и десериализует любые Eloquent-модели, которые содержатся в вашей команде как свойства.

Если вы хотите преобразовать существующую команду в команду для очереди, просто реализуйте интерфейс Illuminate\Contracts\Queue\ShouldBeQueued в классе вручную. Он не содержит методов и просто служит индикатором для командной шины.

Теперь просто пишите свою команду как обычно. Шина автоматически поставит команду в очередь для фоновой обработки.

Для получения дополнительной информации о взаимодействии с очередью команд просмотрите полную документацию по очередям.

Конвейер команд

Прежде чем команда передастся в обработчик, вы можете передать её через другие классы на «конвейер». Каналы команд работают как HTTP-middleware, за исключением ваших команд! Например, канал команды может обернуть всю работу команды в транзакцию базы данных, или просто зарегистрировать в логе её выполнение.

Чтобы добавить канал в вашу шину, вызовите метод диспетчера PHPpipeThrough из вашего метода PHPApp\Providers\BusServiceProvider::boot:

PHP
$dispatcher->pipeThrough(['UseDatabaseTransactions''LogCommand']);

Канал команды определяется в методе PHPhandle, подобно middleware:

PHP
class UseDatabaseTransactions {

  public function 
handle($command$next)
  {
    return 
DB::transaction(function() use ($command$next)
    {
      return 
$next($command);
    });
  }

}

Классы каналов команд выполняются через IoC-контейнер, поэтому свободно указывайте типы любых необходимых зависимостей в их конструкторах.

Вы можете даже определить PHPClosure в качестве канала команды:

PHP
$dispatcher->pipeThrough([function($command$next)
{
  return 
DB::transaction(function() use ($command$next)
  {
    return 
$next($command);
  });
}]);

Комментарии (1)

SurRealistik

Как определить выполняется ли команда в данный момент?

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.