PHP新手30天實戰金流
, Laravel6
參考此平台架構概觀, 測試範例試跑
一個購物平台主要的三個 Model:
產生兩張 table (products, product_skus) 來管理。
Product
:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('description');
$table->string('image');
$table->boolean('on_sale')->default(true);
$table->float('rating')->default(5);
$table->unsignedInteger('sold_count')->default(0);
$table->unsignedInteger('review_count')->default(0);
$table->decimal('price', 10, 2);
$table->timestamps();
});
public function skus()
{
return $this->hasMany(ProductSku::class);
}
ProductSku
: Stock Keeping Unit,簡稱SKU,定義為保存庫存控制的最小可用單位
Schema::create('product_skus', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('description');
$table->decimal('price', 10, 2);
$table->unsignedInteger('stock');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->timestamps();
});
ProductSkuAttribute
: 商品屬性-規格大小顏色
Schema::create('product_sku_attributes', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('items');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->timestamps();
});
產生兩張 table (orders, order_iterms) 來管理。
Order
: 沒有任何商品資訊
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('no')->unique();
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->text('address');
$table->decimal('total_amount', 10, 2);
$table->text('remark')->nullable();
$table->dateTime('paid_at')->nullable();
$table->string('payment_method')->nullable();
$table->string('payment_no')->nullable();
$table->string('refund_status')->default(\App\Models\Order::REFUND_STATUS_PENDING);
$table->string('refund_no')->unique()->nullable();
$table->boolean('closed')->default(false);
$table->boolean('reviewed')->default(false);
$table->string('ship_status')->default(\App\Models\Order::SHIP_STATUS_PENDING);
$table->text('ship_data')->nullable();
$table->text('extra')->nullable();
$table->timestamps();
});
OrderItem
:
Schema::create('order_items', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('order_id');
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->unsignedInteger('product_sku_id');
$table->foreign('product_sku_id')->references('id')->on('product_skus')->onDelete('cascade');
$table->unsignedInteger('amount');
$table->decimal('price', 10, 2);
$table->unsignedInteger('rating')->nullable();
$table->text('review')->nullable();
$table->timestamp('reviewed_at')->nullable();
});
cart_items
:Schema::create('cart_items', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedInteger('product_sku_id');
$table->foreign('product_sku_id')->references('id')->on('product_skus')->onDelete('cascade');
$table->unsignedInteger('amount');
});
User
Product
@foreach($product->attrs as $attr_index => $attr)
Product_sku
-- 好像沒有用到的函式 getAttrsAttribute --
public function getAttrsAttribute()
{
$attrs = $this->product->attrs;
$attr_items_index = json_decode($this->attr_items_index, true);
return collect($attr_items_index)->mapWithKeys(function ($item_index, $index) use ($attrs) {
$attr = $attrs->get($index);
return [$attr->name => $attr->items[$item_index]];
});
}
function ($item_index, $index) use ($attrs) {
$attr = $attrs->get($index);
return [$attr->name => $attr->items[$item_index]];
}
Order
public function user()
{
return $this->belongsTo(User::class);
}
protected static function boot()
{
parent::boot();
// 監聽模型建立事件,在寫入 DB之前觸發
static::creating(function ($model) {
// 如果模型的 no 字段为空
if (!$model->no) {
// 調用 findAvailableNo 生成訂單流水號
$model->no = static::findAvailableNo();
// 如果失敗,則终止建立訂單
if (!$model->no) {
return false;
}
}
});
}
OrderItem
CartItem
將資料在 DB 儲存的型態轉換成一般較通用的型態,方便操作。
Cart
Orders
public function store(OrderRequest $request, OrderService $orderService)
{
$user = $request->user();
$address = UserAddress::find($request->input('address_id'));
$currency_code="THB";
return $orderService->store($user, $address, $request->input('remark'), $request->input('items'),$currency_code);
}
猜...處理資料庫事務程式碼太多, 不宜放在高層
Payment
Products
index
show
favor
disfavor
favorites
show product 會去撈出該商品的27種規格的庫存:
$skus = $product->skus->map(function ($sku) {
return [
'id' => $sku->id,
'price' => $sku->price,
'stock' => $sku->stock,
'attr_items_index' => json_decode($sku->attr_items_index, true),
];
});
dd($skus);
php test.php
會回傳測試用的付款畫面