Návrhový vzor DB pro košík na e-shopu
- Dan Hundrt
- Člen | 74
Zdravím,
rád bych se Vás zeptal, jak by jste řešili návrhový vzor u košíku. Mám to zatím navržené takto:
1) Mám tabulku ‚products‘, ve které jsou produkty (sloupce: id, title, price, slug, … atd)
- Dále tabulku ‚basket‘, do které se zapisují produkty, které si přidám do košíku (sloupce: id, product_id (reference na id produktu), a hash, který vygeneruje eshop pro daného uživatele při vstupu na stránky).
Až sem je to snad ok, nicméně řeším jak dále. Po odeslání objednávky bych nyní vytvořil v tabulce ‚order‘ odběratele a odesílatele + ostatní info a překopíroval produkty z tabulky ‚basket‘, do tabulky ‚order_products‘ s referencní na ‚order‘.
Myslíte, že je to takto ok?
Děkuji
- Dan Hundrt
- Člen | 74
Zdravím,
postoupil jsem dále a mám vše prakticky hotové a vše funguje. Nyní mám tedy logiku následující:
- tabulku order (číslo objednávky, stav objednávky, hash) s vazbami na tabulku subscribers (údaje o zákazníkovi, jméno, tel. …), order_pay (název a cena platby), order_delivery (název a cena dopravy)
- tabulku subscribers s vazbou na subscribers_delivery (adresa pro doručení) a ** subscribers_delivery** (adresa pro doručení pro firmu).
Je toho poměrně dost, jenom model má poměrně dost metod (posílám níže aktuální kód). Celé je to v podstatě dělané, aby objednávka byla na 100% neměnná, pokud se mění cena produktů, nastavení plateb a doručení.
Kód logicky postupuje následovně:
- v metodě saveSubscriber() se uloží data do tabulky subscribers (jméno, přijímení, email, tel. zákazníka) + z nastavení e-shopu se vytáhne typ platby a doručení a uloží se obojí do (saveSubscriber()), (savePay()).
- V metodě saveSubscriber() se poté zavolá metoda saveOrderInterbankTable() a v parametrech se předá ID zákazníka, ID platby a ID doručení a hash (random string).
- V metodě saveOrderInterbankTable() se zavolá metoda saveProducts() ve které se vytáhnou produkty z produktové databáze a vloží se do tabulky s produkty pro danou objednávku.
Celé je to poměrně složité, říkám si, že bych to mohl celé zjednodušit a tabulky pro zákazníka spojit (tj. mít to celé v jedné tabulce, to samé u typ platby a doručení, vložit to přímo k objednávce).
Nevíte jaký je správný přístup s ohledem na pozdější škálování?
Děkuji
<?php
namespace App\Model;
use App\Providers\UserProvider;
use Nette\Database\Context;
use Nette\Utils\Random;
class OrderModel
{
/** Order status */
const STATUS_NEW = 1;
const STATUS_SEND = 2;
/** @var CartModel */
private $cartModel;
/** @var ProductModel */
private $productModel;
/** @var UserProvider */
private $userProvider;
/** @var Context */
public $database;
public function __construct(
CartModel $cartModel,
ProductModel $productModel,
Context $database,
UserProvider $userProvider)
{
$this->cartModel = $cartModel;
$this->productModel = $productModel;
$this->database = $database;
$this->userProvider = $userProvider;
}
/**
* @inheritdoc Get all order
* @return array
*/
public function getAllOrder($limit = 40): array
{
$data = $this->database->table('order')->limit($limit)->order('id DESC')->fetchAll();
$result = [];
foreach ($data as $item) {
$subscribers = $item->ref('subscribers')->toArray();
$result[] = [
'order' => $item->toArray(),
'subscribers' => $subscribers,
];
}
return $result;
}
/**
* @inheritdoc Get detail order with all data
* @param int $id
* @return array
*/
public function getDetailOrder(int $id): array
{
$order = $this->database->table('order')->get($id);
$products = $this->database->table('order_products')->where(['order_id' => $order['id']])->fetchAll();
$subscriber = $this->database->table('subscribers')->where(['id' => $order['subscribers_id']])->fetch();
$subscriberDelivery = $this->database->table('subscribers_delivery')->where(['id' => $subscriber['delivery_id']])->fetch();
$company = $this->database->table('subscribers_company')->where(['id' => $subscriber['company_id']])->fetch();
$delivery = $this->database->table('order_delivery')->where(['id' => $order['delivery_id']])->fetch();
$pay = $this->database->table('order_pay')->where(['id' => $order['pay_id']])->fetch();
return [
'order' => $order,
'products' => $products,
'subscriber' => $subscriber,
'subscriberDelivery' => $subscriberDelivery,
'delivery' => $delivery,
'pay' => $pay,
'subscriberCompany' => $company,
'totalPrice' => $this->getTotalPrice($products)
];
}
/**
* @inheritdoc Get
* @param string $hash
* @return mixed
*/
public function getOrderIDFromHash(string $hash)
{
return $this->database->table('order')->where(['hash' => $hash])->fetch();
}
/**
* @inheritdoc Generate hash order
* @return string
*/
public function generateHash(): string
{
return Random::generate(65);
}
/**
* @inheritdoc Get order total price
* @param array $products
* @return bool|float|int
*/
public function getTotalPrice(array $products)
{
if (!isset($products)) {
return FALSE;
}
$sum = [];
foreach ($products as $item) {
$sum[] += $item['price'] * $item['stock'];
}
return array_sum($sum);
}
/**
* @inheritdoc Save order
* @param $data
* @param string $hash
* @return int
*/
public function saveOrder($data, string $hash)
{
if ($this->saveSubscriber($data, $hash)) {
return TRUE; //$this->cartModel->flushCart();
}
}
/**
* @param $value
* @param string $hash
* @return bool|int|\Nette\Database\Table\ActiveRow
* @throws \Exception
*/
public function saveSubscriber($value, string $hash)
{
$subscriber = [
'date' => new \DateTime(),
'name' => $value['name'],
'surname' => $value['surname'],
'email' => $value['email'],
'phone' => $value['phone'],
'delivery_id' => $this->saveSubscriberDelivery($value),
'company_id' => $this->saveCompany($value)
];
$subscribersId = $this->database->table('subscribers')->insert($subscriber)->id;
$deliveryId = $this->saveDelivery($value);
$payId = $this->savePay($value);
return $this->saveOrderInterbankTable($subscribersId, $deliveryId, $payId, $hash);
}
/**
* @inheritdoc Save delivery
* @param $value
* @return mixed|\Nette\Database\Table\ActiveRow
*/
public function saveDelivery($value)
{
$data = $this->database->table('delivery')->get($value['delivery']);
$insert = [
'title' => $data['title'],
'price' => $data['price'],
];
return $this->database->table('order_delivery')->insert($insert)->id;
}
/**
* @inheritdoc Save pay
* @param $value
* @return mixed|\Nette\Database\Table\ActiveRow
*/
public function savePay($value)
{
$data = $this->database->table('pay')->get($value['pay']);
$insert = [
'title' => $data['title'],
'price' => $data['price'],
];
return $this->database->table('order_pay')->insert($insert)->id;
}
/**
* @inheritdoc Save subscriber delivery
* @param $value
* @return mixed|\Nette\Database\Table\ActiveRow
* @throws \Exception
*/
public function saveSubscriberDelivery($value)
{
$subscriberDelivery = [
'date' => new \DateTime(),
'city' => $value['city'],
'street' => $value['street'],
'postalcode' => $value['postalcode'],
];
return $this->database->table('subscribers_delivery')->insert($subscriberDelivery)->id;
}
/**
* @inheritdoc Save company to table
* @param $value
* @return mixed|\Nette\Database\Table\ActiveRow|null
* @throws \Exception
*/
public function saveCompany($value)
{
if (!$value['use_company']) {
return NULL;
}
$company = [
'date' => new \DateTime(),
'company' => $value['company'],
'ic' => $value['ic'],
'dic' => $value['dic'],
];
return $this->database->table('subscribers_company')->insert($company)->id;
}
/**
* @inheritdoc Insert data to interbank table (order)
* @param int $id
* @param int $delivery
* @param int $pay
* @param string $hash
* @return bool|int|\Nette\Database\Table\ActiveRow
* @throws \Exception
*/
public function saveOrderInterbankTable(int $id, ?int $delivery, ?int $pay, string $hash)
{
$data = [
'subscribers_id' => $id,
'delivery_id' => $delivery,
'pay_id' => $pay,
'status' => self::STATUS_NEW,
'hash' => $hash
];
return $this->saveProducts($this->database->table('order')->insert($data)->id);
}
/**
* @inheritdoc Save product to table
* @param $id
* @return bool|int|\Nette\Database\Table\ActiveRow
* @throws \Exception
*/
public function saveProducts($id)
{
$user = $this->userProvider->getUserCookie();
$data = $this->database->table('cart')->where(['user' => $user])->fetchAll();
$result = [];
foreach ($data as $product) {
$cart = $product->toArray();
$product = $product->ref('product')->toArray();
$result[] = [
'stock' => $cart['count'],
'price' => $product['price'],
'title' => $product['title'],
'product_id' => $product['id'],
'date' => new \DateTime(),
'order_id' => $id,
];
}
return $this->database->table('order_products')->insert($result);
}
}