jcesarbueno / laravel-strategy
A Laravel package for generating Strategy Design Pattern, along with Factory and Chain of Responsibility support.This package provides an Artisan command to quickly scaffold strategies, keeping your Laravel project well-structured.
Requires
- php: >=8.0
- illuminate/support: ^10.48
Requires (Dev)
- laravel/pint: ^1.20
- orchestra/testbench: ^8.33
- pestphp/pest: ^2.36
- pestphp/pest-plugin-laravel: ^2.4
- phpstan/phpstan: ^2.1
- rector/rector: ^2.0
README
π― Laravel Strategy Package
A Laravel package for generating Strategy Design Pattern, along with Factory and Chain of Responsibility support.
This package provides an Artisan command to quickly scaffold strategies, keeping your Laravel project well-structured.
π Features
- β Generates Strategy Pattern classes
- β Creates a Factory for handling strategy instances
- β Supports Chain of Responsibility (Pipelines)
- β Keeps Strategies organized in a dedicated folder
- β Fully tested with PestPHP & PHPStan for static analysis
π¦ Installation
Require the package via Composer:
composer require jcesarbueno/laravel-strategy:^1.0
βοΈ How It Works
Run the following Artisan command:
php artisan make:strategy SendNotification
You will be prompted with interactive questions:
1οΈβ£ Which methods should it have? (Enter method names one by one, press Enter on an empty line to finish)
2οΈβ£ Which concrete implementations should it have? (Enter class names one by one, press Enter on an empty line to finish)
3οΈβ£ Do you want to create Pipelines (Chain of Responsibility) for the Strategy? (Answer yes or no)
π Generated Structure
For example, if you create a SendNotification strategy with method send(), and implementations ApiEvent, SlackEvent and EmailEvent, the package will generate:
app/Strategies/SendNotification/ βββ Contracts/ β βββ SendNotificationContract.php βββ Factories/ β βββ SendNotificationFactory.php βββ Pipelines/ β βββ SendNotificationPipeline.php (if selected) βββ Implementations/ β βββ ApiNotification.php β βββ SlackNotification.php β βββ EmailNotification.php
Then, you can use the SendNotificationFactory to get the desired implementation:
use App\Strategies\SendNotification\Factories\SendNotificationFactory; use App\Models\Customer; $notificationType = Customer::find(1)->notification_type; // Choose the implementation in runtime $sendNotification = SendNotificationFactory::make($notificationType); $sendNotification->send();
You can also use the prebuilt Pipeline to handle the chain of responsibility:
You can create more than one pipeline for the same strategy, each one with a different responsibility. Just copy the SendNotificationPipeline and change the name.
namespace App\Strategies\SendNotification\Pipelines; use Closure; class EnsureNotificationTextIsNotEmpty { public function handle($customer, Closure $next) { if (empty($customer->event->text)) { throw new \Exception('Notification text cannot be empty'); } return $next($customer); } }
namespace App\Strategies\SendNotification\Pipelines; use Closure; class EnsureCustomerHasEmail { public function handle($customer, Closure $next) { if (empty($customer->email)) { throw new \Exception('Customer must have an email'); } return $next($customer); } }
Then, you can choose which pipeline to use in each implementation using the function getPipelines():
public function getPipelines(): array { return [ EnsureNotificationTextIsNotEmpty::class, EnsureCustomerHasEmail::class, ]; }
And another implementation can have a different pipeline:
public function getPipelines(): array { return [ EnsureNotificationTextIsNotEmpty::class, ]; }
Now you just call the Pipeline after creating the strategy:
use App\Strategies\SendNotification\Factories\SendNotificationFactory; use App\Models\Customer; use Illuminate\Support\Facades\Pipeline; $customer = Customer::find(1); $sendNotification = SendNotificationFactory::make($customer->notification_type); Pipeline::send($customer) ->through($sendNotification->getPipelines()) ->then(function ($customer) use ($sendNotification) { $sendNotification->send(); });
Other Usages for Pipelines
You can use the Pipeline to filter the data before sending it to the strategy, or to handle exceptions in a more organized way.
namespace App\Strategies\SendNotification\Pipelines; use Illuminate\Support\Collection; use Closure; class FilterNotSendedEvents { public function handle(Collection $events, Closure $next) { $events->filter(function ($event) { return $event->sended === false; }); return $next($events); } }
Just chain the Pipelines to filter the desired data.
use App\Strategies\SendNotification\Factories\SendNotificationFactory; use App\Models\Customer; use Illuminate\Support\Facades\Pipeline; $customer = Customer::with('events')->find(1); $sendNotification = SendNotificationFactory::make($customer->notification_type); $filteredEvents = Pipeline::send($customer->events) ->through($sendNotification->getPipelines()) ->thenReturn(); $sendNotification->send($filteredEvents);
π License
This package is open-source software licensed under the MIT license.
π§βπ» Author
This package was created by JΓΊlio CΓ©sar Bueno, Laravel developer since 2023.