MichaelJmeadows / has-histories
一个简单的特性,用于辅助Eloquent模型版本历史记录。
Requires
- php: ^8.0
- illuminate/database: ^8.0|^9.0|^10.0
- illuminate/support: ^8.0|^9.0|^10.0
README
一个简单的特性,用于辅助Eloquent模型版本历史记录。
安装
您可以通过composer安装此包
composer require michaeljmeadows/has-histories
使用方法
添加一个迁移来存储您的模型历史。这应该包含与您的主模型表相同的所有字段,以及一个指向原始模型的引用ID。您的模型的历史表可以命名为您喜欢的任何名称,但默认约定将是models
-> model_histories
。我们建议按照此修改后的Laravel Jetstream User迁移修改您的迁移
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { private array $tables = [ 'users', 'user_histories', ]; public function up(): void { foreach ($this->tables as $tableName) { Schema::create($tableName, function (Blueprint $table) use ($tableName) { $isHistoriesTable = str($tableName)->contains('histories'); $table->id(); if ($isHistoriesTable) { $table->foreignId('user_id'); } $table->string('name'); $table->string('email'); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->foreignId('current_team_id')->nullable(); $table->string('profile_photo_path', 2048)->nullable(); $table->timestamps(); if (! $isHistoriesTable) { $table->unique('email'); } }); } } public function down(): void { foreach ($this->tables as $tableName) { Schema::dropIfExists($tableName); } } };
一旦添加了迁移,您只需在模型的定义中包含该特性即可
<?php namespace App\Models; use michaeljmeadows\Traits\HasHistories; use Illuminate\Database\Eloquent\Model; class NewModel extends Model { use HasHistories;
恢复模型
可以使用三种方法中的任何一种来恢复模型
$newModel->restorePrevious(); $newModel->restorePreviousIteration(3); $newModel->restoreBeforeDate('2022-01-01');
这些函数在成功时返回true,如果未找到历史状态,则返回false。
restorePrevious()
将模型恢复到历史表中的上一个状态。
restorePreviousIteration(int $index)
将模型恢复到使用零基编号的状态。例如,restorePreviousIteration(0)
与restorePrevious()
相同。
restoreBeforeDate(DateTimeInterface|string $date)
将模型恢复到给定$date
值之前的最新状态,使用updated_at
和created_at
字段。
恢复说明
- 恢复时,当前模型的副本也会保存到历史表中。
- HasHistories使用历史表的
id
字段来评估最新状态,因为多次恢复可能会导致历史表中出现明显的重复。
自定义行为
忽略的字段
并非模型属性的所有更改都值得记录。在上面的Jetstream User示例中,您可能更愿意忽略对email_verified_at
的更改。在这种情况下,您可以在模型中添加一个受保护的数组属性$ignoredFields
来指定您不感兴趣的属性
<?php namespace App\Models; use michaeljmeadows\Traits\HasHistories; use Illuminate\Database\Eloquent\Model; class User extends Model { use HasHistories; protected array $ignoredFields = [ 'email_verified_at', ];
如果您选择忽略字段,则不应将这些字段包含在历史表迁移中。
历史表名称
默认情况下,HasHistories在确定历史表名称时使用命名约定models
-> model_histories
,但如果出于某种原因这不适合您,您可以通过向模型中添加受保护的字符串属性$historiesTable
来指定不同的历史表名称
<?php namespace App\Models; use michaeljmeadows\Traits\HasHistories; use Illuminate\Database\Eloquent\Model; class User extends Model { use HasHistories; protected string $historyTable = 'user_logging'; // Instead of 'user_histories'.
历史表模型引用
默认情况下,HasHistories将历史表中的一个条目与具有形式为models
-> model_id
的属性的模型相关联,但如果出于某种原因这不适合您,您可以通过添加受保护的字符串属性$historiesModelIdReference
来指定不同的字段
<?php namespace App\Models; use michaeljmeadows\Traits\HasHistories; use Illuminate\Database\Eloquent\Model; class User extends Model { use HasHistories; protected string $historiesModelIdReference = 'user_model_id'; // Instead of 'user_id'.
历史表连接
默认情况下,HasHistories期望历史表将使用与应用于模型的相同连接。偶尔您可能希望为历史表指定不同的连接。这可以通过在saveHistory
方法调用中添加可选参数来完成
<?php namespace App\Observers; use App\Models\NewModel; use Illuminate\Support\Facades\Auth; class NewModelObserver { public function creating(NewModel $newModel): void { $newModel->saveHistory('sqlite'); }
在恢复模型时,可以在每个方法调用的末尾添加相同的连接参数
$newModel->restorePrevious('sqlite'); $newModel->restorePreviousIteration(3, 'sqlite'); $newModel->restoreBeforeDate('2022-01-01', 'sqlite');