menma/approval-binary 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

menma/approval-binary

最新稳定版本:V1.0.0

Composer 安装命令:

composer require menma/approval-binary

包简介

Binary approval engine for Laravel

README 文档

README

A Laravel plugin for binary bitmask-based approval workflows. Define multi-level approval chains where each step is represented as a bit position, enabling efficient state tracking, flexible workflow automation, and high-performance querying.

Requirements

  • PHP 8.1+
  • Laravel 10.x / 11.x / 12.x

Installation

1. Install via Composer

composer require menma/approval-binary

2. Publish

2.1 migrations

php artisan vendor:publish --tag=approval-migrations

2.2 config

php artisan vendor:publish --tag=approval-config

2.3 lang

php artisan vendor:publish --tag=approval-lang

3. Run Migrations

php artisan migrate

Core Concepts

Binary Bitmask System

Each approval step is assigned a unique bit position. The target integer stores the required set of approvals (mask), and step integer tracks the completed approvals.

Component Step Bit Position Mask Value
HR 0 Bit 0 1 << 0 = 1
Manager 1 Bit 1 1 << 1 = 2
Director 2 Bit 2 1 << 2 = 4
  • Target = 7 (binary 111) → HR + Manager + Director required.
  • Target = 3 (binary 011) → HR + Manager required.

Architecture

The plugin is architected around specialized services for robust workflow management:

  • EventStoreService: Handles the creation, retrieval, and initialization of ApprovalEvents. Determines the correct flow and assigns contributors.
  • EventActionService: Orchestrates state changes (Approve, Reject, Cancel). Handles complex logic like Parallel user detection and Sequential order enforcement.
  • ConditionResolverService: Evaluates dynamic conditions (e.g., "Amount > 1000") to filter required steps at runtime (Dynamic Masking).

Usage

1. Prepare Your Model

Extend ApprovalAbstract. This provides the necessary relationships and default implementations. You can override getApprovalConditions to enable Dynamic Masking.

use Menma\Approval\Abstracts\ApprovalAbstract;

class PurchaseOrder extends ApprovalAbstract
{
    // Return users who can approve this specific record (if applicable)
    public function getApproverIds(): array
    {
        return $this->user_id ? [$this->position->user_id] : [];
    }

    // Expose data for Conditional Logic
    public function getApprovalConditions(): array
    {
        return [
            'amount' => $this->amount,
            'dept' => $this->department,
        ];
    }

    // Lifecycle Hooks
    protected function onApprove(ApprovalEvent $event): void { /* ... */ }
    protected function onReject(ApprovalEvent $event): void { /* ... */ }
    protected function onCancel(ApprovalEvent $event): void { /* ... */ }
    protected function onRollback(ApprovalEvent $event): void { /* ... */ }
}

2. Workflow Scenarios

This plugin supports complex enterprise workflows. Here are the core scenarios:

Scenario 1: Single User Approval

A simple one-step workflow.

Scenario 2: Parallel Multi-User (OR)

Multiple approvers (e.g., HR, Finance) can approve in any order.

  • Configuration: Approval Type = PARALLEL (0)
  • EventActionService intelligently detects if the current user is a contributor to any pending step.

Scenario 3: Sequential Multi-User

Strict ordering. Step 2 cannot be approved until Step 1 is complete.

  • Configuration: Approval Type = SEQUENTIAL (1)

Scenario 4: Shared Step (OR Logic)

A single step (e.g., "Manager Approval") assigned to multiple users. Any one of them can approve to complete the step.

  • Component Type: OR (1)

Scenario 5: Shared Step (AND Logic)

A single step assigned to a committee. All assigned users must approve for the step to complete.

  • Component Type: AND (0)

Scenario 6: Conditional Approval (Dynamic Masking)

Dynamically skip steps based on model data. Example: "Director approval is only needed if Amount > 1000".

  1. Define Condition:
    ApprovalCondition::create([
        'approval_id' => $approval->id,
        'field' => 'amount',
        'operator' => '<=',
        'threshold' => '1000',
        'max_step' => 0 // If Amount <= 1000, limit workflow to Step 0 (Manager only)
    ]);
  2. Runtime:
    • If PO Amount = 500: Target Mask = 1 (Manager). Event approved after Manager action.
    • If PO Amount = 1500: Target Mask = 3 (Manager + Director). Both required.

Configuration (Database Seeding)

Since this plugin operates without a UI, approval workflows are defined programmatically via database records. This setup links your Models to specific Approval Flows and defines the logic (steps) and actors (contributors).

Entity Relationships

  • ApprovalDictionary: Registry of models (e.g., "Purchase Order").
  • ApprovalFlow: Container for the workflow.
  • ApprovalFlowComponent: The bridge connecting a Model (Dictionary) to a Flow.
  • ApprovalGroup: A collection of users (e.g., "Board Committee").

Seeder Example

use Menma\Approval\Models\ApprovalDictionary;
use Menma\Approval\Models\ApprovalFlow;
use Menma\Approval\Models\ApprovalFlowComponent;
use Menma\Approval\Models\Approval;
use Menma\Approval\Models\ApprovalComponent;
use Menma\Approval\Models\ApprovalContributor;
use Menma\Approval\Models\ApprovalGroup;
use Menma\Approval\Models\ApprovalGroupContributor;
use Menma\Approval\Enums\ApprovalTypeEnum;
use Menma\Approval\Enums\ContributorTypeEnum;

// 1. Register the Model (Dictionary)
$dictionary = ApprovalDictionary::create([
    'key' => 'App\Models\PurchaseOrder',
    'name' => 'Purchase Order',
]);

// 2. Create the Flow
$flow = ApprovalFlow::create([
    'name' => 'Standard PO Workflow',
]);

// 3. Link Model to Flow
// The 'key' MUST match your Model's morph class (getMorphClass())
ApprovalFlowComponent::create([
    'approval_flow_id' => $flow->id,
    'approval_dictionary_id' => $dictionary->id,
    'key' => 'App\Models\PurchaseOrder',
]);

// 4. Define Logic Container
$approval = Approval::create([
    'approval_flow_id' => $flow->id,
    'name' => 'PO Logic v1',
    'type' => ApprovalTypeEnum::SEQUENTIAL, // Enforces strict sequential order
]);

// 5. Create Steps
// Step 0: Manager (Bit 0)
$stepManager = ApprovalComponent::create([
    'approval_id' => $approval->id,
    'name' => 'Manager Approval',
    'step' => 0,
    'type' => ContributorTypeEnum::OR,
]);

// Step 1: Board (Bit 1)
$stepBoard = ApprovalComponent::create([
    'approval_id' => $approval->id,
    'name' => 'Board Approval',
    'step' => 1,
    'type' => ContributorTypeEnum::AND, // All members must approve
]);

// 6. Assign Contributors

// 6a. Direct User (Manager)
ApprovalContributor::create([
    'approval_component_id' => $stepManager->id,
    'approvable_type' => null, // Direct User
    'approvable_id' => 1,      // User ID
]);

// 6b. Group (Board)
$boardGroup = ApprovalGroup::create(['name' => 'Board Members']);
ApprovalGroupContributor::create(['approval_group_id' => $boardGroup->id, 'user_id' => 2]);
ApprovalGroupContributor::create(['approval_group_id' => $boardGroup->id, 'user_id' => 3]);

// Assign Group to Step
ApprovalContributor::create([
    'approval_component_id' => $stepBoard->id,
    'approvable_type' => ApprovalGroup::class,
    'approvable_id' => $boardGroup->id,
]);

API Reference

Triggering Actions

// Initialize
$foo->initEvent($user);

// Approve (Smart detection of step)
$foo->approve($user);

// Reject
$foo->reject($user);

// Cancel
$foo->cancel($user);

// Rollback
$foo->rollback($user);

// Force Approve (Skip Smart Detection)
$foo->force($user, 5, ApprovalStatusEnum::DRAFT->value);

// Check Status
if ($foo->isApproved()) { ... }

Manual Service Usage

For custom implementations avoiding the Model trait:

$service = app(EventActionService::class);
$service->approve($model, $user);

License

GNU AGPLv3

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 6
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: AGPL-3.0-or-later
  • 更新时间: 2026-02-17

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固