源码Illuminate\Database\Eloquent\Model中bootTraits方法可以自定义模型启动后做一些处理
protected static function bootTraits(){$class = static::class;$booted = [];static::$traitInitializers[$class] = [];foreach (class_uses_recursive($class) as $trait) {$method = 'boot'.class_basename($trait);//关键语句if (method_exists($class, $method) && ! in_array($method, $booted)) {forward_static_call([$class, $method]);$booted[] = $method;}if (method_exists($class, $method = 'initialize'.class_basename($trait))) {static::$traitInitializers[$class][] = $method;static::$traitInitializers[$class] = array_unique(static::$traitInitializers[$class]);}}}
实现步骤
一 注册模型启动任务
trait FieldLogTrait{public static function bootFieldLogTrait(){static::saved(function ($model) {$_model = clone $model;$_model->relations = [];FieldLog::addEvent(function () use ($_model) {return $_model->changedRevisionableFields();});});static::deleted(function ($model) {$_model = clone $model;$_model->relations = [];FieldLog::addEvent(function () use ($_model) {return $_model->changedRevisionableFields();});});}private function changedRevisionableFields(){$changes_to_record = [];$dirtyData = $this->getDirty();$originalData = $this->original;$updatedData = $this->attributes;$table = $this->getTable();$row_id = $this->getKey();foreach ($dirtyData as $key => $value) {if (!isset($originalData[$key]) || $originalData[$key] != $updatedData[$key]) {$old_value = array_get($originalData, $key);$changes_to_record[] = ['table' => $table,'row_id' => $row_id,'key' => $key,'old_value' => !empty($old_value) ? $old_value : '','new_value' => $updatedData[$key],];}}return $changes_to_record;}
二 字段变动收集
<?phpnamespace App\Foundation\FieldLog;use App\Foundation\RequestID\RequestID;use App\Foundation\RequestID\ResID;use Carbon\Carbon;use Illuminate\Support\Facades\App;use Illuminate\Support\Facades\DB;use Illuminate\Support\Facades\Log;use function MongoDB\select_server;class FieldLogHandler{/*** 是否保存* @var bool*/public $canStore = true;/*** 保存请求之后执行的动作* @var array*/public $events = [];/*** 保存修改记录*/public function store(){if ($this->canStore) {try {if (!empty($this->events)) {$data = [];//执行并合并所有结果foreach ($this->events as $event) {$results = call_user_func($event);if (!empty($results)) {foreach ($results as $result) {$data[] = $result;}}}//保存结果if (!empty($data)) {if (count($data) > 20) {//防止insert过长$lists = array_chunk($data, 20);foreach ($lists as $list) {$this->insert($list);}} else {$this->insert($data);}}}} catch (\Exception $exception) {}}}/*** 业务完成之后执行的回调* @param callable $fn*/public function addEvent(callable $fn){$this->events[] = $fn;}/*** 跳过持久化*/public function skip(){$this->canStore = false;}public function insert($data){if (!empty($data)) {$time = Carbon::now()->toDateTimeString();$requestId = ResID::get();foreach ($data as $key => $item) {$data[$key]['request_id'] = $requestId;$data[$key]['created_at'] = $time;$data[$key] = array_merge($data[$key], $this->extra);}event(new FieldChangeEvent($data));}}}
三 持久化
创建事件监听器处理FieldChangeEvent事件即可
