PHPackages                             mhqady/flowra - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mhqady/flowra

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mhqady/flowra
=============

Flowra is a flexible, database-driven workflow and state machine engine for Laravel. It supports workflows, typed states, transitions, guards, actions, scopes, and dynamic workflow loading, enabling complex business processes to evolve at runtime without redeploying code.

v0.1.6(4mo ago)2581MITPHPPHP ^8.4CI passing

Since Sep 6Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/mhQady/flowra)[ Packagist](https://packagist.org/packages/mhqady/flowra)[ RSS](/packages/mhqady-flowra/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (2)Versions (10)Used By (0)

Flowra
======

[](#flowra)

Flowra is a database-driven workflow engine for Laravel applications. It lets you describe business processes as workflows composed of **typed states**, **transitions**, **guards**, **actions**, and **state groups**—all persisted in your database so processes can evolve without redeploying code.

The package provides artisan generators, migration stubs, rich Eloquent traits, and DTO helpers that make it simple to:

- attach workflows to any Eloquent model,
- track the current status and historical registry of each workflow run,
- nest state groups,
- gate transitions with guards and execute actions after state changes, and
- query models by workflow state (including grouped states) using fluent scopes.

---

📦 Installation
--------------

[](#-installation)

```
composer require mhqady/flowra
```

Register the service provider if you are not using package auto-discovery, then publish the assets as shown below. Add `HasWorkflow` to any model that needs a workflow and use the stubs to generate your first workflow pair.

---

✨ Key Concepts
--------------

[](#-key-concepts)

### Workflows &amp; States

[](#workflows--states)

Every workflow extends `Flowra\Concretes\BaseWorkflow` and defines two classes:

- `YourWorkflow` – contains transition definitions.
- `YourWorkflowStates` – an enum describing the workflow states. Optional `groups()` declarations describe grouped states (e.g., a `draft` group that owns all of the draft states).

```
enum MainWorkflowStates: string
{
    use Flowra\Enums\BaseEnum;

    case INIT = 'init';
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    // ...

    public static function groups(): array
    {
        return [
            \Flowra\DTOs\StateGroup::make(self::DRAFT)->children(
                self::INIT,
                // ...
            ),
        ];
    }
}
```

State groups are surfaced everywhere—switching, querying, and eager loading—so your workflow knows when it is in a grouped state and scopes can refer to either the parent group or any of its child states.

### Transitions

[](#transitions)

Use the `Transition` DTO to define transitions, guards, and actions:

```
class MainWorkflow extends BaseWorkflow
{
    public static function transitionsSchema(): array
    {
        return [
            Transition::make('filling_app_data', MainWorkflowStates::INIT, MainWorkflowStates::DRAFT)
                ->guard(CheckPermissions::class)
                ->action(fn ($transition) => event(new WorkflowStarted($transition))),
        ];
    }
}
```

Transitions are cached and exposed as magic properties (`$model->mainWorkflow->fillingAppData`) so you can call `->apply()` on them fluently.

### Guards &amp; Actions

[](#guards--actions)

- **Guards** (`Flowra\Contracts\GuardContract`) determine if a transition may proceed.
- **Actions** (`Flowra\Contracts\ActionContract`) run after persistence.

Both can be closures, container-resolved class names, or concrete instances.

### Persistence

[](#persistence)

Flowra publishes migrations for two tables:

- `statuses` – holds the current status per workflow &amp; owner, including hierarchy data, type, and path.
- `statuses_registry` – an append-only log of every transition.

The included `Status` and `Registry` models provide accessors; workflows are kept in sync via the `HasStates`, `HasStateGroups`, and `HasTransitions` traits in `BaseWorkflow`.

### Model Integration

[](#model-integration)

Add `Flowra\Concretes\HasWorkflow` to your Eloquent model and define the workflows it uses:

```
class Context extends Model
{
    use HasWorkflow;

    protected static array $workflows = [
        \App\Workflows\MainWorkflow\MainWorkflow::class,
    ];
}
```

`HasWorkflow` wires up:

- attribute casts (via `WorkflowAware`) so `$context->mainWorkflow` returns the live workflow instance,
- relations (`mainWorkflowStatus`, `mainWorkflowRegistry`, `statuses`, `registry`), and
- query scopes/macros (`whereMainWorkflowCurrentStatus`, `withWhereMainWorkflowCurrentStatus`, etc.) that understand grouped states.

🧰 Tooling
---------

[](#-tooling)

Flowra ships several artisan commands once registered through `FlowraServiceProvider`:

- `flowra:make-workflow` – scaffolds a workflow class and its states enum (with the `groups()` template).
- `flowra:make-guard`, `flowra:make-action` – generate guard/action classes.
- `flowra:list-workflow` – inspect registered workflows at runtime.
- `flowra:export-workflow` – export any workflow to a Mermaid or PlantUML diagram (print to the console or write to disk).
- `flowra:import-workflow` – convert a Mermaid/PlantUML diagram back into enum cases, transition snippets, and ready-to-use workflow/state files.

```
# print a Mermaid diagram
php artisan flowra:export-workflow "Flowra\Flows\MainFlow\MainWorkflow"
# ⇢ writes to storage/app/flowra/workflows/Flowra-Flows-MainFlow-MainWorkflow.mmd

# or pass just the class name (resolved from config('flowra.workflows_namespace'))
php artisan flowra:export-workflow "MainWorkflow"
# ⇢ resolves to App\Workflows\MainWorkflow\MainWorkflow by default

# save a PlantUML diagram to a file
php artisan flowra:export-workflow "Flowra\Flows\MainFlow\MainWorkflow" \
    --format=plantuml --output=storage/app/diagrams/main-workflow.puml

# convert a Mermaid file into PHP snippets + workflow/state classes
php artisan flowra:import-workflow "Flowra\Flows\MainFlow\MainWorkflow" \
    --path=storage/app/flowra/workflows/Flowra-Flows-MainFlow-MainWorkflow.mmd \
    --force  # overwrite the generated files if they already exist

# or paste a diagram directly (finish with CTRL+D/CTRL+Z) and let Flowra resolve PSR-4 paths automatically
cat diagram.mmd | php artisan flowra:import-workflow "App\Workflows\OrderWorkflow"

# a snippets summary is still stored at storage/app/flowra/imports/-import.php unless you override --output
```

`flowra:import-workflow` always writes the workflow class and its states enum into the same directory defined by `config('flowra.workflows_path')` (default: `app/workflows/`). Update that config value to point Flowra at a different base directory for generated workflows.

It also publishes config (`config/flowra.php`), migrations, stubs, and translations. After installing via Composer, run:

```
php artisan vendor:publish --tag=flowra-config
php artisan vendor:publish --tag=flowra-migrations
php artisan vendor:publish --tag=flowra-stubs
php artisan migrate
```

---

🚀 Usage
-------

[](#-usage)

Once you have configured your model with the `HasWorkflow` trait and defined your workflows, you can start using them.

### Applying Transitions

[](#applying-transitions)

There are several ways to apply transitions to a model.

#### Using Magic Properties

[](#using-magic-properties)

The easiest way is to use the magic properties on the workflow instance, which correspond to the transition keys defined in your `transitionsSchema`.

```
$context = Context::find(1);

// Apply transition using its key as a property
$context->mainWorkflow->filling_app_data->apply();

// Or using camelCase
$context->mainWorkflow->fillingAppData->apply();
```

#### Using the Transition DTO

[](#using-the-transition-dto)

You can also apply a transition by passing the `Transition` DTO directly.

```
use Flowra\DTOs\Transition;

$context->mainWorkflow->apply(
    Transition::make('filling_app_data', MainWorkflowStates::INIT, MainWorkflowStates::DRAFT)
);
```

#### Adding Metadata

[](#adding-metadata)

You can attach comments or the ID of the user who applied the transition.

```
$context->mainWorkflow->filling_app_data
    ->comment('This is a reason for transition', 'Another comment')
    ->appliedBy(auth()->id())
    ->apply();
```

### Bulk Transitions

[](#bulk-transitions)

Flowra provides a way to apply transitions to multiple models efficiently.

```
$models = Context::whereIn('id', [1, 2, 3])->get();

// Apply transition to a collection
MainWorkflow::applyMany($models, 'filling_app_data');

// You can also use the BulkTransitionService for more control
use Flowra\Services\BulkTransitionService;

BulkTransitionService::for(MainWorkflow::class)
    ->targets($models)
    ->transition('filling_app_data')
    ->appliedBy(auth()->id())
    ->comments(['Bulk update'])
    ->run();
```

### State Jumps

[](#state-jumps)

If you need to move a model to a specific state without following a defined transition (e.g., for administrative resets), you can use the `jumpTo` method.

```
$context->mainWorkflow->jumpTo(MainWorkflowStates::INIT, 'admin_reset');
```

### Accessing Status &amp; History

[](#accessing-status--history)

You can easily access the current status and the full history of transitions.

```
// Get current status model (Flowra\Models\Status)
$status = $context->mainWorkflow->status();
echo $status->to; // 'draft'

// Get current state (Enum case)
$state = $context->mainWorkflow->currentState;

// Get history (Collection of Flowra\Models\Registry)
$history = $context->mainWorkflow->registry();
```

---

🧪 Querying &amp; Scopes
-----------------------

[](#-querying--scopes)

The `HasWorkflowScopes` trait (included in `HasWorkflow`) installs helper scopes and macros that allow you to query your models based on their workflow state.

### Basic Scopes

[](#basic-scopes)

```
// Find all models in a specific state
Context::query()
    ->whereMainWorkflowCurrentStatus(MainWorkflowStates::PUBLISHED)
    ->get();

// Using orWhere
Context::query()
    ->whereMainWorkflowCurrentStatus(MainWorkflowStates::DRAFT)
    ->orWhereMainWorkflowCurrentStatus(MainWorkflowStates::INIT)
    ->get();
```

### State Group Expansion

[](#state-group-expansion)

Flowra's scopes automatically handle state groups. If you query by a parent state that has children, Flowra will include models in any of those child states.

```
// If DRAFT group includes INIT, FILLING_DATA, and SENT
// This will find models in any of those three states
Context::query()
    ->whereMainWorkflowCurrentStatus(MainWorkflowStates::DRAFT)
    ->get();
```

### Eager Loading Statuses

[](#eager-loading-statuses)

To avoid N+1 issues when you need to access workflow information for multiple models, use the `with` scopes.

```
// Eager load the main workflow status
$models = Context::query()
    ->withMainWorkflowStatus()
    ->get();

// Eager load and filter at the same time
$models = Context::query()
    ->withWhereMainWorkflowCurrentStatus(MainWorkflowStates::READY_FOR_AUDITING)
    ->get();
```

---

Flowra brings workflow modeling, state management, and auditability straight into your Laravel models. Whether you’re orchestrating multi-step approvals or complex business processes, Flowra gives you strongly typed, testable workflows you can iterate on quickly. Happy flowing!

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance78

Regular maintenance activity

Popularity16

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~21 days

Recently: every ~31 days

Total

7

Last Release

123d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8a16125a41bc529b7bba7a68333f48032a391594f0651edfe1a1737609bd0a28?d=identicon)[mhQady](/maintainers/mhQady)

---

Top Contributors

[![mhQady](https://avatars.githubusercontent.com/u/71000742?v=4)](https://github.com/mhQady "mhQady (23 commits)")

---

Tags

approval-workflowbpmnfinite-state-machinelaravelphpstate-machineworkflowworkflow-enginelaravellaravel-packageworkflowfinite-state machineworkflow enginestate-machinebusiness-processprocess-automationflowraHierarchical State Machine

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/mhqady-flowra/health.svg)

```
[![Health](https://phpackages.com/badges/mhqady-flowra/health.svg)](https://phpackages.com/packages/mhqady-flowra)
```

###  Alternatives

[ringierimu/state-workflow

Laravel State Workflow provide tools for defining and managing workflows and activities with ease.

3251.1k](/packages/ringierimu-state-workflow)[erag/laravel-pwa

A simple and easy-to-use PWA (Progressive Web App) package for Laravel applications.

16083.3k](/packages/erag-laravel-pwa)[brexis/laravel-workflow

Integerate Symfony Workflow component into Laravel.

283125.6k](/packages/brexis-laravel-workflow)[tarfin-labs/event-machine

Event-driven state machines for Laravel with event sourcing, type-safe context, and full audit trail.

188.5k](/packages/tarfin-labs-event-machine)[waad/laravel-profanity-filter

Laravel Profanity Filter - Powerful PHP package for detecting, filtering, and masking profanity in multiple languages. Supports leet speak, custom word lists, case sensitivity, and seamless Laravel integration.

202.9k](/packages/waad-laravel-profanity-filter)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
