Eloquent 副本写入:自动将所有模型更改复制到单独的表中。

v1.0.4 2024-08-09 17:55 UTC

This package is auto-updated.

Last update: 2024-09-12 00:24:25 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Eloquent 副本写入:自动将所有模型更改复制到单独的表中。

ecow

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),
...
]

关于模型键的说明

这里使用的是事件源模式,最佳实践是使用uuidsguids作为模型的ID,因为在提交到数据库之前,模型ID可能无法被识别或全局唯一标识。然而,为了方便起见,该包支持标准自增键,如果模型创建时没有uuid,则会通过填充创建事件上的自增键来实现。这要求包本身创建模型并通过返回false来阻止创建事件。此外,每次创建模型时,包都会在自己的表中存储一个guid属性。否则,更新存储的事件历史通常是不可取的,也不推荐这样做。仅在创建/创建时,包作为解决方案才执行此操作。

还支持,可能也是最受欢迎的做法是,在你的模型表上同时使用uuid和(自增)id列。每当使用名为uuid的列时,包将使用$model->uuid而不是$model->getKey()来记录模型版本。

测试

composer test

变更日志

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

贡献

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

安全漏洞

有关报告安全漏洞的详细信息,请参阅我们的安全策略

鸣谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件