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.

v1.0.0 2025-03-03 00:16 UTC

This package is auto-updated.

Last update: 2025-07-01 00:09:42 UTC


README

Latest Version PHP Version Tests Total Downloads

🎯 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.