Skip to content

Instantly share code, notes, and snippets.

@pelmered
Created July 11, 2025 17:48
Show Gist options
  • Save pelmered/d88744b89a9ca6d1bf592e9f9926e052 to your computer and use it in GitHub Desktop.
Save pelmered/d88744b89a9ca6d1bf592e9f9926e052 to your computer and use it in GitHub Desktop.
<?php
namespace Support\Utilities;
use App\Exceptions\Api\InvalidArgumentApiException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;
class ActionChain
{
public function __construct(
protected mixed $initial = null,
protected object|string|null $contract = null,
protected bool $dbTransaction = true,
) {}
/**
* @throws InvalidArgumentApiException
* @throws Throwable
*/
public function execute(...$actions): mixed
{
$completedActions = collect();
$carry = $this->initial;
$currentAction = null;
try {
if (! $this->dbTransaction) {
DB::beginTransaction();
}
$actions = collect($actions);
$carry = $actions->reduce(function ($carry, $action) use ($completedActions, $currentAction) {
$currentAction = $action;
if (! $action instanceof $this->contract
&& ! in_array($this->contract, class_implements($action), true)
) {
throw new InvalidArgumentApiException(
'Action must be an instance of: '.class_basename($this->contract).
'. Got '.class_basename($action)
);
}
$carry = app($action)->execute($carry);
$completedActions->push($action);
return $carry;
}, initial: $carry);
if (! $this->dbTransaction) {
DB::commit();
}
} catch (Throwable $throwable) {
try {
if (! $this->dbTransaction) {
DB::rollback();
}
} catch (Throwable $throwable) {
Log::error('Failed to roll back database for: '.class_basename($currentAction), $carry);
}
$completedActions->reverse()->reduce(function ($carry, $action) {
try {
if (method_exists($action, 'rollback')) {
$carry = $action->rollback($carry);
}
} catch (Throwable) {
Log::error('Failed to rollback: '.class_basename($action), $carry);
}
return $carry;
}, initial: $carry);
throw $throwable;
}
return $carry;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment