moffhub/maker-checker
Feature-complete maker-checker (four-eyes) approvals for Laravel. Add a trait to intercept model create/update/delete, or use the API for complex workflows: multi-level/role & user approvals, conditional rules, delegation, bulk ops, reminders/escalation, audit trail & export.
Installation:
composer require moffhub/maker-checker
php artisan vendor:publish --tag=maker-checker-migrations
php artisan migrate
php artisan vendor:publish --tag=maker-checker-config
Implement User Contract:
Add MakerCheckerUserContract to your User model:
use Moffhub\MakerChecker\Contracts\MakerCheckerUserContract;
class User extends Authenticatable implements MakerCheckerUserContract
{
public function hasMakerCheckerPermission(string $permission): bool { ... }
public function getMakerCheckerTeamId(): ?int { ... }
public function getMakerCheckerRole(): ?string { ... }
public function getMakerCheckerEmail(): ?string { ... }
}
First Use Case:
Add the RequiresApproval trait to a model (e.g., Post):
use Moffhub\MakerChecker\Traits\RequiresApproval;
class Post extends Model
{
use RequiresApproval;
protected static array $approvalRequirements = ['create' => ['editor' => 1]];
}
Now, creating a Post will trigger an approval workflow.
Auto-Intercept Workflow:
RequiresApproval trait to models.$approvalRequirements (e.g., ['create' => ['admin' => 2]]).createWithoutApproval() or withoutApprovalDo() for bypasses.Facade-Based Workflow:
MakerChecker::create(), update(), or delete() for manual requests.$request = MakerChecker::create(Post::class, ['title' => 'Draft'], 'Draft post');
Request Builder Pattern:
$request = MakerChecker::request()
->toCreate(Post::class, ['title' => 'Post'])
->withApprovals(['editor' => 1])
->beforeApproval(fn($r) => Log::info('Pre-approval'))
->save();
/maker-checker/requests) for frontend approval flows.MakerCheckerRequestApproved or MakerCheckerRequestRejected events.ExecutableRequest for non-CRUD operations (e.g., fund transfers).Race Conditions:
pessimistic_locking in config to prevent double-approvals.'locking' => [
'enabled' => true,
'timeout' => 30, // seconds
],
User-Specific Approvals:
validateExistence: false).try {
$request->requiringUsersToApprove(['nonexistent@example.com']);
} catch (RequestCouldNotBeInitiated $e) {
// Handle missing user
}
Approval Expiry:
expiry_minutes in config to auto-expire pending requests:
'request_expiry' => [
'enabled' => true,
'minutes' => 1440, // 24 hours
],
/maker-checker/audit/export.$request->status (e.g., pending, approved, rejected).$request->getPendingRoles() or $request->getPendingUsers().Custom Rules Engine:
MakerChecker::getApprovalRequirements() to dynamically set rules.MakerChecker::extend(function ($request) {
if ($request->payload['amount'] > 50000) {
return ['finance' => 2];
}
return ['manager' => 1];
});
Notifications:
MakerCheckerNotification to customize email templates or add Slack alerts.Delegation:
MakerChecker::delegateApproval($request, $delegateUser, $expiryMinutes) for temporary approval transfers.maker_checker_config table.getMakerCheckerTeamId() in the User contract to scope requests by team.How can I help you explore Laravel packages today?