├── src ├── Contracts │ ├── ProcessPayload.php │ └── TaskContract.php ├── Providers │ └── PackageServiceProvider.php └── Process.php ├── phpstan.neon ├── phpunit.xml ├── LICENSE ├── pint.json ├── composer.json └── README.md /src/Contracts/ProcessPayload.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests 6 | 7 | 8 | 9 | 10 | 11 | ./app 12 | ./src 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Process.php: -------------------------------------------------------------------------------- 1 | > 15 | */ 16 | protected array $tasks = []; 17 | 18 | /** 19 | * @param ProcessPayload $payload 20 | * @return mixed 21 | */ 22 | public function run(ProcessPayload $payload): mixed 23 | { 24 | return Pipeline::send( 25 | passable: $payload, 26 | )->through( 27 | pipes: $this->tasks, 28 | )->thenReturn(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Steve McDougall. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "psr12", 3 | "rules": { 4 | "align_multiline_comment": true, 5 | "array_indentation": true, 6 | "array_syntax": true, 7 | "blank_line_after_namespace": true, 8 | "blank_line_after_opening_tag": true, 9 | "combine_consecutive_issets": true, 10 | "combine_consecutive_unsets": true, 11 | "concat_space": true, 12 | "declare_parentheses": true, 13 | "declare_strict_types": true, 14 | "explicit_string_variable": true, 15 | "final_class": true, 16 | "final_internal_class": false, 17 | "fully_qualified_strict_types": true, 18 | "global_namespace_import": { 19 | "import_classes": true, 20 | "import_constants": true, 21 | "import_functions": true 22 | }, 23 | "is_null": true, 24 | "lambda_not_used_import": true, 25 | "logical_operators": true, 26 | "mb_str_functions": true, 27 | "method_chaining_indentation": true, 28 | "modernize_strpos": true, 29 | "new_with_braces": true, 30 | "no_empty_comment": true, 31 | "not_operator_with_space": true, 32 | "ordered_traits": true, 33 | "protected_to_private": true, 34 | "simplified_if_return": true, 35 | "strict_comparison": true, 36 | "ternary_to_null_coalescing": true, 37 | "trim_array_spaces": true, 38 | "use_arrow_functions": true, 39 | "void_return": true, 40 | "yoda_style": true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "juststeveking/laravel-business-process", 3 | "description": "Laravel Business Process is a simple and clean way to run business process using a Laravel Pipeline, in a structured and type-safe way.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "role": "Developer", 8 | "name": "Steve McDougall", 9 | "email": "juststevemcd@gmail.com", 10 | "homepage": "https://www.juststeveking.uk/" 11 | } 12 | ], 13 | "autoload": { 14 | "psr-4": { 15 | "JustSteveKing\\BusinessProcess\\": "src/" 16 | } 17 | }, 18 | "autoload-dev": { 19 | "psr-4": { 20 | "JustSteveKing\\BusinessProcess\\Tests\\": "tests/" 21 | } 22 | }, 23 | "require": { 24 | "php": "^8.2" 25 | }, 26 | "require-dev": { 27 | "laravel/pint": "^1.9", 28 | "orchestra/testbench": "^8.5", 29 | "pestphp/pest": "^2.5.2", 30 | "phpstan/phpstan": "^1.10.14" 31 | }, 32 | "scripts": { 33 | "pint": [ 34 | "./vendor/bin/pint" 35 | ], 36 | "stan": [ 37 | "./vendor/bin/phpstan analyse" 38 | ], 39 | "test": [ 40 | "./vendor/bin/pest" 41 | ] 42 | }, 43 | "extra": { 44 | "laravel": { 45 | "providers": [ 46 | "JustSteveKing\\BusinessProcess\\Providers\\PackageServiceProvider" 47 | ] 48 | } 49 | }, 50 | "config": { 51 | "sort-packages": true, 52 | "optimize-autoloader": true, 53 | "allow-plugins": { 54 | "pestphp/pest-plugin": true 55 | } 56 | }, 57 | "minimum-stability": "dev", 58 | "prefer-stable": true 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Business Process 2 | 3 | 4 | [![Latest Version][badge-release]][packagist] 5 | [![Software License][badge-license]][license] 6 | [![Run Tests](https://github.com/JustSteveKing/laravel-business-process/actions/workflows/tests.yml/badge.svg)](https://github.com/JustSteveKing/laravel-business-process/actions/workflows/tests.yml) 7 | [![PHP Version][badge-php]][php] 8 | [![Total Downloads][badge-downloads]][downloads] 9 | 10 | [badge-release]: https://img.shields.io/packagist/v/juststeveking/laravel-business-process.svg?style=flat-square&label=release 11 | [badge-license]: https://img.shields.io/packagist/l/juststeveking/laravel-business-process.svg?style=flat-square 12 | [badge-php]: https://img.shields.io/packagist/php-v/juststeveking/laravel-business-process.svg?style=flat-square 13 | [badge-downloads]: https://img.shields.io/packagist/dt/juststeveking/laravel-business-process.svg?style=flat-square&colorB=mediumvioletred 14 | 15 | [packagist]: https://packagist.org/packages/juststeveking/laravel-business-process 16 | [license]: https://github.com/juststeveking/laravel-business-process/blob/main/LICENSE 17 | [php]: https://php.net 18 | [downloads]: https://packagist.org/packages/juststeveking/laravel-business-process 19 | 20 | 21 | Laravel Business Process is a simple and clean way to run business process using a Laravel Pipeline, in a structured and type-safe way. 22 | 23 | This package is inspired by the tutorial I wrote for Laravel News [Going Past Actions in Laravel](https://laravel-news.com/going-past-actions-in-laravel). 24 | 25 | ## Installation 26 | 27 | ```shell 28 | composer require juststeveking/laravel-business-process 29 | ``` 30 | 31 | ## Usage 32 | 33 | To get started with this package, all you need to do is create a new process class: 34 | 35 | ```php 36 | use JustSteveKing\BusinessProcess\Process; 37 | 38 | final class PurchaseProduct extends Process 39 | { 40 | protected array $tasks = [ 41 | CheckStockLevel::class, 42 | ProcessOrder::class, 43 | DecreaseStockLevel::class, 44 | NotifyWarehouse::class, 45 | EmailCustomer::class, 46 | ]; 47 | } 48 | ``` 49 | 50 | Our process class registers the tasks that need to be completed for this process to run, each task must implement the `TaskContract` interface that comes with this package. 51 | 52 | ```php 53 | use JustSteveKing\BusinessProcess\Contracts\TaskContract; 54 | 55 | final class CheckStockLevel implements TaskContract 56 | { 57 | public function __invoke(ProcessPayload $payload, Closure $next): mixed 58 | { 59 | // perform your logic here with the passed in payload. 60 | 61 | return $next($payload); 62 | } 63 | } 64 | ``` 65 | 66 | Your tasks are standard classes that the `Pipeline` class from Laravel would expect. 67 | 68 | The payload is a class that implements `ProcessPayload` interface, signalling that it is a payload for a process. They are simple plain old PHP classes with no requirements to add methods. 69 | 70 | ```php 71 | use JustSteveKing\BusinessProcess\Contracts\ProcessPayload; 72 | 73 | final class PurchaseProductPayload implements ProcessPayload 74 | { 75 | public function __construct( 76 | // add whatever public properties you need here 77 | public int $product, 78 | public int $user, 79 | public int $order, 80 | ) {} 81 | } 82 | ``` 83 | 84 | Finally, we can call this process within our controller/job/cli wherever you need to. 85 | 86 | ```php 87 | final class PurchaseController 88 | { 89 | public function __construct( 90 | private readonly PurchaseProduct $process, 91 | ) {} 92 | 93 | public function __invoke(PurchaseRequest $request, int $product): JsonResponse 94 | { 95 | try { 96 | $this->process->run( 97 | payload: $request->payload(), 98 | ); 99 | } catch (Throwable $exception) { 100 | // Handle exception 101 | } 102 | 103 | // return response. 104 | } 105 | } 106 | ``` 107 | ## Testing 108 | 109 | To run the test: 110 | 111 | ```bash 112 | composer run test 113 | ``` 114 | 115 | ## Credits 116 | 117 | - [Steve McDougall](https://github.com/JustSteveKing) 118 | - [All Contributors](../../contributors) 119 | 120 | ## LICENSE 121 | 122 | The MIT License (MIT). Please see [License File](./LICENSE) for more information. 123 | 124 | --------------------------------------------------------------------------------