Divide Laravel into components

Hello, Habr. Recently I got an interesting project in my hands, which, despite its simplicity, demanded not to use any framework. There was no talk of packages, so it was decided to use the usual Laravel components. If you need to use queues, Eloquent or a container - welcome to cat.


On the simplicity of dividing the framework into components


Starting with Laravel 4, all components are separate packages, which in theory can be made to work in any PHP project. However, some components require additional customization, which in the main framework is hidden under the hood.


Components


Container


Of all the components under consideration, illuminate/container is the easiest to install and use.


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

However, calling a static method on the Container class every time you use a container is not a good idea. The app() is available in the framework, which will return the global container instance to us, however, we need to create one manually.


Create a helpers.php file for such helpers, and add it to startup.


 "autoload": { "files": [ "src/helpers.php" ], "psr-4": { "YourApp\\": "src/" } } 

Add the app() helper to the file.


 <?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); } } 

Done. You can try to use a helper.


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

Query Builder and Eloquent


To use the illuminate/database component, we will use Capsule\Manager , a class designed to work with the query builder outside of Laravel.


Let's start by setting up a connection to the database. It is advisable to carry out this configuration at the startup stage of your application, immediately after connecting 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(); 

You can get started with the query builder.


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

What about Eloquent?


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

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

The situation is more complicated with migrations - on the one hand, there is a Schema Builder in the kit. On the other hand, there is no automatic mechanism for starting migrations.


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

To start, just execute the file with migration: php migration.php


Queues


Queues also have their own Capsule , however, the analogs of queue:work and queue:listen must be written manually.


Let's start with the Application class. In Laravel, this class is used as a global container instance, which, in addition to the Illuminate\Container\Container methods, contains auxiliary methods for working with the framework (current version, storage paths, resources). However, our class will contain only one method - isDownForMaintenance . It is necessary for the work of the worker, as it determines the state of the application at the moment.


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

Next, we need to register the illuminate/events provider, and bind the Illuminate\Contracts\Events\Dispatcher contract to the events alias.


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

Now you need to create the Capsule instance, and add the connection configurations there.


Example configuration for the database


 <?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); }); 

Configuration example for Redis (requires 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(); 

The final step in the configuration is to add an analog 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 configuration completed. Now you can start writing 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); 

Now to start the queue worker, just write php worker.php .


If there is a need to use queue:listen , then you need to create two separate files. One is a daemon that listens to the queue and runs a second file on every new job. The second file, in turn, acts as the executor of the task.


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); 

We pass to use. All methods can be viewed in the API.


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


Source: https://habr.com/ru/post/475144/


All Articles