PHP code example of coringawc / filament-action-approvals
1. Go to this page and download the library: Download coringawc/filament-action-approvals library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
coringawc / filament-action-approvals example snippets
return [
// The user model used for approver relationships
'user_model' => App\Models\User::class,
// Registered resolver classes available in the flow builder
'approver_resolvers' => [
\CoringaWc\FilamentActionApprovals\ApproverResolvers\UserResolver::class,
\CoringaWc\FilamentActionApprovals\ApproverResolvers\RoleResolver::class,
\CoringaWc\FilamentActionApprovals\ApproverResolvers\CustomRuleResolver::class,
],
// Multi-tenancy settings
'multi_tenancy' => [
'enabled' => false,
'column' => 'company_id',
'scope_approvers' => true,
],
// SLA warning threshold (0.75 = 75% of SLA time elapsed)
'sla_warning_threshold' => 0.75,
// Date display settings
'date' => [
'display_format' => 'd/m/Y H:i',
'use_since' => true,
],
// Auto-register the SLA processing command to run every minute
'schedule_sla_command' => true,
// Navigation group for the ApprovalFlow resource
'navigation_group' => null,
// Toggle built-in operational actions in package UIs
'actions' => [
'approve' => true,
'reject' => true,
'comment' => false,
'delegate' => false,
],
// Intercept native Filament operations when models declare approval operations
'operations' => [
'intercept' => false,
'modal_callout' => true,
],
// Broadcasting — opt-in per event (all disabled by default)
'broadcasting' => [
'events' => [
'submitted' => false,
'approved' => false,
'rejected' => false,
'cancelled' => false,
'commented' => false,
'delegated' => false,
'step_completed' => false,
'escalated' => false,
],
'queue' => null,
],
// Super admin bypass — see and act on all approvals
'super_admin' => [
'enabled' => false,
'roles' => ['super_admin'],
'user_ids' => [],
],
// Resource customization
'resource' => [
'enabled' => true,
'cluster' => null,
'navigation_sort' => null,
'navigation_icon' => null,
'show_widgets' => true,
],
// ApprovalResource customization
'approvals_resource' => [
'enabled' => true,
'navigation_sort' => null,
'navigation_icon' => null,
],
// Opt-in operational dashboard
'dashboard' => [
'enabled' => false,
'route_path' => 'approvals-dashboard',
'navigation_sort' => null,
'navigation_icon' => null,
],
// Database table prefix (empty = no prefix)
'table_prefix' => '',
];
use CoringaWc\FilamentActionApprovals\FilamentActionApprovalsPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentActionApprovalsPlugin::make()
->flowResource() // Enable the ApprovalFlow resource (default: true)
->approvalResource() // Enable the operational ApprovalResource (default: true)
->dashboard() // Enable the ApprovalsDashboard page (default: false / opt-in)
->widgets() // Enable global panel widgets explicitly when also using the dedicated dashboard
->interceptOperations() // Intercept EditAction/DeleteAction when an approval flow exists
->operationModalCallout(false) // Disable the automatic approval callout in intercepted action modals
->navigationGroup('Workflow'), // Override navigation group
]);
}
use CoringaWc\FilamentActionApprovals\Actions\ListApprovalsAction;
protected function getHeaderActions(): array
{
return [
ListApprovalsAction::make()
->forApprovableType(PurchaseOrderResource::getModel()),
];
}
ListApprovalsAction::make()
->forApprovable(fn (): Model => $this->getOwnerRecord())
ListApprovalsAction::make()
->forApprovable(fn (): Model => $this->getRecord())
->hideWhenNoActionableApprovals(false);
use CoringaWc\FilamentActionApprovals\FilamentActionApprovalsPlugin;
use CoringaWc\FilamentActionApprovals\Widgets\ContextualApprovalsTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
FilamentActionApprovalsPlugin::make()
->configureContextualApprovalsTableUsing(
fn (Table $table, ContextualApprovalsTable $widget): Table => MyApprovalsTable::configure($table),
)
->scopeContextualApprovalsUsing(
fn (Builder $query, ContextualApprovalsTable $widget): Builder => MyApprovalResource::scopeVisibleApprovals($query),
);
use CoringaWc\FilamentActionApprovals\Concerns\HasApprovals;
use CoringaWc\FilamentActionApprovals\Models\Approval;
class PurchaseOrder extends Model
{
use HasApprovals;
// React to approval lifecycle events
public function onApprovalApproved(Approval $approval): void
{
$this->update(['status' => 'approved']);
}
public function onApprovalRejected(Approval $approval): void
{
$this->update(['status' => 'rejected']);
}
}
class PurchaseOrder extends Model
{
use HasApprovals;
/**
* Define domain-specific actions that can be submitted for approval.
* Each key is an action identifier, each value is a human-readable label.
*
* @return array<string, string>
*/
public static function approvableActions(): array
{
return [
'submit' => __('Submit for Processing'),
'cancel' => __('Request Cancellation'),
];
}
}
use CoringaWc\FilamentActionApprovals\Attributes\ApprovableOperation;
use CoringaWc\FilamentActionApprovals\Concerns\HasApprovals;
use CoringaWc\FilamentActionApprovals\Enums\ApprovalOperation;
#[ApprovableOperation(
operation: ApprovalOperation::Update,
actionKey: 'purchase-order.edit',
fields: ['title', 'amount'],
)]
#[ApprovableOperation(
operation: ApprovalOperation::Delete,
actionKey: 'purchase-order.delete',
)]
class PurchaseOrder extends Model
{
use HasApprovals;
}
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
EditAction::make();
DeleteAction::make();
use CoringaWc\FilamentActionApprovals\ApproverResolvers\UserResolver;
use CoringaWc\FilamentActionApprovals\ApproverResolvers\RoleResolver;
use CoringaWc\FilamentActionApprovals\Enums\EscalationAction;
use CoringaWc\FilamentActionApprovals\Enums\StepType;
use CoringaWc\FilamentActionApprovals\Models\ApprovalFlow;
$flow = ApprovalFlow::create([
'name' => 'Purchase Order Approval',
'approvable_type' => PurchaseOrder::class,
'action_key' => 'submit', // Optional: tie this flow to a specific action
'is_active' => true,
]);
// Step 1: Manager approval
$flow->steps()->create([
'name' => 'Manager Review',
'order' => 1,
'type' => StepType::Single,
'approver_resolver' => UserResolver::class,
'approver_config' => ['user_ids' => [1, 2]],
'
use CoringaWc\FilamentActionApprovals\Concerns\HasApprovalsResource;
class PurchaseOrderResource extends Resource
{
use HasApprovalsResource;
// ...
}
// Edit or View Page
class EditPurchaseOrder extends EditRecord
{
protected function getHeaderActions(): array
{
return [
...static::getResource()::getApprovalHeaderActions(),
// Returns: a single ActionGroup labeled "Aprovações"
// containing SubmitForApprovalAction, ApproveAction,
// RejectAction, CommentAction, and DelegateAction
];
}
}
use CoringaWc\FilamentActionApprovals\Actions\ApproveAction;
use CoringaWc\FilamentActionApprovals\Actions\CommentAction;
use CoringaWc\FilamentActionApprovals\Actions\DelegateAction;
use CoringaWc\FilamentActionApprovals\Actions\RejectAction;
use CoringaWc\FilamentActionApprovals\Actions\SubmitForApprovalAction;
class ViewInvoice extends ViewRecord
{
protected function getHeaderActions(): array
{
return [
// Custom domain actions first
AdvanceStatusAction::make(),
CancelAction::make(),
// Only the approval response actions — submitter uses a different flow
ApproveAction::make(),
RejectAction::make(),
CommentAction::make(),
DelegateAction::make(),
];
}
}
use CoringaWc\FilamentActionApprovals\Actions\SubmitForApprovalAction;
use Filament\Support\Icons\Heroicon;
class EditPurchaseOrder extends EditRecord
{
protected function getHeaderActions(): array
{
return [
// Dedicated button for "submit" action — skips the action selector modal
SubmitForApprovalAction::make('submitPO')
->actionKey('submit')
->label(__('Submit for Approval'))
->icon(Heroicon::OutlinedPaperAirplane),
// Dedicated button for "cancel" action
SubmitForApprovalAction::make('cancelPO')
->actionKey('cancel')
->label(__('Request Cancellation'))
->icon(Heroicon::OutlinedXMark)
->color('danger'),
// Approval response actions
ApproveAction::make(),
RejectAction::make(),
CommentAction::make(),
DelegateAction::make(),
];
}
}
use CoringaWc\FilamentActionApprovals\RelationManagers\ApprovalsRelationManager;
class PurchaseOrderResource extends Resource
{
public static function getRelations(): array
{
return [
ApprovalsRelationManager::class,
];
}
}
use CoringaWc\FilamentActionApprovals\Columns\ApprovalStatusColumn;
class PurchaseOrderResource extends Resource
{
public static function table(Table $table): Table
{
return $table->columns([
TextColumn::make('title'),
ApprovalStatusColumn::make(), // Badge: Pending, Approved, Rejected, Cancelled
]);
}
}
use CoringaWc\FilamentActionApprovals\Infolists\ApprovalStatusSection;
class ViewPurchaseOrder extends ViewRecord
{
public function infolist(Infolist $infolist): Infolist
{
return $infolist->schema([
// ... your other infolist sections ...
ApprovalStatusSection::make(),
]);
}
}
use CoringaWc\FilamentActionApprovals\Services\ApprovalEngine;
$engine = app(ApprovalEngine::class);
// Submit for approval
$approval = $engine->submit($purchaseOrder, $flow, auth()->id());
// Or via the model
$approval = $purchaseOrder->submitForApproval($flow);
// Approve a step
$stepInstance = $approval->currentStepInstance();
$engine->approve($stepInstance, auth()->id(), 'Approved — budget ok');
// Reject
$engine->reject($stepInstance, auth()->id(), 'Budget exceeded');
// Add a comment
$engine->comment($approval, auth()->id(), 'Please provide receipts');
// Delegate to another user
$engine->delegate($stepInstance, auth()->id(), $delegateUserId, 'On vacation');
// Cancel the approval
$engine->cancel($approval);
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasName;
class User extends Authenticatable implements FilamentUser, HasName
{
public function getFilamentName(): string
{
return "{$this->first_name} {$this->last_name}";
}
}
use CoringaWc\FilamentActionApprovals\Contracts\ApproverResolver;
class HierarchyResolver implements ApproverResolver
{
public function resolve(array $config, Model $approvable): array
{
return [$approvable->user->manager_id];
}
public static function label(): string
{
return 'Direct Manager';
}
public static function configSchema(): array
{
return []; // Filament form components for the flow builder
}
public static function isAvailable(?string $modelClass = null): bool
{
return true; // Available for all models
}
}
class Expense extends Model
{
use HasApprovals {
canSubmitForApproval as protected canSubmitForApprovalThroughFlow;
}
// By default, approved and cancelled approvals cannot be resubmitted.
// Override when your domain should also block or allow other outcomes.
public function allowsApprovalResubmission(): bool
{
$latest = $this->latestApproval();
return ! $latest || $latest->status === ApprovalStatus::Rejected;
}
// Add project-specific submit rules on top of the default flow-approver policy
public function canSubmitForApproval(?string $actionKey = null, int|string|null $userId = null): bool
{
return $this->user_id === ($userId ?? auth()->id())
|| $this->canSubmitForApprovalThroughFlow($actionKey, $userId);
}
}
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Contracts\HasLabel;
enum PurchaseOrderAction: string implements HasLabel, HasColor, HasIcon
{
case Submit = 'submit';
case Cancel = 'cancel';
public function getLabel(): string
{
return match ($this) {
self::Submit => __('Submit for Processing'),
self::Cancel => __('Request Cancellation'),
};
}
public function getColor(): string
{
return match ($this) {
self::Submit => 'success',
self::Cancel => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Submit => 'heroicon-o-paper-airplane',
self::Cancel => 'heroicon-o-x-mark',
};
}
}
use CoringaWc\FilamentActionApprovals\Attributes\ApprovableActions;
#[ApprovableActions(PurchaseOrderAction::class)]
class PurchaseOrder extends Model
{
use HasApprovals;
}
use CoringaWc\FilamentActionApprovals\Support\ApprovableActionLabel;
ApprovableActionLabel::iconFor($model, 'submit'); // 'heroicon-o-paper-airplane'
ApprovableActionLabel::colorFor($model, 'submit'); // 'success'
// config/filament-action-approvals.php
'resource' => [
'enabled' => true,
'cluster' => \App\Filament\Admin\Clusters\Settings::class,
'navigation_sort' => 5,
'navigation_icon' => 'heroicon-o-cog',
'show_widgets' => true, // Show analytics widgets on the list page
],
namespace App\Filament\Admin\Resources;
use CoringaWc\FilamentAcl\Attributes\PermissionSubject;
use CoringaWc\FilamentAcl\Resources\Concerns\HasResourcePermissions;
use CoringaWc\FilamentActionApprovals\Resources\ApprovalFlows\ApprovalFlowResource as BaseResource;
#[PermissionSubject('ApprovalFlow')]
class ApprovalFlowResource extends BaseResource
{
use HasResourcePermissions;
}