Запуск команд в Laravel c использованием Процессов

Источник: «Run Commands in Laravel Using Processes»
В этом руководстве вы узнаете, как использовать фасад Laravel Process, построенный на основе высокоэффективного компонента Symfony Process, для выполнения команд вне среды Laravel.

Laravel построил фасад вокруг высокоэффективного компонента Symfony Process позволяющего выполнять команды вне среды Laravel.

Процессы позволяют командам оболочки, таким как grep, и командам, которые вызывают внешние службы, такие как GitHub, выполняться асинхронно без потенциального нарушения определённого потока выполнения из-за синхронной природы PHP. Это происходит в режиме реального времени, с обратными вызовами и обработкой исключений.

Давайте рассмотрим, что это означает, с помощью базового примера кода ниже:

use Illuminate\Support\Facades\Process;

$result = Process::run('ls -la');

return $result->output();

В приведённом выше коде фасад Process вызывается и используется для запуска команды Linux ls, выводящая список всех файлов в каталоге, включая скрытые файлы, которые затем распечатываются.

Предварительные требования

  1. Знания PHP
  2. PHP 8.1
  3. Composer установленный глобально
  4. Postman или curl
  5. Опыт работы с Laravel и с командной строкой будут полезны, но не обязательны.

Варианты использования

Запуск команд CLI: Команды CLI представляют собой текстовые пользовательские интерфейсы, используемые для запуска команд и взаимодействия с компьютерными файлами и функциями. Процессы позволяют запускать команды CLI, подобные приведённому выше примеру, в приложении Laravel.

Асинхронные команды: Процессы могут выполняться асинхронно, не прерывая другие функции приложения Laravel. Кроме того, выходные данные асинхронного процесса всё ещё могут быть выведены без прерывания процесса.

Конвейеризация/piping нескольких процессов: Конвейеризация нескольких команд может пригодиться, когда вы хотите, чтобы более поздняя команда выполнялась после завершения предыдущей. С Процессами несколько команда, таких как, например, приведённая ниже, могут запускаться и выполняться синхронно.

$result = Process::pipe(function (Pipe $pipe) {
$pipe->command('ls -la');
$pipe->command('grep -i "PHP"');
});

Как видно, первой запускаемой командой является команда ls -la, которая выводит список файлов в каталоге, а затем команда grep -i "PHP" для проверки и извлечения файлов, содержащих текст PHP.

Параллельные функции: Параллельными задачами можно управлять одновременно с использованием Процесса. Это позволяет одновременно запускать несколько команд с использованием пользовательского пула функции. С помощью функции pool() команды запускаются как автономные и выполняются асинхронно.

Ниже приведён пример запуска нескольких сценариев для импорта файлов.

use Illuminate\Process\Pool;
use Illuminate\Support\Facades\Process;

$pool = Process::pool(function (Pool $pool) {
$pool->path(__DIR__)->command('bash import-1.sh');
$pool->path(__DIR__)->command('bash import-2.sh');
$pool->path(__DIR__)->command('bash import-3.sh');
})->start(function (string $type, string $output, int $key) {
// ...
});

$results = $pool->wait();

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

Создание шаблона приложения Laravel

Чтобы проверить возможности Процессов в Laravel, сначала нужно установить и настроить приложение Laravel, а затем установить в проекте пакет Symfony Process. Создайте новый проект, используя приведённую ниже команду.

composer create-project laravel/laravel laravel_processes

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

cd laravel_processes
php artisan serve

Ваше приложение должно работать по адресу http://localhost:8000.

Затем в новом сеансе терминала установите пакет Symfony Process, используя приведённую ниже команду.

composer require symfony/process

Добавление поддержки процессов

По умолчанию для запуска процесса требуется, чтобы функция run() запускала синхронные функции в среде Laravel, а функция start() зарезервирована для асинхронных функций. В ходе этого руководства мы разберём это, а пока создайте базовую функцию используя тестовый контроллер.

Создание контроллера

Контроллер будет содержать функции, которые при запуске запускают заложенные в них функции процесса. Чтобы сгенерировать контроллер, выполните приведённую ниже команду.

php artisan make:controller ProcessController

Это создаст файл app/Http/Controllers/ProcessController.php. Откройте файл и замените существующий код приведённым ниже кодом.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Process;

class ProcessController extends Controller
{
public function test() {
$result = Process::run('ls -la');
return $result->output();
}
}

Создание маршрута

Теперь, когда создан контроллер для вызова функции процесса, можем создать маршрут для запуска контроллера. Для этого перейдите в routes/api.php и добавьте новый маршрут GET, добавив следующий код в конец файла.

Route::get("/test", [App\Http\Controllers\ProcessController::class, 'test']);

Тестирование приложения

Тестирование можно выполнить с помощью команды curl, выполнив приведённую ниже команду.

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://127.0.0.1:8000/api/test

Вы должны увидеть вывод, аналогичный приведённому ниже примеру.

HTTP/1.1 200 OK
Host: 127.0.0.1:8001
Date: Fri, 16 Jun 2023 12:10:53 GMT
Connection: close
X-Powered-By: PHP/8.1.18
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache, private
Date: Fri, 16 Jun 2023 12:10:53 GMT
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
Access-Control-Allow-Origin: *

total 20
drwxrwxr-x 2 settermjd settermjd 4096 Jun 1 18:12 .
drwxrwxr-x 13 settermjd settermjd 4096 Jun 16 14:08 ..
-rw-rw-r-- 1 settermjd settermjd 603 Jun 1 18:12 .htaccess
-rw-rw-r-- 1 settermjd settermjd 0 Jun 1 18:12 favicon.ico
-rw-rw-r-- 1 settermjd settermjd 1710 Jun 1 18:12 index.php
-rw-rw-r-- 1 settermjd settermjd 24 Jun 1 18:12 robots.txt

Обработка ошибок

С помощью Процессов ошибки могут быть зарегистрированы в Laravel. Затем эти ошибки можно обработать внутренне или передать пользователю приложения. Это эффективно, потому что можно запускать внешние команды, и их результаты могут повлиять на поток активности в приложении Laravel, или ошибка просто регистрируется.

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

В app/Http/Controllers/ProcessController.php создайте новую функцию с именем error(). Затем включите функцию errorOutput() в обречённый на неудачу процесс, определив её следующим образом.

public function error() {
$result = Process::run("i-dont-exit");
return $result->errorOutput();
}

Затем добавьте маршрут для проверки ответа об ошибке в route/api.php.

Route::get('/error-handling', [ProcessController::class, 'error']);

Затем приступайте к тестированию функции с помощью curl.

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://127.0.0.1:8000/api/error-handling

В приведённом выше коде функция errorOutput() использовалась для вывода ошибки, полученной от процесса. Результатом, подобным приведённому ниже, должна быть обратная связь, которую вы получаете от терминала.

sh: i-dont-exist: command not found

Также для тестирования можно использовать Postman

Вот как запускать команды в Laravel с помощью Процессов

В этой статье мы рассмотрели, что такое Процесс в Laravel, варианты его использования, а также как запускать и обрабатывать внешние команды и возвращать ошибки. Вы можете подробно изучить другие компоненты Symfony, которые позволяют эффективно программировать на Laravel. Я надеюсь, что вы используете Процессы для проверки ваших CLI команд, чтобы получить соответствующие данные для лучшего программирования.

Дополнительные материалы

Предыдущая Статья

Как определить, когда элемент входит или выходит из области просмотра с помощью ванильного JavaScript

Следующая Статья

Свойства API-интерфейса IntersectionObserver