Builder/manager pattern in Laravel
In Hungary, there are many invoice services, and I want to give clients the choice of which one they prefer. To facilitate easy configuration and changes, I have implemented the Manager (builder) pattern. I will show you the pattern-related codes.
Let's create the config file, call it config/invoice.php
.
<?php
return [
/*
|--------------------------------------------------------------------------
| Default driver
|--------------------------------------------------------------------------
|
| You can change the invoice driver. Example: pdf, billingo, szamlazzhu
*/
'driver' => env('INVOICE_DRIVER', 'pdf'),
];
Now create the Interface for the driver app/Driver/InvoiceInterface.php
.
<?php
namespace App\Drivers;
interface InvoiceInterface
{
public function run($data);
}
Create the Billingo invoice class app/Driver/Billingo.php
.
<?php
namespace App\Drivers;
class Billingo implements InvoiceInterface
{
public function run($data)
{
// Do your action
}
}
Create the PDF invoice class app/Driver/PDF.php
.
<?php
namespace App\Drivers;
class PDF implements InvoiceInterface
{
public function run($data)
{
// Create a pdf
}
}
Create the Manager class app/Managers/InvoiceManager.php
where we load our Drivers.
<?php
namespace App\Managers;
use App\Drivers\Billingo;
use App\Drivers\PDF;
use Illuminate\Support\Manager;
class InvoiceManager extends Manager
{
public function createBillingoDriver(): Billingo
{
return new Billingo();
}
public function createPdfDriver(): PDF
{
return new PDF();
}
public function getDefaultDriver()
{
return $this->config->get('invoice.driver');
}
}
Register the InvoiceManager in the service provider app/Providers/AppServiceProvider.php
.
public function register(): void
{
$this->app->singleton('invoice', function ($app) {
return new InvoiceManager($app);
});
}
Create a Facade to access the Invoice anywhere app/Facades/Invoice.php
.
<?php
namespace App\Facades;
use App\Managers\InvoiceManager;
use Closure;
use Illuminate\Support\Facades\Facade;
use RuntimeException;
/**
* @method static InvoiceManager getDefaultDriver()
* @method static InvoiceManager driver(string $name)
* @method static InvoiceManager extend(string $driver, Closure $callback)
* @method static mixed run($data)
*/
class CreateInvoice extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*
* @throws RuntimeException
*/
protected static function getFacadeAccessor()
{
return 'invoice';
}
}
And in your controller or anywhere else, just call the following:
Invoice::run($data);
If you want to change the default driver, you can do so by editing the INVOICE_DRIVER
variable in the .env file. Alternatively, you can change it on the fly by calling the Invoice with driver('billingo')
.
Invoice::driver('billingo')->run($data);
More example and explanation:
https://www.honeybadger.io/blog/laravel-manager-pattern/
https://laravel-news.com/manager-pattern-package-for-laravel
https://darkghosthunter.medium.com/laravel-the-hidden-manager-that-helps-you-with-any-driver-1a534d2b3570
https://refactoring.guru/design-patterns/builder/php/example