gazugafan / laravel-changelog
为 Laravel 5 记录数据库变更日志
Requires
- php: >=7.0.0
- doctrine/dbal: ^2.5
- illuminate/database: ^5.1
- illuminate/events: ^5.1
Requires (Dev)
- mockery/mockery: ^0.9.4
- phpunit/phpunit: ^4.0
- satooshi/php-coveralls: 1.*
This package is auto-updated.
Last update: 2024-09-21 22:05:04 UTC
README
为 Laravel 5 记录数据库变更日志
自动记录谁做了什么,何时,从哪里。与 laravel-temporal 配合使用效果更佳!
要求
- 此软件仅在 Laravel 5.4 和 PHP 7.1 上进行过测试。如果您发现它在旧版本上也能工作,请告诉我!
- 此外,也仅在 MySQL/MariaDB 上进行了测试。如果您发现它可以与其他数据库一起使用,请告诉我!
- 尚未编写单元测试。
安装
通过 Composer 安装...
composer require gazugafan/laravel-changelog
将服务提供者添加到 config/app.php
文件中的 providers
数组...
'providers' => [ ... \Gazugafan\Changelog\ServiceProvider::class ];
并在 config/app.php
文件中的 aliases
数组中添加一个别名...
'aliases' => [ ... 'Change' => Gazugafan\Changelog\Facades\Change::class ];
概述
变更记录表将获得一个新的 change_id
列,它与一个新创建的 changes
表相关联,用于保存关于记录最新变更的详细信息。将变更包裹在数据库事务中可以使多个表受到同一变更的影响。每次变更时(如果可能),都会自动记录认证用户的 ID,并且您可以包括像备注和变更发生的界面这样的详细信息。
与 laravel-temporal 配合使用时,这将为您提供对记录的每次变更的历史记录,包括谁进行了每次变更以及确切更改了什么。
模式迁移
运行以下迁移来创建必要的 changes
表...
Schema::create('changes', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); $table->unsignedInteger('user_id')->nullable(); $table->string('interface', 127)->nullable(); $table->string('notes', 255)->nullable(); $table->enum('status', ['pending', 'complete', 'failed'])->default('pending'); $table->index('status'); });
您还需要将 change_id
列添加到您想要记录变更的任何表中...
Schema::table('widgets', function (Blueprint $table) { $table->unsignedInteger('change_id')->nullable(); });
模型设置
要使您的模型支持变更记录,只需将 Gazugafan\Changelog\Changelog
特性添加到模型的类...
class Widget extends Model { use Changelog; //add all the changelog features }
您还可以设置一些模型特定的选项...
class Widget extends Model { use Changelog; //add all the changelog features protected $forceChangelogging = true; //set to false to allow saving outside of changes protected $changeIDColumn = 'change_id'; //in case you want to use a different column for some reason }
用法
记录变更
要开始记录变更,调用 Change::begin()
。您可以可选地指定与变更一起记录的界面和备注...
Change::begin('Web API', 'Painting a widget red');
这将向 changes
表中插入一个新的变更记录,状态为 pending
,并自动填写可用的认证用户的 ID。接下来,开始进行与您的变更相关的一切操作...
$widget = \App\Widget::find(123); $widget->color = 'red'; $widget->save(); $redPaint = \App\Paint::where('color', 'red')->first(); $redPaint->available -= 1; $redPaint->save();
每次您使用具有 Changelog
特性的模型调用 save()
时,正在进行的变更的 ID 将自动填写到记录的 change_id
中。
当您完成您的变更时,调用 Change::commit()
。这将通过将状态更新为 complete
来最终确定变更。如果变更由于某些原因失败,您可以通过调用 Change::rollBack()
来放弃变更并将其状态设置为 failed
。以下是一个示例...
try { Change::begin('Web API', 'Painting a widget red'); $widget = \App\Widget::find(123); $widget->color = 'red'; $widget->save(); $redPaint = \App\Paint::where('color', 'red')->first(); $redPaint->available -= 1; $redPaint->save(); Change::commit(); } catch (Exception $e) { Change::rollBack(); }
如果这看起来类似于 Laravel 中处理数据库事务的方式,那不是巧合!默认情况下,上述 Change
方法也会将您的变更包裹在事务中。这意味着如果在您的变更过程中发生错误,整个操作将自动回滚。换句话说:要么整个变更成功,要么整个操作失败。没有部分变更可以成功完成。同样,就像 Laravel 事务一样,您可以使用闭包使用 transaction
方法...
Change::transaction(function (){ $widget = \App\Widget::find(123); $widget->color = 'red'; $widget->save(); $redPaint = \App\Paint::where('color', 'red')->first(); $redPaint->available -= 1; $redPaint->save(); }, 'Web API', 'Painting a widget red', 5); //make 5 attempts in case of deadlock
如果您出于某种原因希望禁用事务的使用,请将 false
作为第三个参数传递给 Change::begin()
...
try { Change::begin('Web API', 'Painting a widget red', FALSE); //start a change without transactions $widget = \App\Widget::find(123); $widget->color = 'red'; $widget->save(); $redPaint = \App\Paint::where('color', 'derek')->first(); $redPaint->available -= 1; //there's no "derek" color, dummy! This is gonna blow up! $redPaint->save(); Change::commit(); } catch (Exception $e) { //great, now we've somehow painted a widget red without using any red paint. //if only we had used transactions, we'd rollback painting the widget red here... Change::rollBack(); //but this will still log the change's status as "failed", at least }
通过 Auth::id()
获取已认证用户的ID。如果您想用自己定义的行为覆盖它,可以向 Change::authID()
传递一个闭包...
Change::authID(function(){ return getMySpecialLoggedInUsersID(); }); Change::begin(); ...
陷阱
- 与正常的Laravel数据库事务不同,嵌套更改不受支持。如果在另一个更改正在进行时尝试启动一个更改,将导致错误。