Хабрахабр

[Из песочницы] Делим Laravel на компоненты

Недавно получил в руки интересный проект, который, несмотря на свою простоту требовал не использовать какой-либо фреймворк. Привет, Хабр. Если есть необходимость в использовании очередей, Eloquent или контейнера — добро пожаловать под кат. О пакетах речи не шло, поэтому было принято решение использовать привычные компоненты Laravel.

О простоте деления фреймворка на компоненты

Однако, некоторые компоненты требуют дополнительной настройки, которая в основном фреймворке спрятана под капот. Начиная с Laravel 4, все компоненты — отдельные пакеты, которые в теории можно заставить работать в любом PHP проекте.

Компоненты

Контейнер

Из всех рассматриваемых компонентов illuminate/container — самый простой в установке и использовании.

<?php use Illuminate\Container\Container; $container = Container::getInstance(); return $container->make(Foo::class);

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

Создадим файл helpers.php для таких хелперов, и добавим его в автозагрузку.

"autoload":
}

Добавляем хелпер app() в файл.

<?php use Illuminate\Container\Container; if (! function_exists('app')) { /** * Get the available container instance. * * @param string|null $abstract * @param array $parameters * @return mixed|\Illuminate\Container\Container */ function app($abstract = null, array $parameters = []) { if (is_null($abstract)) { return Container::getInstance(); } return Container::getInstance()->make($abstract, $parameters); }
}

Можно пробовать использовать хелпер. Готово.

<?php return app(Foo::class);

Query Builder и Eloquent

Для использования компонента illuminate/database мы будем использовать Capsule\Manager — класс, предназначенный для работы с построителем запросов вне Laravel.

Желательно эту настройку проводить на этапе запуска вашего приложения, сразу после подключения autoload.php. Начнём с настройки подключения к БД.

<?php require_once __DIR__.'/../vendor/autoload.php'; use Illuminate\Database\Capsule\Manager; $manager = new Manager; $manager->addConnection([ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'database', 'username' => 'root', 'password' => 'password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '',
]); // Позволяет использовать статичные вызовы при работе с Capsule.
$manager->setAsGlobal();

Можно начинать работу с построителем запросов.

<?php use Illuminate\Database\Capsule\Manager; return Manager::table('orders')->get();

Что насчёт Eloquent?

<?php namespace YourApp\Models; use Illuminate\Database\Eloquent\Model; class Order extends Model { protected $fillable = [ 'name', ];
}

<?php use YourApp\Models\Order; Order::first();

С другой — автоматический механизм запуска миграций отсутствует. С миграциями ситуация сложнее — с одной стороны, в комплекте есть Schema Builder.

<?php use Illuminate\Database\Capsule\Manager; Manager::schema()->create('orders', function ($table) { $table->bigIncrements('id'); $table->string('name'); $table->timestamps();
});

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

Очереди

У очередей тоже есть свой Capsule, однако аналоги queue:work и queue:listen необходимо писать вручную.

В Laravel этот класс используется как глобальный инстанс контейнера, который помимо методов Illuminate\Container\Container содержит вспомогательные методы для работы с фреймворком (текущая версия, пути к хранилищу, ресурсам). Начнём с класса Application. Он необходим для работы воркера, так как определяет состояние работы приложения в данный момент. Однако, наш класс будет содержать лишь один метод — isDownForMaintenance.

<?php namespace YourApp; use Illuminate\Container\Container; class Application extends Container { public function isDownForMaintenance() { return false; }
}

Далее, нам необходимо зарегистрировать провайдер illuminate/events, и забиндить контракт Illuminate\Contracts\Events\Dispatcher к алиасу events.

<?php use YourApp\Application;
use Illuminate\Contracts\Events\Dispatcher; $application = Application::getInstance();
$application->bind(Dispatcher::class, 'events');

Теперь необходимо создать инстанс Capsule, и добавить туда конфигурации соединений.

Пример конфигурации для БД

<?php use YourApp\Application;
use Illuminate\Queue\Capsule\Manager;
use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\ConnectionResolver; $container = Application::getInstance();
$queue = new Manager($container); $queue->addConnection([ 'driver' => 'database', 'table' => 'jobs', 'connection' => 'default', 'queue' => 'default',
], 'default'); // Также, как и с Illuminate\Database\Capsule\Manager позволяет использовать статичные вызовы для очередей
$queue->setAsGlobal(); $connection = Capsule::schema()->getConnection();
$resolver = new ConnectionResolver(['default' => $connection]); $queue->getQueueManager()->addConnector('database', function () use ($resolver) { return new DatabaseConnector($resolver);
});

Пример конфигурации для Redis (требует установленного illuminate/redis)

<?php use Illuminate\Redis\RedisManager;
use Illuminate\Queue\Capsule\Manager; $container->bind('redis', function () use ($container) { return new RedisManager($container, 'predis', [ 'default' => [ 'host' => '127.0.0.1', 'password' => null, 'port' => 6379, 'database' => 0, ] ]);
}); $queue = new Manager($container);
$queue->addConnection([ 'driver' => 'redis', 'connection' => 'default', 'queue' => 'default',
], 'default'); $queue->setAsGlobal();

Последний этап в конфигурации — добавление аналога Exception Handler.

<?php use Illuminate\Contracts\Debug\ExceptionHandler; class Handler implements ExceptionHandler { public function report(Exception $e) { // Действие, если Exception подпадает под критерии об уведомлении. // Пример: отправка в Sentry, отправка сообщения на почту. } public function render($request, Exception $e) { // Отображение ошибки } public function renderForConsole($output, Exception $e) { // Отображение ошибки, если среда запуска приложения - терминал } public function shouldReport(\Exception $e) { // Необходимо ли уведомлять об ошибке }
} app()->bind('exception.handler', function () { return new Handler;
});

Теперь можно приступать к написанию queue:work. Конфигурация очередей завершена.

<?php require_once __DIR__.'/bootstrap/bootstrap.php'; use Illuminate\Queue\Worker;
use Illuminate\Queue\Capsule\Manager;
use Illuminate\Queue\WorkerOptions; $queueManager = Manager::getQueueManager(); $worker = new Worker($queueManager, app('events'), app('exception.handler')); $worker->daemon('default', 'default', new WorkerOptions);

Теперь для запуска воркера очередей достаточно написать php worker.php.

Один — демон, который слушает очередь, и запускает второй файл на каждый новый job. Если же есть необходимость в использовании queue:listen, то нужно создавать два отдельных файла. Второй файл, в свою очередь, выступает в роли исполнителя задачи.

worker.php

<?php require_once __DIR__.'/bootstrap/bootstrap.php'; use Illuminate\Queue\Listener;
use Illuminate\Queue\ListenerOptions; // По умолчанию, в качестве "второго файла", в Laravel выступает artisan, однако в нашем случае это будет файл work.php.
// https://github.com/laravel/framework/blob/6.x/src/Illuminate/Queue/Listener.php#L72
define('ARTISAN_BINARY', 'work.php'); $worker = app(Listener::class, ['commandPath' => __DIR__]); $worker->setOutputHandler(function ($type, $line) { echo $line;
}); $worker->listen('default', 'default', new ListenerOptions);

work.php

<?php require_once 'bootstrap/bootstrap.php'; use Illuminate\Queue\Worker;
use Illuminate\Queue\WorkerOptions;
use Illuminate\Queue\Capsule\Manager; $queueManager = Manager::getQueueManager(); $worker = new Worker($queueManager, app('events'), app('exception.handler')); $worker->runNextJob('default', 'default', new WorkerOptions);

Все методы можно просмотреть в API Переходим к использованию.

<?php
use Illuminate\Queue\Capsule\Manager; Manager::push(SomeJob::class);

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть