Download the PHP package moffhub/maker-checker without Composer
On this page you can find all versions of the php package moffhub/maker-checker. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download moffhub/maker-checker
More information about moffhub/maker-checker
Files in moffhub/maker-checker
Package maker-checker
Short Description Enterprise-grade maker-checker (four-eyes) approval workflow for Laravel. Multi-role approvals, conditional rules engine, delegation, audit trail, bulk actions, and auto-intercept via Eloquent events.
License MIT
Homepage https://github.com/moffhub/maker-checker
Informations about the package maker-checker
Maker-Checker for Laravel
The most feature-complete maker-checker (four-eyes principle) approval workflow package for Laravel. Add multi-level approval requirements to any Eloquent model with a single trait, or use the full-featured API for complex enterprise workflows.
Unlike simpler approval packages, this supports multi-role approvals, a conditional rules engine, approval delegation, bulk operations, audit trail with export, reminders & escalation, and auto-intercept via Eloquent model events -- all out of the box.
Why This Package?
| Feature | moffhub/maker-checker | Others |
|---|---|---|
| Auto-intercept via trait | ✅ | Some |
| Multi-role approvals (2 admins + 1 manager) | ✅ | Rare |
| User-specific approvals | ✅ | ❌ |
| Conditional rules engine (if amount > 50K...) | ✅ | ❌ |
| Database-driven config (change rules at runtime) | ✅ | ❌ |
| Execute arbitrary actions (not just CRUD) | ✅ | ❌ |
| Approval delegation with expiry | ✅ | ❌ |
| Bulk approve endpoint | ✅ | ❌ |
| Reminders & escalation | ✅ | ❌ |
| Audit trail + CSV/JSON export | ✅ | Rare |
| Race condition safe (pessimistic locking) | ✅ | ❌ |
| REST API included | ✅ | ❌ |
| 360+ tests | ✅ | Varies |
Features
- Auto-intercept - Add
RequiresApprovaltrait to any model; create/update/delete are intercepted automatically - Multi-role approvals - Require approvals from specific roles (e.g., 2 admins + 1 manager)
- User-specific approvals - Require specific people to approve by email or ID
- Conditional rules engine - Different approval rules based on payload (e.g., amount > 50,000 needs extra approval)
- CRUD + Execute - Built-in support for Create, Update, Delete, and custom Execute operations
- Flexible configuration - Configure via file, database, model interfaces, or runtime API
- Multi-tenancy support - Team/company scoping for requests
- API ready - RESTful API endpoints for managing requests, configs, delegations, and audits
- Bulk operations - Approve multiple requests in one call
- Delegation - Delegate approval authority to another user with optional expiry
- Hooks & callbacks - Execute custom logic before/after approval or rejection
- Reminders & escalation - Auto-remind approvers; escalate after configurable delay
- Request expiration - Auto-expire pending requests after a configurable time
- Audit trail - Full audit log with CSV/JSON export endpoint
- Notifications - Built-in email/database notifications with sequential approval support
- Race condition safe - Pessimistic locking prevents double-approval bugs
Installation
Install the package via Composer:
Publish and run the migrations:
Optionally publish the config file:
Quick Start
Option A: Automatic Model Event Interception (Recommended)
The simplest way to add maker-checker to your models is using the RequiresApproval trait. This automatically intercepts create, update, and delete operations:
Now when you try to create or delete a Post, the operation returns false and a pending approval request is created:
Option B: Convenience Methods (Simple API)
Use the MakerChecker facade with convenience methods that auto-inject the authenticated user:
Approve, reject, or cancel requests (also auto-injects auth user):
You can also call these methods directly on the request model:
Option C: Request Builder (Full Control)
For advanced usage with hooks and custom configuration:
1. Implement the User Contract
Add the MakerCheckerUserContract interface to your User model:
2. Create a Pending Request
Use the MakerChecker facade to create approval requests:
3. Approve or Reject
Request Types
Create
Update
Delete
Execute (Custom Actions)
For complex operations, create an executable class:
Then create the request:
Multi-Role Approvals
Require approvals from multiple roles:
Check approval status:
User-Specific Approvals
In addition to role-based approvals, you can require specific users to approve a request. This is useful when you need approval from a particular person regardless of their role.
Requiring Specific Users
Specify users by email or ID:
Combining Roles and Users
Require both role-based and user-specific approvals:
User Validation
By default, the package validates that all specified users exist in the system before creating the request:
Checking Pending Users
Approval Flow
When a user-specific approval is required, only the specified users can approve:
Configuration
Model-Based Configuration
Implement MakerCheckerConfigurable on your models:
File-Based Configuration
Configure in config/maker-checker.php:
Database-Driven Configuration
Enable the database driver for dynamic configuration:
Manage configs via API or programmatically:
Configuration API
Create configuration via API:
Response:
Update configuration:
UI Mockup
A sample UI mockup for the configuration management interface is available at docs/ui-mockup.html. Open it in a browser to see how the frontend could interact with these APIs.
API Endpoints
The package provides RESTful API endpoints (prefix configurable):
Requests
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/maker-checker/requests |
List all requests |
| GET | /api/maker-checker/requests/{id} |
Get request details |
| GET | /api/maker-checker/requests/{id}/approvals |
Get approval status |
| POST | /api/maker-checker/requests/{id}/approve |
Approve a request |
| POST | /api/maker-checker/requests/{id}/reject |
Reject a request |
| POST | /api/maker-checker/requests/{id}/cancel |
Cancel own request |
| GET | /api/maker-checker/requests/statistics |
Get request statistics |
| GET | /api/maker-checker/requests/statuses |
List available statuses |
Query Parameters
Configs (database driver)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/maker-checker/configs |
List all configs |
| POST | /api/maker-checker/configs |
Create config |
| GET | /api/maker-checker/configs/{id} |
Get config |
| PUT | /api/maker-checker/configs/{id} |
Update config |
| DELETE | /api/maker-checker/configs/{id} |
Delete config |
| POST | /api/maker-checker/configs/{id}/enable |
Enable config |
| POST | /api/maker-checker/configs/{id}/disable |
Disable config |
| GET | /api/maker-checker/configs/export |
Export all configs |
| POST | /api/maker-checker/configs/import |
Import configs |
Route Configuration
To customize routes, publish them:
Request Statuses
| Status | Description |
|---|---|
pending |
Awaiting first approval |
partially_approved |
Has some approvals but not all required |
approved |
Fully approved and executed |
rejected |
Rejected by a checker |
cancelled |
Cancelled by the maker |
expired |
Expired after timeout |
failed |
Execution failed |
Hooks
Add hooks to the request builder:
Automatic Model Interception
The RequiresApproval trait provides automatic interception of Eloquent model events. When added to a model, create/update/delete operations return false and create a pending approval request instead of executing immediately.
Basic Usage
Configuration via Properties
Bypassing Approval
Handling Interception
When an operation is intercepted, the model's save() or delete() returns false. Check if it was intercepted and get the pending request:
Exception Mode (Optional)
If you prefer exception-based handling:
Checking Pending Approvals
Setting the Maker
By default, the trait uses auth()->user() as the maker. You can override this:
Visibility Scoping
Query requests visible to a user:
Expiring Requests
Enable automatic expiration:
Run the expiration command (add to scheduler):
Notifications
The package can automatically notify approvers when a new request is pending, and notify makers when their request is approved or rejected.
Enabling Notifications
Finding Approvers by Role
The package uses an ApproverResolver to find users who can approve requests. The default resolver queries users by role attribute:
For more complex scenarios (Spatie permissions, team-based roles, etc.), implement your own resolver:
Sequential Notifications
By default, all required roles are notified at once. Enable sequential mode to notify roles one at a time:
In sequential mode:
- First role is notified when request is created
- After that role approves, next role is notified
- Use
MakerChecker::notifyNextApprovers($request)to manually trigger next notification
Custom Notification Classes
Override the default notifications with your own:
Your custom notification should accept a MakerCheckerRequest in its constructor:
Manual Notifications
Trigger notifications manually when needed:
Lifecycle Callbacks
Register callbacks to execute at various points in the request lifecycle.
Config-Based Callbacks
Define callbacks in the config file:
Callback classes should implement RequestCallback or have a handle method:
Programmatic Callbacks
Register callbacks at runtime:
Available Hooks
| Hook | When Executed |
|---|---|
on_initiated |
After a new request is created |
before_approval |
Before approval processing (per-request hooks only) |
after_approval |
After request is fully approved and executed |
before_rejection |
Before rejection processing (per-request hooks only) |
after_rejection |
After request is rejected |
on_failure |
When request execution fails |
Rate Limiting
All package API routes are rate-limited by default. Configure the limit in your config:
Rate limiting is keyed by the authenticated user's ID or by IP address for unauthenticated requests. Set to 0 or null to disable rate limiting.
The rate limiter is registered under the name maker-checker, so you can reference it in your own routes if needed:
Audit Logging
The package automatically logs all approval actions (approve, reject, cancel, fail) with full context.
Configuration
Drivers
database(default): Writes audit entries to themaker_checker_audit_logstable. Best for querying and reporting.log: Writes audit entries to a Laravel log channel. Best for high-throughput systems where you want to offload to external log aggregation (ELK, Datadog, etc.).
Logged Data
Each audit entry includes:
request_id- The maker-checker request IDactor_type/actor_id- Who performed the action (morph relationship)action- The action performed (approved, rejected, cancelled, partially_approved, failed)previous_status- The request status before the actionnew_status- The request status after the actionip_address- The IP address of the actormetadata- Additional context (e.g., exception messages for failures)
Conditional Configuration
When using the database config driver, you can define conditions that determine which configuration applies based on the request payload. This allows different approval requirements for different scenarios.
Supported Operators
| Operator | Description | Example Value |
|---|---|---|
= |
Equal to | 50000 |
!= |
Not equal to | "draft" |
> |
Greater than | 10000 |
>= |
Greater than or equal | 5000 |
< |
Less than | 100 |
<= |
Less than or equal | 50 |
in |
Value in array | ["US", "EU", "UK"] |
not_in |
Value not in array | ["blocked", "suspended"] |
contains |
String contains | "urgent" |
starts_with |
String starts with | "VIP-" |
ends_with |
String ends with | "@company.com" |
is_null |
Value is null | (no value needed) |
is_not_null |
Value is not null | (no value needed) |
between |
Value between two numbers | [1000, 50000] |
regex |
Matches regex pattern | "^[A-Z]{3}\\d{4}$" |
Condition Examples
Simple condition - high-value transfers require extra approval:
Multiple conditions (AND) - large international transfers:
Any condition (OR) - sensitive operations:
Nested groups - complex business rules:
Using between for range checks:
Testing Conditions
Use the test endpoint to verify which config matches a payload:
Team Scoping
The package supports multi-tenant setups where requests and configurations are scoped to teams/companies.
Setup
-
Implement the User Contract with team support:
- Pass team ID when creating requests:
Or use the builder methods:
-
Enable team scoping for notifications:
- Create team-scoped configs (database driver):
Visibility
Requests are automatically filtered by team when using scopeVisibleTo:
Users with the view_any_permission bypass team filtering and see all requests.
Custom ApproverResolver
The default ApproverResolver finds approvers by querying a role attribute on the user model. For more complex scenarios, implement your own resolver.
Example: Spatie Permissions Integration
Register it in your AppServiceProvider:
Custom ExecutableRequest
Create custom executable actions for complex operations that need approval:
Use it:
Testing
Run the full check suite:
Configuration Reference
| Option | Default | Description |
|---|---|---|
ensure_requests_are_unique |
true |
Prevent duplicate pending requests |
request_expiration_in_minutes |
null |
Auto-expire after N minutes |
default_approval_count |
1 |
Default approvals when not specified |
table_name |
maker_checker_requests |
Requests table name |
config_table_name |
maker_checker_configs |
Configs table name |
delete_on_completion |
true |
Delete requests after execution |
soft_delete_on_completion |
false |
Soft delete instead |
view_any_permission |
maker-checker.view-any |
Permission to view all requests |
config_driver |
file |
file or database |
cache_config |
true |
Cache database configs |
config_cache_ttl |
3600 |
Cache TTL in seconds |
routes.rate_limit |
60 |
Rate limit per minute (0 to disable) |
notifications.enabled |
false |
Enable automatic notifications |
notifications.channels |
['mail', 'database'] |
Notification delivery channels |
notifications.notify_maker |
true |
Notify maker on approval/rejection |
notifications.sequential |
false |
Notify roles one at a time |
notifications.role_attribute |
role |
User model attribute for role |
audit.enabled |
true |
Enable audit logging |
audit.driver |
database |
Audit storage: database or log |
audit.table_name |
maker_checker_audit_logs |
Audit log table name |
audit.log_channel |
null |
Laravel log channel for log driver |
Troubleshooting
"No authenticated user found" error
This error occurs when using the convenience methods (MakerChecker::create(), MakerChecker::approve()) without an authenticated user. Solutions:
- Ensure the user is authenticated before calling these methods
- Use the request builder with
->madeBy($user)to explicitly pass a user - For console commands or jobs, use the builder pattern instead of convenience methods
"Request checker cannot be the same as the maker"
By default, the same user cannot both create and approve a request. To allow this for specific users (e.g., admins in development):
"The request model passed must be an instance of..."
This happens when:
- The
request_modelconfig points to a class that doesn't extendMakerCheckerRequest - The config hasn't been published or is outdated
Fix: Ensure your custom model extends MakerCheckerRequest:
Duplicate request exceptions
When ensure_requests_are_unique is true, creating a request with the same payload as an existing pending request throws a DuplicateRequestException. Solutions:
- Use
uniqueBy()on the builder to specify which fields determine uniqueness - Set
ensure_requests_are_uniquetofalseif duplicates are acceptable - Approve or cancel existing pending requests first
Notifications not sending
- Ensure notifications are enabled:
'notifications.enabled' => true - Verify
user_modelis set orauth.providers.users.modelis configured - Check that your user model uses Laravel's
Notifiabletrait - Verify the
ApproverResolverreturns users for the required roles - Check your notification channels configuration
Config validation errors on boot
The package validates configuration when the application boots (except during tests). Common issues:
default_approval_countmust be >= 1config_drivermust befileordatabaserequest_modelmust be a class extendingMakerCheckerRequestwhitelisted_models.makerandwhitelisted_models.checkermust be arrays
Database config not applying
When using the database config driver:
- Ensure the config driver is set:
'config_driver' => 'database' - Run migrations:
php artisan migrate - Check configs are
is_active: true - Clear config cache if changes aren't reflected:
php artisan cache:clear - Verify the
team_idmatches (team-specific configs only apply to that team)
Rate limiting too aggressive
Adjust the rate limit per minute:
Or disable rate limiting entirely:
Known Limitations
-
No built-in queue support for fulfillment: When a request is approved, the underlying operation (create/update/delete/execute) runs synchronously within the approval request. For long-running operations, implement your own queue dispatch inside an
ExecutableRequest. -
JSON payload comparison: Duplicate request checking uses JSON field comparisons (
payload->field), which may behave differently across database engines (MySQL vs PostgreSQL vs SQLite). -
Single approval per user: A user can only approve a request once. They cannot approve under multiple roles for the same request.
-
No partial rollback: If fulfillment fails after approval, the request is marked as
failedbut any partial side effects from hooks (beforeApproval) are not rolled back. -
Config driver is global: You cannot use different config drivers for different models. The
config_driversetting applies to all models. -
Morph map dependency: The package uses polymorphic relationships for maker/checker/subject. If you change your morph map after requests are created, existing requests may break.
- No built-in approval deadlines: While requests can expire, there is no built-in deadline per approval step in a multi-role chain. All roles have the same expiration window.
Performance
For high-traffic production deployments, see docs/PERFORMANCE.md for:
- Recommended database indexes
- Query optimization tips
- Config caching recommendations
- Approval chain resolution at scale
License
MIT License. See LICENSE for details.
All versions of maker-checker with dependencies
illuminate/support Version ^12.0 || ^13.0
sourcetoad/enhanced-resources Version ^7.3