inmanturbo / ecow
Eloquent 副本写入:自动将所有模型更改复制到单独的表中。
Requires
- php: ^8.2
- illuminate/contracts: ^10.0||^11.0
- inmanturbo/modelware: ^1.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^9.0.0||^8.22.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
README
Eloquent 副本写入:自动将所有模型更改复制到单独的表中。
DALL-E 的作品
安装
您可以通过 composer 安装此包
composer require inmanturbo/ecow
您可以使用以下命令运行迁移
php artisan ecow:migrate
您可以使用以下命令运行迁移
php artisan ecow:migrate
您可以使用以下命令发布并运行迁移
php artisan vendor:publish --tag="ecow-migrations"
php artisan migrate
您可以使用以下命令发布配置文件
php artisan vendor:publish --tag="ecow-config"
这是发布配置文件的内容
return [ /* * Enable or disable the event listeners. */ 'enabled' => env('ECOW_ENABLED', true), /* * The model used to store saved models. */ 'model' => \Inmanturbo\Ecow\Models\SavedModel::class, /* * After this amount of days, the records in `saved_models` will be deleted * * This functionality uses Laravel's native pruning feature. */ 'prune_after_days' => 365 * 1000000, // wouldn't delete this in a million years /* * The table name used to store saved models. * * Changing it is not supported at this time, * but it's here for reference and used by the `ecow:migrate` command. */ 'saved_models_table' => 'saved_models', /* * These tables will be created when running the migration. * * They will be dropped when running `php artisan ecow:migrate --fresh`. */ 'migration_tables' => [ 'saved_models', 'saved_model_snapshots', ], /* * The Models that should be saved by default. * * You can use '*' to save all models. */ 'saved_models' => '*', /* * The Models that should not be saved by default. */ 'unsaved_models' => [], ];
用法
此包通过创建、更新和删除事件来存储和跟踪所有模型的更改。这将不会跟踪使用批量更新或直接使用 DB 门面写入数据库所做的任何更改。
它使用 事件溯源 通过存储原生 eloquent 事件的数据,且不需要向您的模型添加任何特质!
存储任意数据
您可以在模型上存储任意数据,它将被存储在模型的记录中,以后可以使用 Inmanturbo\Ecow\Facades\Ecow
门面检索。
use Inmanturbo\Ecow\Facades\Ecow; $model->fakeField = 'this is some fake data'; $model->save(); // no error $model->fakeField; // null $clone = Ecow::retrieveModel(clone $model); $clone->fakeField; // 'this is some fake data'
建议在检索模型时使用克隆,而不是修改原始模型,因为将历史中的任意属性添加到运行时的 auth()->user()
可能会有意外结果。
快照模型
Ecow::retrieveModel
会遍历模型的先前所有版本来构建状态。如果您有一个模型的数百万个版本,这可能会稍微减慢速度。快照设置当前状态,然后从那时起跟踪更改。
Ecow::snapshotModel($model);
查询模型版本和更改
您可以使用 Inmanturbo\Ecow\Facades\Ecow::savedModelVersions($model)
查询模型的保存版本。
use Inmanturbo\Ecow\Facades\Ecow; $versions = Ecow::savedModelVersions($model)->latest('model_version')->limit(10)->get(); foreach ($versions as $version) { // get the saved models version $modelVersion = $version->model_version; // make an in memory copy of the model $modelCopy = $version->makeRestoredModel(); // reset the current model's state to this version $modelCopy->save(); // }
重放模型历史
您可以使用 php artisan ecow:replay-models
重放所有已记录模型的记录。
php artisan ecow:replay-models
这将截断所有记录的模型,并使用当前应用程序逻辑重新播放它们的构建状态。
排除模型从 Ecow 监听器中
您可能不希望某些模型被记录。您可以将它们的类名添加到 ecow.php
配置文件中的 unsaved_models
数组中。
php artisan vendor:publish --tag="ecow-config"
return [ /... /* * The Models that should be saved by default. * * You can use '*' to save all models. */ 'saved_models' => '*', /* * The Models that should not be saved by default. */ 'unsaved_models' => [\App\Models\User::class], ];
仅监听和记录少量模型
您可能只想记录几个模型。您可以将它们的类名添加到 ecow.php 配置文件中的 saved_models
数组中。
return [ /... /* * The Models that should be saved by default. * * You can use '*' to save all models. */ 'saved_models' => [\App\Models\Subscription::class], /* * The Models that should not be saved by default. */ 'unsaved_models' => [], ];
覆盖 modelware
管道
此包通过 管道(类似于中间件)发送事件数据,这些管道迭代可调用的类集合,这些集合绑定到并从服务容器解析。它们可以在服务提供程序的 boot 方法中使用以下语法替换或覆盖
app()->bind("ecow.{$event}", function () use ($pipes) { return collect($pipes)->map(fn ($pipe) => app($pipe)); });
其中 {$event}
是 eloquent 的 通配符事件
ecow.eloquent.creating*
=>eloquent.creating*
ecow.eloquent.updating*
=>eloquent.updating*
ecow.eloquent.deleting*
=>eloquent.deleting*
示例
public function boot() { // pipes for all eloquent.creating events app()->bind('ecow.eloquent.creating*', fn () => collect($pipes = [ \App\MyCustom\Invokable::class, )); }
此包将通过您的自定义管道发送以下数据对象
use Inmanturbo\Modelware\Data; $data = app(Data::class, [ 'event' => $events, 'model' => $payload[0], 'payload' => $payload, ]);
建议您以以下默认值开始您的管道
[ \Inmanturbo\Ecow\Pipeline\InitializeData::class, \Inmanturbo\Ecow\Pipeline\EnsureModelShouldBeSaved::class, \Inmanturbo\Ecow\Pipeline\EnsureModelIsNotSavedModel::class, \Inmanturbo\Ecow\Pipeline\EnsureEventsAreNotReplaying::class, \Inmanturbo\Ecow\Pipeline\EnsureModelIsNotBeingSaved::class, // custom classes here ];
您也可以覆盖单个管道
app()->bind(\Inmanturbo\Ecow\Pipeline\InitializeData::class, \App\Pipeline\InitializeData::class)
禁用 Ecow 事件监听器
您可以在运行时使用 Ecow::disable()
禁用 ecow 监听器
use Inmanturbo\Ecow\Facades\Ecow; Ecow::disable(); User::create([...]); // will not be recorded Ecow::enable(); User::create([...]); // will be recorded
您可以通过 config('ecow.enabled')
或 env('ECOW_ENABLED')
全局禁用它们
// ecow.php return [ /* * Enable or disable the event listeners. */ 'enabled' => env('ECOW_ENABLED', true), ... ]
关于模型键的说明
这里使用的是事件源模式,最佳实践是使用uuids
或guids
作为模型的ID,因为在提交到数据库之前,模型ID可能无法被识别或全局唯一标识。然而,为了方便起见,该包支持标准自增键,如果模型创建时没有uuid
,则会通过填充创建事件上的自增键来实现。这要求包本身创建模型并通过返回false
来阻止创建事件。此外,每次创建模型时,包都会在自己的表中存储一个guid属性。否则,更新存储的事件历史通常是不可取的,也不推荐这样做。仅在创建/创建时,包作为解决方案才执行此操作。
还支持,可能也是最受欢迎的做法是,在你的模型表上同时使用uuid
和(自增)id
列。每当使用名为uuid
的列时,包将使用$model->uuid
而不是$model->getKey()
来记录模型版本。
测试
composer test
变更日志
有关最近更改的详细信息,请参阅变更日志。
贡献
有关详细信息,请参阅贡献指南。
安全漏洞
有关报告安全漏洞的详细信息,请参阅我们的安全策略。
鸣谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。