mtvs / eloquent-approval
Laravel Eloquent 模型的审批流程。
Requires
- illuminate/database: ^8.0|^9.0|^10.0
- illuminate/support: ^8.0|^9.0|^10.0
Requires (Dev)
- mockery/mockery: ^1.0
- orchestra/testbench: ^6.0|^7.0|^8.0
- phpunit/phpunit: ^8.3|^9.0|^10.0
This package is auto-updated.
Last update: 2024-09-14 17:26:48 UTC
README
Eloquent Approval
Laravel Eloquent 模型的审批流程。
为什么我们需要在应用中实现内容审批
除非你能够接受不可接受的内容、垃圾邮件以及其他可能出现在用户帖子中的违规行为,否则你需要在你的应用中加入某种形式的内容审批。
为什么采用三种状态审批流程
虽然可以使用布尔字段来批准模型,但具有三个可能值(待批准、批准和拒绝)的字段给我们提供了更多的灵活性。它区分了等待决策的模型和被拒绝的模型,并使用户清楚地了解其内容是否被拒绝。
它如何工作
设置完成后,在创建新的实体时,它们会被标记为 待批准。然后可以将其状态更改为 批准 或 拒绝。
此外,当发生更新操作并修改需要审批的属性时,实体将再次变为 挂起 状态。
默认情况下,审批作用域适用于每个查询,并过滤掉 待批准 和 拒绝 的实体,因此只包含 批准 的实体。你可以通过显式指定来包含未被批准的实体。
安装
$ composer require mtvs/eloquent-approval
设置
注册服务提供者
默认情况下,服务提供者通过 Laravel 包发现自动注册,否则你需要在 config\app.php
中注册它。
Mtvs\EloquentApproval\ApprovalServiceProvider::class
数据库
以下方法向模式添加两个列,一个用于存储 审批状态,命名为 approval_status
,另一个用于存储上次状态更新的 时间戳,命名为 approval_at
。
$table->approvals()
你可以更改默认的列名,但需要在模型中指定它们。
模型
将 Approvable
特性添加到模型中
use Illuminate\Database\Eloquent\Model; use Mtvs\EloquentApproval\Approvable; class Entity extends Model { use Approvable; }
如果你想要更改默认的列名,你需要通过添加类常量到你的模型中指定它们
use Illuminate\Database\Eloquent\Model; use Mtvs\EloquentApproval\Approvable; class Entity extends Model { use Approvable; const APPROVAL_STATUS = 'custom_approval_status'; const APPROVAL_AT = 'custom_approval_at'; }
将
approval_at
添加到模型的$dates
列表中,以便在访问时获得Carbon
实例。
需要审批的属性
当发生更新操作并修改需要审批的属性时,实体将再次变为 挂起 状态。
$entity->update($attributes); // an update with approval required modification $entity->isPending(); // true
请注意,这仅在您对
Model
对象本身执行 更新 操作时发生,而不是使用查询Builder
实例。
默认情况下,所有属性都需要审批。
/** * @return array */ public function approvalRequired() { return ['*']; } /** * @return array */ public function approvalNotRequired() { return []; }
你可以覆盖它们以拥有自定义的审批所需属性集。
它们在 Eloquent 中类似于 $fillable
和 $guarded
。 approvalRequired()
返回 黑名单,而 approvalNotRequired()
返回 白名单。
使用方法
新创建的实体被标记为 待批准,并且默认情况下不包含在模型的查询中。
Entity::create(); // #1 pending Entity::all(); // [] Entity::find(1); // null
包括所有实体
Entity::anyApprovalStatus()->get(); // retrieving all Entity::anyApprovalStatus()->find(1); // retrieving one Entity::anyApprovalStatus()->delete(); // deleting all
如果你想要在每次查询中完全禁用审批作用域,你可以在模型上设置 approvalScopeDisabled
。
use Illuminate\Database\Eloquent\Model; use Mtvs\EloquentApproval\Approvable; class Entity extends Model { use Approvable; public $approvalScopeDisabled = true; }
限制特定状态
Entity::onlyPending()->get(); // retrieving only pending entities Entity::onlyRejected()->get(); // retrieving only rejected entities Entity::onlyApproved()->get(); // retrieving only approved entities
更新状态
在模型对象上
你可以通过在 Model
对象上使用提供的方法来更新实体的状态。
$entity->approve(); // returns bool if the entity exists otherwise null $entity->reject(); // returns bool if the entity exists otherwise null $entity->suspend(); // returns bool if the entity exists otherwise null
在 Builder
对象上
你可以通过在 Builder
对象上使用提供的方法来更新多个实体的状态。
Entity::whereIn('id', $updateIds)->approve(); // returns number of updated Entity::whereIn('id', $updateIds)->reject(); // returns number of updated Entity::whereIn('id', $updateIds)->suspend(); // returns number of updated
审批时间戳
当您更改实体的审批状态时,其approval_at
列会更新。在实体的第一次审批操作之前,其approval_at
是null
。
检查实体状态
您可以使用Model
对象提供的提供的方法来检查实体状态。
$entity->isApproved(); // returns bool if entity exists otherwise null $entity->isRejected(); // returns bool if entity exists otherwise null $entity->isPending(); // returns bool if entity exists otherwise null
审批事件
有一些模型事件会在每个审批操作的之前和之后触发。
此外,还有一个名为approvalChanged
的通用事件,无论实际状态如何,都会在审批状态更改时触发。
您可以通过调用与它们同名并提供回调的提供static
方法来挂钩,或者通过使用具有相同名称的方法注册观察者。
use Illuminate\Database\Eloquent\Model; use Mtvs\EloquentApproval\Approvable; class Entity extends Model { use Approvable; protected static function boot() { parent::boot(); static::approving(function ($entity) { // You can halt the process by returning false }); static::approved(function ($entity) { // $entity has been approved }); // or: static::observe(ApprovalObserver::class); } } class ApprovalObserver { public function approving($entity) { // You can halt the process by returning false } public function approved($entity) { // $entity has been approved } }
Eloquent模型事件也可以映射到您应用程序的事件类。
重复审批
尝试将审批状态设置为当前值会被忽略,即:不会触发事件,审批时间戳也不会更新。在这种情况下,审批方法返回false
。
模型工厂
导入ApprovalFactoryStates
以在使用模型工厂时使用审批状态。
namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; use Mtvs\EloquentApproval\ApprovalFactoryStates; class EntityFactory extends Factory { use ApprovalFactoryStates; public function definition() { // } }
Entity::factory()->approved()->create(); Entity::factory()->rejected()->create(); Entity::factory()->suspended()->create();
处理审批HTTP请求
您可以在控制器中导入HandlesApproval
以对模型执行审批操作。它包含一个抽象方法,必须实现以返回模型的类名。
namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Entity; use Mtvs\EloquentApproval\HandlesApproval; class EntitiesController extends Controller { use HandlesApproval; protected function model() { return Entity::class; } }
特性中的performApproval()
方法执行审批,请求应路由到该方法。它具有通过路由器传递给它的key
和request
参数。
进行路由时,不要忘记为认证和授权应用auth
和can
中间件。
Route::post( 'admin/enitiy/{key}/approval', 'Admin\EntitiesController@performApproval' )->middleware(['auth', 'can:perform-approval'])
请求必须有一个approval_status
键,其值为可能的值之一:approved
、pending
、rejected
。
前端组件
这里还有一些为Vue.js和Bootstrap编写的UI组件,您可以使用它们。首先使用approval:ui
artisan命令安装它们,然后在您的app.js文件中注册它们。
审批按钮组件
调用<approval-buttons>
并传递current-status
和approval-url
属性,以便能够通过HTTP请求设置审批状态。
当发生审批操作时,它发出approval-changed
事件。事件的有效负载是一个对象,包含新的approval_status
和approval_at
值。使用事件来修改相应的entity
上的键,这将反过来在下一个周期中更改current-status
属性。
审批状态组件
调用<approval-status>
并传递value
属性以显示当前状态。
灵感
当我搜索eloquent模型上现有审批功能包时,我遇到了hootlex/laravel-moderation,尽管我决定编写自己的包,但我从那个包中得到了一些有用的灵感。
我还遵循了Eloquent本身编写类似部分代码的方式编写了代码的不同部分。