louishrg/state-flow

Laravel 状态机的简单实现

1.4 2023-11-08 22:52 UTC

This package is auto-updated.

Last update: 2024-09-09 00:44:30 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads

为您的 Laravel 应用提供简单状态机/弹性状态!

安装

您可以通过 composer 安装此包

composer require louishrg/state-flow

使用 artisan 创建您的状态类

为每个可用的状态创建文件是重复的,因此此包提供了一个 artisan 命令来加快处理过程

php artisan states:new

简单状态,也称为 Stack

Stack 是一个不需要注册转换的简单状态机。这是为您的模型添加硬编码类型或类别的非常方便的方式。

如何使用

您至少需要一个变量:key,这是数据库列的实际值。

如果您想使用其他变量作为键,您可以在创建状态 Stack 时提供变量的名称(见下文)

  • 第一个参数是您所有可用的状态数组。
  • 第二个参数是创建模型时的默认值(可选)。
  • 第三个参数用于覆盖默认键值(可选)。
new Stack(self::$status, Pending::class, 'key'),

在您选择的目录中声明您的状态类,例如

namespace App\Models\States\User;

use Louishrg\StateFlow\StateAbstract;

class Active extends StateAbstract
{
    public $key = 'active';

    public $label = 'Active';
    public $color = 'green';
    // and everything you want !
    //
    public function computedField() {
        return $this->$label.$this->color;
    }
}

现在,在您的模型中添加所有需要的声明

<?php

...

// Import all your states
use App\Models\States\Active;
use App\Models\States\Banned;
use App\Models\States\Inactive;

// Import the classes
use Louishrg\StateFlow\Traits\WithState;
use Louishrg\StateFlow\Casts\StateCast;
use Louishrg\StateFlow\Stack;

class User
{
    // Add WithState trait
    use WithState, ...;

    ...

    // You can register all available states for a namespace in a var for example
    protected static $status = [
        Active::class,
        Banned::class,
        Inactive::class,
    ];

    // register your states as a Stack for the namespace "status"
    protected static function registerStates(){
        return [
            'status' => new Stack(self::$status),
        ];
    }

    ...

    // Add the cast for your column and that's it !
    protected $casts = [
        'status' => StateCast::class,
    ];
}

现在您可以通过以下方式获取您的状态

$user->status;
// It'll give you the state object with all your defined constants in it.

如果您想更新/创建具有状态的对象

$user = new User;

// Simply pass the state class and that's it.
$user->status = Pending::class;

Laravel Nova

如果您想在 nova 中使用此包,应按以下方式使用

使用选择框的示例

Select::make('Statut', 'status')
->options(GearRequest::getState('status')->pluck('label', 'key')->toArray())
->displayUsing(fn($item) => $item->label)
->resolveUsing(fn($item) => $item->key)
// Use the magic setter in the fillUsing method
->fillUsing(fn($request, $model) => ($model->_status = $request->status)),

有用的方法

如果您想比较状态的一个当前值与另一个,可以使用

$user->status->equal(Banned::class);

此外,您可以直接获取当前状态的类

$user->status->is();

如果您想检索在命名空间中注册的所有状态作为一个集合

User::getState('status')

复杂状态,也称为 Flow

如果您想在您的应用程序中使用真实的状态机模式,您可以添加注册如下

// Import the Flow class
use Louishrg\StateFlow\Flow;

...

protected static function registerStates(){
    return [
        // use a custom method in your model for better readability
        'status' => self::myFlow(),
    ];
}

// You need to use the Flow class
protected static function myFlow(){
    // We'll use the data from above
    return (new Flow(self::$status))
    // Add a transition, here your state can go from Pending to either Accepted or Refused.
    ->add(Pending::class, [
        Accepted::class,
        Refused::class
    ])
    ->add(Refused::class, [
        Pending::class
    ])
    ->add(Accepted::class, [
        Pending::class,
        Canceled::class,
        CanceledByAdmin::class
    ])
    ->default(Pending::class);
    // You can specify a default class, when creating you don't need to provide value.
}

Flow 的方法

当使用 flows 时,您可以检查是否可以转换到另一个状态如下

$user->status->canBe(Banned::class);

或者您可以获取当前状态的所有可能转换

$user->status->allowedTo();

状态的方法

当您从数据库检索行时,您需要实例化状态来获取键

$users = User::where('status', (new Active)->key)->get();

为了简化语法,每个状态值都扩展了提供魔法方法的 StateAbstract

$users = User::where('status', Active::key())->get();

魔法方法可以获取您的状态中定义的每个属性

即将推出的功能

  • 在状态类中使用 getter & setters 的可能性
  • 测试

测试

composer test

变更日志

有关最近更改的更多信息,请参阅变更日志

贡献

有关详细信息,请参阅贡献指南

安全性

如果您发现任何安全相关的问题,请通过电子邮件 dev@narah.io 而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证 (MIT)。请参阅 许可证文件 了解更多信息。

laravel 包模板

此包使用 Laravel 包模板 生成。