[實戰]laravel 利用trait實現中介軟體指定資料庫按月份水平分表記錄系統日誌

my38778570發表於2022-08-02
php artisan make:model SystemTraceRecords -m
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateSystemTraceRecordsTable extends Migration
{
    protected $connection = 'xiongge_log';

    public function up()
    {
        Schema::create('system_trace_records', function (Blueprint $table) {
            $table->id();
            $table->foreignId('users_id')->index()->default(0)->comment('使用者id');
            $table->json('data')->nullable()->comment('data');
            $table->string('method')->nullable()->comment('method');
            $table->string('secure')->nullable()->comment('secure');
            $table->string('path')->nullable()->comment('path');
            $table->string('uri')->nullable()->comment('uri');
            $table->string('response')->nullable()->comment('response');
            $table->string('status')->nullable()->comment('status');
            $table->timestamps();
        });
         \DB::statement("ALTER TABLE `xg_system_trace_records` comment '系統跟蹤記錄'");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('system_trace_records');
    }
}
<?php

namespace App\Models;

use App\Traits\SubmeterTraits;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use DateTimeInterface;


class SystemTraceRecords extends Model
{
    use HasFactory, SubmeterTraits;

    protected $connection = "xiongge_log";

    protected $guarded = [];

    protected $table = "system_trace_records";

    protected $primaryKey = 'id';

    protected $prefix = 'xg_';

    protected $casts = [
        'created_at' => 'datetime:Y-m-d H:i',
        'updated_at' => 'datetime:Y-m-d H:i',
    ];

    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    protected $columns;

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        // 初始化分表處理
        $this->init();
    }
}
<?php

namespace App\Traits;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

trait SubmeterTraits
{
    //是否分表,預設false,即不分表
    protected $isSplitTable = true;

    //原表
    public $originTable;

    //表
    public $endTable;

    /**
     * 字尾引數
     * @var string
     */
    protected $suffix = null;

    /**
     * 年月引數:202104
     * @var string
     */
    public $ym;

    public function init(array $attributes = [], $suffix = null)
    {
        //預設原表
        $this->originTable = $this->table;
        //預設最終表
        $this->endTable = $this->table;

        $this->ym = Carbon::now()->format('Ym');

        //isSplitTable引數為true時進行分表,否則不分表
        if ($this->isSplitTable) {
            //初始化字尾,未傳則預設年月分表
            $this->suffix = $suffix ?: $this->ym;
        }
        //初始化分表表名並建立
        $this->setSuffix();
    }

    /**
     * 設定表字尾, 如果設定分表字尾,可在service層呼叫生成自定義字尾表名,
     * 但每次操作表之前都需要呼叫該方法以保證資料表的準確性
     * @param $suffix
     */
    public function setSuffix($suffix = null)
    {
        //isSplitTable引數為true時進行分表,否則不分表
        if ($this->isSplitTable) {
            //初始化字尾,未傳則預設年月分表
            $this->suffix = $suffix ?: $this->ym;
        }
        if ($this->suffix !== null) {
            //$this->endTable = $this->getTable() . '_' . $suffix;
            $this->endTable = $this->originTable . '_' . $this->suffix;

            //最終表替換模型中宣告的表作為分表使用的表
            $this->table = $this->endTable;
        }
        //呼叫時,建立分表,格式為 table_{$suffix}
        //未傳自定義字尾情況下,,預設按年月分表格式為:orders_202205
        //無論使用時是否自定義分表名,都會建立預設的分表,除非關閉該呼叫
        $this->createTable();
    }

    /**
     * 提供一個靜態方法設定表字尾
     * @param string $suffix
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function suffix($suffix = null)
    {
        $instance = new static;
        $instance->setSuffix($suffix);
        return $instance->newQuery();
    }

    /**
     * 建立新的"table_{$suffix}"的模型例項並返回
     * @param array $attributes
     * @param bool $exists
     * @return object $model
     */
    public function newInstance($attributes = [], $exists = false)
    {
        $model = parent::newInstance($attributes, $exists);
        $model->setSuffix($this->suffix);
        return $model;
    }

    /**
     * 建立分表,沒有則建立,有則不處理
     */
    protected function createTable()
    {
        info("createTable===============", [Schema::connection($this->connection)->hasTable($this->endTable)]);
        //初始化分表,,按年月分表格式為:orders_202205
        if (!Schema::connection($this->connection)->hasTable($this->endTable)) {
            info("建立表==========", [$this->endTable]);
            DB::connection($this->connection)->update("create table {$this->prefix}{$this->endTable} like {$this->prefix}{$this->originTable}");
        }
    }

}
php artisan make:middleware SystemTraceRecords
protected $routeMiddleware = [
    'systemTraceRecords' => \App\Http\Middleware\SystemTraceRecords::class,
];
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class SystemTraceRecords
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);
        if ($request->getMethod() != "POST") return $response;
        \App\Models\SystemTraceRecords::query()->create(
            [
                'users_id' => Auth::id() ?? 0,
                'data' => json_encode($request->all(), JSON_UNESCAPED_UNICODE),
                'method' => $request->getMethod(),
                'secure' => $request->getScheme(),
                'uri' => $request->getRequestUri(),
                'path' => $request->path(),
//            'response' => $response->getContent() ?: '',
                'status' => $response->getStatusCode()
            ]
        );
        return $response;
    }
}

laravel 實現指定資料庫按月份水平分表

laravel 8實現 訂單表按月份水平分表
PHP trait的使用和詳解

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章