Using Laravel components individually
Starting from Laravel 4 all framework components are separate packages that can be used in any PHP project without using the laravel/framework
package.
In this post, I'll demonstrate the usage of illuminate/container
, illuminate/queue
, illuminate/events
, illuminate/redis
and illuminate/database
in a project without the Laravel framework.
Components
Container
Out of all components presented in this post, illuminate/container
is the easiest one to install and use.
<?php
use Illuminate\Container\Container;
$container = Container::getInstance();
return $container->make(Foo::class);
But we can go further and create the app() helper that we can use to quickly resolve dependencies.
Let's start by creating the file called helpers.php
:
<?php
use Illuminate\Container\Container;
if (! function_exists('app')) {
function app($abstract = null, array $parameters = [])
{
if (is_null($abstract)) {
return Container::getInstance();
}
return Container::getInstance()->make($abstract, $parameters);
}
}
Don't forget to add helpers.php
to the autoload
section of the composer.json
file:
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"YourApp\\": "src/"
}
}
Let's try it out.
<?php
$container = app();
$foo = app(Foo::class);
Database
Basic setup and Query Builder
Conveniently, illuminate/database
provides us with the Capsule\Manager class, designed for query builder integration outside of Laravel applications.
Let's start with the database connection configuration by creating the bootstrap.php
file with the following contents:
<?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' => '',
]);
$manager->setAsGlobal();
We can try querying the database now:
<?php
use Illuminate\Database\Capsule\Manager;
return Manager::table('orders')->get();
Eloquent
We can now send queries to the database using the query builder. But what about Eloquent ORM?
You can expect Eloquent ORM to work out of the box:
<?php
namespace YourApp\Models;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
protected $fillable = [
'name',
];
}
<?php
use YourApp\Models\Order;
Order::first();
Migrations
We can use the schema method to obtain a Schema\Builder
instance used to compose migrations:
<?php
use Illuminate\Database\Capsule\Manager;
Manager::schema()->create('orders', function ($table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
To run database migrations just execute the database migration file with php migration.php
.
Events
Laravel already provides us with the dispatcher singleton, so we'll just register the service provider in the global container instance:
<?php
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Events\EventServiceProvider;
(new EventServiceProvider(app()))->register();
app()->bind(Dispatcher::class, 'events');
Redis
To use illuminate/redis
you just need to bind the RedisManager instance to the redis
alias:
<?php
use Illuminate\Redis\RedisManager;
app()->bind('redis', function () {
return new RedisManager(app(), 'predis', [
'default' => [
'host' => '127.0.0.1',
'password' => null,
'port' => 6379,
'database' => 0
]
]);
});
Queues
Similarly to illuminate/database
, illuminate/queue
also provides us with the Capsule\Manager class. However, we still need to implement the queue:work
and queue:listen
commands ourselves.
Let's start with the Application contract.
In Laravel, this contract provides us with:
- Global container instance
- Current framework version
- Paths to storage, resources
- other things, that you can find here
Our implementation (without the actual implements Application
syntax) of this contract will contain only one method - isDownForMaintenance
, that will always return false
, as our application won't need any maintenance (hopefully):
<?php
namespace YourApp;
use Illuminate\Container\Container;
class Application extends Container
{
public function isDownForMaintenance()
{
return false;
}
}
Example configuration for the database
driver:
<?php
use Illuminate\Queue\Capsule\Manager;
use Illuminate\Queue\Connectors\DatabaseConnector;
use Illuminate\Database\Capsule\Manager as DatabaseManager;
use Illuminate\Database\ConnectionResolver;
$queue = new Manager(app());
$queue->addConnection([
'driver' => 'database',
'table' => 'jobs',
'connection' => 'default',
'queue' => 'default'
]);
$queue->setAsGlobal();
$resolver = new ConnectionResolver([
'default' => DatabaseManager::connection()
]);
$queue->getQueueManager()
->addConnector('database', function () use ($resolver) {
return new DatabaseConnector($resolver);
});
Redis configuration example:
<?php
use Illuminate\Queue\Capsule\Manager;
$queue = new Manager(app());
$queue->addConnection([
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default'
]);
$queue->setAsGlobal();
Now, we need to add the exception handler:
<?php
use Exception;
use Illuminate\Contracts\Debug\ExceptionHandler;
class Handler implements ExceptionHandler
{
public function report(Exception $e)
{
}
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();
});
Finally, let's implement the queue:work
command:
<?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());
To start a queue worker, use php worker.php
.
For cases when your code has memory leaks requires testing you can use the queue:listen
command.
Here, two PHP files are required, as queue job listener and executor are two different processes in this case.
listener.php
:
<?php
require_once __DIR__.'/bootstrap/bootstrap.php';
use Illuminate\Queue\Listener;
use Illuminate\Queue\ListenerOptions;
define('ARTISAN_BINARY', 'process.php');
$worker = app(Listener::class, [
'commandPath' => __DIR__
]);
$worker->setOutputHandler(function ($type, $line) {
echo $line;
});
$worker->listen('default', 'default', new ListenerOptions());
process.php
:
<?php
require_once __DIR__.'/bootstrap/bootstrap.php';
use Illuminate\Queue\Worker;
use Illuminate\Queue\WorkerOptions;
use Illuminate\Queue\Capsule\Manager;
$queueWorker = Manager::getQueueWorker();
$worker = new Worker($queueManager, app('events'), app('exception.handler'));
$worker->runNextJob('default', 'default', new WorkerOptions());
You can start listening with php listener.php
.
Queueing new jobs looks like this:
<?php
use Illuminate\Queue\Capsule\Manager;
Manager::push(SomeJob::class);
Links