MichaelJmeadows/has-histories

一个简单的特性,用于辅助Eloquent模型版本历史记录。

v2.0.0 2023-10-29 23:00 UTC

This package is auto-updated.

Last update: 2024-09-30 00:58:25 UTC


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_atcreated_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');