csinghdev/cs-revisionable

为您的模型使用Laravel保存带有自定义字段的修订历史

1.29.0 2017-07-12 08:16 UTC

README

Revisionable

Laravel 4.x Laravel 5.2 Latest Version Downloads License

您是否希望在项目中为任何模型保留修订历史,而不必为此做任何工作?通过简单地从您的模型扩展修订,您可以立即获得这样的功能,并能够显示类似于以下的历史记录:

  • Chris将标题从'Something'更改为'Something else'
  • Chris将类别从'News'更改为'Breaking news'
  • Matt将类别从'Breaking news'更改为'News'

因此,您不仅可以查看发生了什么历史,还可以知道是谁做的,因此有责任。

Revisionable是一个Laravel包,允许您无需思考即可为模型保留修订历史。有关背景信息和信息,请参阅这篇文章

与第三方Auth / Eloquent扩展一起工作

Revisionable支持由以下驱动的Auth

Revisionable现在也可以用作特质,因此您的模型可以继续扩展Eloquent,或任何其他扩展Eloquent的类(例如Ardent)。

安装

Revisionable可以通过composer安装,详细信息在packagist,这里

将以下内容添加到您的项目的composer.json文件中的require部分

"csinghdev/cs-revisionable": "1.*",

运行composer update以下载包

php composer.phar update

最后,您还需要在包上运行迁移(Laravel 5.x)

php artisan migrate --path=vendor/venturecraft/revisionable/src/migrations

对于Laravel 4.x用户

php artisan migrate --package=venturecraft/revisionable

如果您将频繁地完全迁移上下文(使用migrate:refresh),您可以采取的一个替代方案是,将包中的迁移文件从app/database文件夹复制到您的文件夹中,并将类名从CreateRevisionsTable更改为类似CreateRevisionTable的东西(不带's',否则您将收到一个错误,表明有重复的类)

cp vendor/venturecraft/revisionable/src/migrations/2013_04_09_062329_create_revisions_table.php app/database/migrations/

文档

实现

新的基于特质实现

对于您想要保留修订历史的任何模型,请包含修订的命名空间并在模型中使用RevisionableTrait,例如,如果您正在使用另一个可启动的特质,请确保在模型中重写boot方法;

namespace MyApp\Models;

class Article extends Eloquent {
    use \Venturecraft\Revisionable\RevisionableTrait;

    public static function boot()
    {
        parent::boot();
    }
}

作为特质,修订现在可以与标准的Eloquent模型一起使用,或者与任何扩展Eloquent的类一起使用,例如Ardent

特质需要PHP >= 5.4

基于类的历史实现

新的基于特质的方案与现有的Revisionable安装向后兼容。您仍然可以使用下面的安装说明,这实际上是一个扩展特质的包装器。

对于您希望保留修订历史记录的任何模型,请包含可修订命名空间并扩展可修订,而不是eloquent,例如:

use Venturecraft\Revisionable\Revisionable;

namespace MyApp\Models;

class Article extends Revisionable { }

注意,这也适用于命名空间模型。

实现说明

如果需要,您可以通过在您的模型中将 $revisionEnabled 设置为 false 来禁用修订。如果您想暂时禁用修订,或者如果您想创建自己的基模型,该模型扩展了可修订,所有模型都扩展了它,但您想关闭某些模型的修订,这将很有用。

namespace MyApp\Models;

class Article extends Eloquent {
    use Venturecraft\Revisionable\RevisionableTrait;

    protected $revisionEnabled = false;
}

您还可以通过将 $historyLimit 设置为您想要停止修订之前要保留的修订次数来在 X 次修订后禁用修订。

namespace MyApp\Models;

class Article extends Eloquent {
    use Venturecraft\Revisionable\RevisionableTrait;

    protected $revisionEnabled = true;
    protected $historyLimit = 500; //Stop tracking revisions after 500 changes have been made.
}

为了维持历史记录的限制,但如果你想要删除旧修订而不是停止跟踪修订,你可以通过设置 $revisionCleanup 来实现该功能。

namespace MyApp\Models;

class Article extends Eloquent {
    use Venturecraft\Revisionable\RevisionableTrait;

    protected $revisionEnabled = true;
    protected $revisionCleanup = true; //Remove old revisions (works only when used with $historyLimit)
    protected $historyLimit = 500; //Maintain a maximum of 500 changes at any point of time, while cleaning up old revisions.
}

存储软删除

默认情况下,如果您的模型支持软删除,修订将存储此删除和任何恢复作为模型上的更新。

您可以选择忽略删除和恢复,通过将 deleted_at 添加到您的 $dontKeepRevisionOf 数组中。

为了更好地格式化 deleted_at 条目的输出,您可以使用 isEmpty 格式化器(有关示例,请参阅格式化输出)。

存储创建

默认情况下,新模型的创建不会作为修订存储。只有模型后续的变化会被存储。

如果您想将创建作为修订存储,可以通过在您的模型中添加以下内容来覆盖此行为,将 revisionCreationsEnabled 设置为 true

protected $revisionCreationsEnabled = true;

更多控制

无疑,会有一些情况,您只想为模型的某些字段存储修订历史记录,这以两种不同的方式支持。在您的模型中,您可以指定您明确想要跟踪的字段,其他所有字段都被忽略

protected $keepRevisionOf = array(
    'title'
);

或者,您可以指定您明确不想要跟踪的字段。所有其他字段将被跟踪。

protected $dontKeepRevisionOf = array(
    'category_id'
);

$keepRevisionOf 设置优先于 $dontKeepRevisionOf

自定义字段

要添加自定义字段,请将 $revisionsCustomFields 添加到您的模型中。之后,在您的模型中添加一个函数来添加自定义字段及其值,在创建/更新/删除时使用。

protected $revisionsCustomFields;
public function addRevisionsCustomFields($custom_fields) {
    $this->revisionsCustomFields = $custom_fields;
}

现在,在您的控制器文件中,添加如下字段(以用户为例):

$user->addRevisionsCustomFields([
            'action' => "Create"
        ]);
$user->save();

事件

每次创建模型修订时,都会触发一个事件。您可以监听 revisionable.created
revisionable.savedrevisionable.deleted

// app/Providers/EventServiceProviders.php
public function boot(DispatcherContract $events)
{
    parent::boot($events);

    $events->listen('revisionable.*', function($model, $revisions) {
        // Do something with the revisions or the changed model. 
        dd($model, $revisions);
    });
}

格式输出

您可以使用 eloquent accessors 在您的模型中设置值输出,有关更多信息,请参阅 laravel 文档。因此,以下文档已弃用

在您想要控制值输出格式的情况下,例如布尔字段,您可以在模型中将它们设置在 $revisionFormattedFields 数组中。例如:

protected $revisionFormattedFields = array(
    'title'  => 'string:<strong>%s</strong>',
    'public' => 'boolean:No|Yes',
    'modified' => 'datetime:m/d/Y g:i A',
    'deleted_at' => 'isEmpty:Active|Deleted'
);

您也可以使用模型中的 $revisionFormattedFieldNames 数组覆盖字段名称输出,例如:

protected $revisionFormattedFieldNames = array(
    'title' => 'Title',
    'small_name' => 'Nickname',
    'deleted_at' => 'Deleted At'
);

当使用 $revision->fieldName() 输出修订字段名称时,这会发挥作用。

字符串

要格式化字符串,只需在值前加上 string: 并确保包含 %s(这是实际值将在格式化响应中出现的位置),例如:

string:<strong>%s</strong>

布尔

布尔默认情况下将显示为 0 或 1,这对最终用户来说可能相当平淡,所以这个格式化器可以用来输出更友好的内容。在值前加上 boolean: 然后添加您的 false 和 true 选项,用竖线分隔,例如:

boolean:No|Yes

日期时间

日期时间默认情况下将显示为 Y-m-d H:i:s。在值前加上 datetime: 然后添加您的日期时间格式,例如:

datetime:m/d/Y g:i A

是否为空

此功能借鉴了布尔值,但它不是测试值是否为真或假,而是检查值是否为null或空字符串。

isEmpty:No|Yes

如果您想输出值,它也可以接受%s,例如以下代码将显示'无'如果值为空,或者如果存在实际值则显示实际值

isEmpty:Nothing|%s

加载修订历史

要加载给定模型的修订历史,只需在该模型上调用revisionHistory方法,例如:

$article = Article::find($id);
$history = $article->revisionHistory;

显示历史记录

大多数情况下,修订历史将包含足够的信息以直接输出变更历史,但是在外键更新的情况下,我们需要能够进行一些映射,并显示比plan_id从3变为1更友好的信息。

为此,有一些辅助方法可以显示更深入的信息,因此您可以显示类似Chris将计划从青铜改为黄金的信息。

上面的结果将是以下内容的输出:

@foreach($account->revisionHistory as $history )
    <li>{{ $history->userResponsible()->first_name }} changed {{ $history->fieldName() }} from {{ $history->oldValue() }} to {{ $history->newValue() }}</li>
@endforeach

如果您还启用了创建的修订版本,您可以这样显示:

@foreach($resource->revisionHistory as $history)
  @if($history->key == 'created_at' && !$history->old_value)
    <li>{{ $history->userResponsible()->first_name }} created this resource at {{ $history->newValue() }}</li>
  @else
    <li>{{ $history->userResponsible()->first_name }} changed {{ $history->fieldName() }} from {{ $history->oldValue() }} to {{ $history->newValue() }}</li>
  @endif
@endforeach

userResponsible()

返回负责进行修订的用户。返回用户模型,如果没有记录用户则返回null。

加载的用户模型取决于您在config/auth.php文件中为model变量设置的值。

fieldName()

返回被更新的字段的名称,如果更新的字段是外键(在这个阶段,它只是检查字段是否具有_id后缀),则返回_id之前的部分。例如,如果字段是plan_id,则返回plan

请记住,您可以通过在模型中设置$revisionFormattedFieldNames数组来覆盖字段的输出。

identifiableName()

当值(旧值或新值)是外键关系的ID时使用。

默认情况下,它只返回被更新的模型的ID。您可以根据自己的需求在模型中覆盖此方法以返回有意义的内容。例如:

use Venturecraft\Revisionable\Revisionable;

class Article extends Revisionable
{
    public function identifiableName()
    {
        return $this->title;
    }
}

oldValue()和newValue()

获取更新前或更新后的模型值。如果它是外键,则调用identifiableName()。

未知或无效的外键作为修订

在旧值或新值为不再存在的外键或实际上是null的情况下,您可以在模型中设置两个变量来控制这些情况下的输出。

protected $revisionNullString = 'nothing';
protected $revisionUnknownString = 'unknown';

disableRevisionField()

有时暂时禁用可修订的字段可能会很有用,如果您想要保存更新但不需要保留更改记录。

$object->disableRevisionField('title'); // Disables title

或者

$object->disableRevisionField(array('title', 'content')); // Disables title and content

贡献

欢迎并鼓励贡献;为了保持有序,所有错误和请求都应该在GitHub问题标签页中打开,该标签页位于venturecraft/revisionable/issues

所有拉取请求都应该提交到develop分支,以便在合并到master分支之前进行测试。

遇到麻烦了吗?

如果您在使用此包时遇到困难,可能其他人已经遇到了相同的问题。您可以在以下两个地方查找常见问题的答案:

如果您更喜欢在StackOverflow上公开提出问题,请使用'revisionable'标签。