Laravel 資料表按月份水平分表,表不存在,自動建立生成

gyp719發表於2023-03-15

說明:建立表的時候需要進行判斷,如果表存在,則不需要建立。這個程式碼會被多次使用並可以重複使用,選擇寫成trait,實現分表後的增刪改查操作和分表前一樣,但預設是對當前月份進行增刪改查。

trait:

<?php

namespace App\Models\Traits;

use Carbon\Carbon;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

trait SplitTableTrait
{
    /**
     * 是否分表,預設false,即不分表
     * @var bool
     */
    protected $isSplitTable = true;

    /**
     * 最終生成表
     * @var
     */
    protected $endTable;

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

    /**
     * 初始化
     * @param  array  $attributes
     * @param $suffix
     * @return void
     */
    public function init(array $attributes = [], $suffix = null)
    {
        $this->endTable = $this->table;

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

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

        if ($this->suffix !== null) {
            // 最終表替換模型中宣告的表作為分表使用的表
            $this->table = $this->endTable.'_'.$this->suffix;
        }

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

    /**
     * 提供一個靜態方法設定表字尾
     * @param $suffix
     * @return mixed
     */
    public static function suffix($suffix = null)
    {
        $instance = new static;
        $instance->setSuffix($suffix);

        return $instance->newQuery();
    }

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

        return $model;
    }

    /**
     * 建立分表,沒有則建立,有則不處理
     * @return void
     */
    protected function createTable()
    {
        $connectName = $this->getConnectionName();

        // 初始化分表,,按年月分表格式為:orders_202205
        if (!Schema::connection($connectName)->hasTable($this->table)) {
            Schema::connection($connectName)->create($this->table, function (Blueprint $table) {
                $table->id();
                $table->dateTime('pay_at')->comment('交易時間');
                $table->string('appid')->comment('公眾賬號ID');
                $table->string('mch_id')->comment('商戶號');
                $table->string('sub_mch_id')->nullable()->comment('特約商戶號');
                $table->string('device_info')->nullable()->comment('裝置號');
                $table->string('transaction_id')->comment('微信訂單號');
                $table->string('out_trade_no')->comment('商戶訂單號');
                $table->string('openid')->comment('使用者標識');
                $table->string('trade_type')->comment('交易型別');
                $table->string('pay_status')->comment('交易狀態');
                $table->string('bank_type')->comment('付款銀行');
                $table->string('fee_type')->comment('貨幣種類');
                $table->decimal('settlement_total_fee', 10, 2)->comment('應結訂單金額');
                $table->decimal('coupon_fee', 10, 2)->comment('代金券金額');
                $table->string('refund_id')->comment('微信退款單號');
                $table->string('out_refund_no')->comment('商戶退款單號');
                $table->decimal('refund_fee', 10, 2)->comment('退款金額');
                $table->decimal('coupon_refund_fee', 10, 2)->comment('充值券退款金額');
                $table->string('refund_type')->nullable()->comment('退款型別');
                $table->string('refund_status')->nullable()->comment('退款狀態');
                $table->string('body')->comment('商品名稱');
                $table->string('attach', 1000)->nullable()->comment('商戶資料包');
                $table->decimal('service_charge', 10, 2)->comment('手續費');
                $table->string('rate')->comment('費率');
                $table->decimal('total_fee', 10, 2)->comment('訂單金額');
                $table->decimal('apply_refund_fee', 10, 2)->comment('申請退款金額');
                $table->string('rate_remark')->nullable()->comment('費率備註');
                $table->timestamps();
            });
        }
    }
}

模型使用trait:(任何模型都可使用這個trait進行按月分表)

<?php

namespace App\Models;

use App\Models\Traits\SplitTableTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class WechatBill extends Model
{
    use HasFactory;

    use SplitTableTrait;

    protected $table = 'wechat_bill';

    protected $guarded = [];

    public function __construct(array $attributes = [], $suffix = null)
    {
        // 初始化分表處理
        $this->init($attributes, $suffix);

        parent::__construct($attributes);
    }

}

效果:

Laravel  資料表按月份水平分表,表不存在,自動建立生成

分表查詢示例

$wechatBill = new WechatBill();
$wechatBill->setSuffix(202303);
return $wechatBill->newQuery()->get();

分表寫入

  return (new WechatBill([], 202303))->newInstance()->create([]);
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章