utilitarian-dev / utilitarian-laravel-toolkit
Laravel implementation of Utilitarian Architecture: CQRS operations (Query, Command, Action), State Machine, and Data mapping utilities
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/utilitarian-dev/utilitarian-laravel-toolkit
Requires
- php: ^8.3
- illuminate/contracts: ^11.25|^12.0
- illuminate/support: ^11.25|^12.0
Requires (Dev)
- laradumps/laradumps: ^4.0
- laravel/pint: ^1.13
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
Suggests
- laradumps/laradumps: Enhanced debugging and dumping for Laravel (^4.0)
This package is not auto-updated.
Last update: 2026-02-07 08:20:11 UTC
README
Laravel implementation of Utilitarian Architecture — a pragmatic approach to organizing applications around business operations (use cases) rather than technical layers.
Requirements
- PHP 8.3+
- Laravel 11+
Installation
composer require utilitarian-dev/utilitarian-laravel-toolkit
The service provider is registered automatically via Laravel's package discovery.
Optionally, publish the configuration:
php artisan vendor:publish --tag=utilitarian-config
Core Components
Query
Read-only operations. Execute via QueryBus or dispatch().
class GetUserQuery extends Query { public function __construct( private readonly int $userId, ) {} protected function boot(UserRepository $repo): void { $this->repository = $repo; } public function execute(): ?User { return $this->repository->find($this->userId); } } // Execute $user = GetUserQuery::make(userId: 1)->dispatch(); // or $user = QueryBus::execute(GetUserQuery::make(userId: 1));
Command
Write-only operations. Execute via CommandBus or dispatch().
class CreateUserCommand extends Command { public function __construct( private readonly string $email, private readonly string $name, ) {} protected function boot(UserRepository $repo): void { $this->repository = $repo; } public function execute(): User { return $this->repository->create([ 'email' => $this->email, 'name' => $this->name, ]); } } // Execute $user = CreateUserCommand::make(email: '...', name: '...')->dispatch();
Action
Business logic and orchestration. Execute directly via run().
class RegisterUserAction extends Action { public function __construct( private readonly string $email, private readonly string $name, ) {} public function execute(): User { $user = CreateUserCommand::make( email: $this->email, name: $this->name )->dispatch(); SendWelcomeEmailCommand::make(userId: $user->id)->dispatch(); return $user; } } // Execute $user = RegisterUserAction::make(email: '...', name: '...')->run();
Middleware
Configure middleware in config/utilitarian.php:
return [ 'cqrs' => [ 'query_middleware' => [ \Utilitarian\Cqrs\Middleware\CachingMiddleware::class, ], 'command_middleware' => [ \Utilitarian\Cqrs\Middleware\TransactionMiddleware::class, ], 'action_middleware' => [ \Utilitarian\Cqrs\Middleware\AuthorizationMiddleware::class, ], ], ];
Per-operation middleware:
class MyQuery extends Query { protected function middleware(): array { return [CustomMiddleware::class]; } protected function excludeMiddleware(): array { return [UnwantedMiddleware::class]; } }
Built-in middleware:
TransactionMiddleware— wraps execution in database transactionCachingMiddleware— caches query resultsValidationMiddleware— validates operation dataAuthorizationMiddleware— checks access permissions
State Machine
Manage state for Eloquent models with three levels of complexity:
use Utilitarian\StateMachine\Traits\HasStateMachine; class Order extends Model { use HasStateMachine; }
Key-Value Storage
$order->state()->set('notes', 'Special handling'); $order->state()->get('notes'); $order->state()->has('notes'); $order->state()->forget('notes');
Enum States (no rules)
$order->state()->transitionTo(OrderState::Paid); $order->state()->current(); // OrderState::Paid $order->state()->is(OrderState::Paid); // true
Enum States (with transition rules)
enum OrderState: string implements FlowHandler { case Pending = 'pending'; case Paid = 'paid'; case Shipped = 'shipped'; public function canTransitionTo(UnitEnum $target): bool { return match ($this) { self::Pending => $target === self::Paid, self::Paid => $target === self::Shipped, self::Shipped => false, }; } } $order->state()->transitionTo(OrderState::Paid); // OK $order->state()->transitionTo(OrderState::Shipped); // throws InvalidTransitionException
Database Setup:
Migrations are loaded automatically. Run:
php artisan migrate
Data Mapping
Lightweight DTOs with automatic property mapping:
use Utilitarian\Data\Data; class UserData extends Data { public function __construct( public readonly int $id, public readonly string $email, public readonly string $name, ) {} } // Create from array $userData = UserData::from([ 'id' => 1, 'email' => 'user@example.com', 'name' => 'John Doe', ]); // Convert back to array $array = $userData->toArray();
Custom field mapping:
use Utilitarian\Data\Attributes\MapField; class UserData extends Data { public function __construct( public readonly int $id, #[MapField('email_address')] public readonly string $email, ) {} }
Testing
composer test # Run tests composer test:coverage # Run with coverage vendor/bin/pest --filter TestName # Run specific test
Code Quality
composer lint # Fix code style composer lint:test # Check code style
License
Licensed under the Apache License 2.0. See LICENSE for details.
Credits
Created by Vasilii Shvakin