前言: 管理后台实现操作日志功能,能够监听且实时记录模型操作数据。?
通过provider中间件和配置文件配合实现
(一)初建数据库
使用laravel数据迁移,迁移文件内容如下:
<?php
/**
**类名与迁移文件名要对应上才可以顺利迁移
**/
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePowerActionLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::connection('mysql_store_power')->create('action_logs', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->comment('执行人用户id');
$table->string('title', 32)->nullable()->comment('行为名称');
$table->text('content')->comment('行为内容');
$table->string('model', 256)->nullable()->comment('行为的关联表格名称或者模型名称(包含命名空间)');
$table->integer('model_id')->unsigned()->nullable()->comment('行为的关联表格受影响记录ID');
$table->string('uri', 256)->default('')->comment('执行操作时的当前uri');
$table->ipAddress('created_ip')->nullable()->comment('执行行为时的IP');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::connection('mysql_store_power')->dropIfExists('action_logs');
}
}
(二) 创建event(事件)和listen(监听)和observe(观察者)
备注:在这里我们没有使用->常规流程:laravel5.5事件系统
所以这里只是备注说明。非文章步骤
- 在App\Events下创建DefaultLoggable.php文件
<?php
namespace App\Events\Power\Log;
use Auth;
use Illuminate\Queue\SerializesModels;
class DefaultLoggable
{
use SerializesModels;
protected $title;
protected $content;
protected $userId;
protected $model;
protected $modelId;
public function __construct(string $title, string $content, $userId = null, $model = null, $modelId = null)
{
$this->title = $title;
$this->content = $content;
$this->userId = $userId ? $userId : (Auth::check() ? Auth::user()->id : 0);
$this->model = $model;
$this->modelId = $modelId;
}
}
- 在App\Listeners下创建DefaultLogger.php
<?php
namespace App\Listeners\Power\Log;
use Request;
use App\Events\Power\Log\DefaultLoggable;
use App\Models\Power\Log\ActionLog;
use Wunsun\Cms\Support\BrowserDetector;
class DefaultLogger
{
/**
* 处理事件
*/
public function handle(DefaultLoggable $event)
{
ActionLog::create([
'user_id' => $event->userId,
'title' => $event->title,
'content' => $event->content,
'model' => $event->model,
'model_id' => $event->modelId,
'uri' => Request::getRequestUri(),
'os' => BrowserDetector::getOS(),
'browser' => BrowserDetector::getBrowser(),
'created_ip' => get_client_ip(),
]);
}
}
- 在App\Observer下创建ModelObserver.php
<?php
namespace App\Observers\Power\Log;
use Illuminate\Support\Arr;
use App\Events\Power\Log\DefaultLoggable;
class ModelObserver
{
/**
* 模型新建后
*/
public function created($model)
{
$attributes = $model->getAttributes();
$attributes = Arr::except($attributes, ['created_at', 'updated_at']);
$modelName = get_class($model);
$baseModelName = get_base_class($model);
$modelId = $model->getKey();
$title = "新建【{$baseModelName}】模型";
$content = "模型数据:".pretty_string($attributes);
event(new DefaultLoggable($title, $content, null, $modelName, $modelId));
}
/**
* 只有确定更新后才记录日志
*/
public function updated($model)
{
$dirty = $model->getDirty();
$original = $model->getOriginal();
// 有时候可能只要监控某些字段
if (method_exists($model, 'limitObservedFields')) {
$fields = $model->limitObservedFields();
$dirty = Arr::only($dirty, $fields);
$original = Arr::only($original, array_keys($dirty));
} else {
$dirty = Arr::except($dirty, ['updated_at']);
$original = Arr::only($original, array_keys($dirty));
}
if (count($dirty)) {
$modelName = get_class($model);
$baseModelName = get_base_class($model);
$modelId = $model->getKey();
$title = "修改【{$baseModelName}】模型";
$content = "数据修改前:".pretty_string($original).";数据修改后:".pretty_string($dirty);
event(new DefaultLoggable($title, $content, null, $modelName, $modelId));
}
}
/**
* 模型删除后
*/
public function deleted($model)
{
$attributes = $model->getAttributes();
$modelName = get_class($model);
$baseModelName = get_base_class($model);
$modelId = $model->getKey();
$title = "删除【{$baseModelName}】模型";
$content = "模型数据:".pretty_string($attributes);
event(new DefaultLoggable($title, $content, null, $modelName, $modelId));
}
}
(三)创建服务中间件
(1)首先,我们在config下创建power.php配置文件。内容如下:
<?php
return [
/**
* 事件相关
*/
'event' => [
/**
* 监听者
*/
'listeners' => [
/**
* 默认的记录事件
*/
'App\Events\Power\Log\DefaultLoggable' => [
'App\Listeners\Power\Log\DefaultLogger',
],
],
/**
* 模型观察者.
* 以下添加的模型都被ModelObserver监听和观察
* 后续添加
*/
'observers' => [
\App\Models\Power\Access\Role::class,
],
],
];
(2)然后我们需要创建一个服务的类,比如叫CqhServiceProvider,最简单的方式就是用artisan来帮我们创建
php artisan make:provider PowerServiceProvider
然后,我们会看到app\Provider文件夹下在生成了如下的文件PowerServiceProvider
.php,并写上代码内容如下
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use App\Observers\Power\Log\ModelObserver;
class PowerServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->registerEvents();
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
}
/**
* 执行配置文件
*/
public function registerEvents()
{
$allListeners = config('power.event.listeners');
foreach ($allListeners as $event => $listeners) {
foreach ($listeners as $listener) {
Event::listen($event, $listener);
}
}
$subscribers = config('power.event.subscribers');
foreach ($subscribers as $subscriber) {
Event::subscribe($subscriber);
}
$observers = config('power.event.observers');
foreach ($observers as $observer) {
$observer::observe(ModelObserver::class);
}
}
}
但是,这样还不能使用,我们需要把这个服务添加到我们的配置文件中,在打开config/app.php,找到providers数组,把刚刚生成的服务添加上
<?php
return [
'providers' => [
...
'App\Providers\PowerServiceProvider',
...
],
];
这样服务就会自动运行了