38571-vm/includes/store.php
Flatlogic Bot 9b7ccbdd3d versionone
2026-02-18 16:23:45 +00:00

350 lines
9.8 KiB
PHP

<?php
declare(strict_types=1);
function init_store(): void {
ensure_schema();
seed_data();
}
function ensure_schema(): void {
$pdo = db();
$pdo->exec(
'CREATE TABLE IF NOT EXISTS categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(120) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
$pdo->exec(
'CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(160) NOT NULL,
description TEXT NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
rating DECIMAL(3,2) NOT NULL DEFAULT 0.00,
category_id INT NULL,
image_url VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (category_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
$pdo->exec(
'CREATE TABLE IF NOT EXISTS orders (
id INT AUTO_INCREMENT PRIMARY KEY,
order_number VARCHAR(20) NOT NULL,
customer_name VARCHAR(120) NOT NULL,
customer_email VARCHAR(160) NOT NULL,
customer_address VARCHAR(255) NOT NULL,
status VARCHAR(30) NOT NULL,
total_price DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY (order_number)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
$pdo->exec(
'CREATE TABLE IF NOT EXISTS order_items (
id INT AUTO_INCREMENT PRIMARY KEY,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (order_id),
INDEX (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
}
function seed_data(): void {
$pdo = db();
$count = (int) $pdo->query('SELECT COUNT(*) FROM products')->fetchColumn();
if ($count > 0) {
return;
}
$categories = [
'Apparel',
'Electronics',
'Moroccan Goods'
];
$categoryStmt = $pdo->prepare('INSERT INTO categories (name) VALUES (:name)');
$categoryIds = [];
foreach ($categories as $name) {
$categoryStmt->execute([':name' => $name]);
$categoryIds[$name] = (int) $pdo->lastInsertId();
}
$products = [
[
'name' => 'Atlas Hoodie',
'description' => 'Midweight cotton hoodie with brushed interior and clean stitch detailing.',
'price' => 79.00,
'stock' => 24,
'rating' => 4.6,
'category' => 'Apparel'
],
[
'name' => 'Casablanca Sneakers',
'description' => 'Everyday sneaker with cushioned sole and minimalist profile.',
'price' => 98.00,
'stock' => 18,
'rating' => 4.4,
'category' => 'Apparel'
],
[
'name' => 'Rabat Smartwatch',
'description' => 'Slim fitness watch with sleep tracking and a 7-day battery.',
'price' => 149.00,
'stock' => 12,
'rating' => 4.2,
'category' => 'Electronics'
],
[
'name' => 'Sahara Bluetooth Speaker',
'description' => 'Portable speaker with clean bass and long-lasting battery.',
'price' => 129.00,
'stock' => 10,
'rating' => 4.3,
'category' => 'Electronics'
],
[
'name' => 'Fez Copper Lamp',
'description' => 'Hand-finished lamp with soft perforated light pattern.',
'price' => 119.00,
'stock' => 7,
'rating' => 4.8,
'category' => 'Moroccan Goods'
],
[
'name' => 'Agadir Ceramic Tagine',
'description' => 'Glazed ceramic tagine for slow cooking and elegant serving.',
'price' => 84.00,
'stock' => 9,
'rating' => 4.7,
'category' => 'Moroccan Goods'
]
];
$productStmt = $pdo->prepare(
'INSERT INTO products (name, description, price, stock, rating, category_id) VALUES (:name, :description, :price, :stock, :rating, :category_id)'
);
foreach ($products as $product) {
$productStmt->execute([
':name' => $product['name'],
':description' => $product['description'],
':price' => $product['price'],
':stock' => $product['stock'],
':rating' => $product['rating'],
':category_id' => $categoryIds[$product['category']] ?? null
]);
}
}
function get_categories(): array {
$stmt = db()->query('SELECT id, name FROM categories ORDER BY name ASC');
return $stmt->fetchAll();
}
function get_products(?string $search = null, ?int $categoryId = null, ?string $sort = null): array {
$sql = 'SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE 1=1';
$params = [];
if ($search) {
$sql .= ' AND (p.name LIKE :search OR p.description LIKE :search)';
$params[':search'] = '%' . $search . '%';
}
if ($categoryId) {
$sql .= ' AND p.category_id = :category_id';
$params[':category_id'] = $categoryId;
}
switch ($sort) {
case 'price_asc':
$sql .= ' ORDER BY p.price ASC';
break;
case 'price_desc':
$sql .= ' ORDER BY p.price DESC';
break;
default:
$sql .= ' ORDER BY p.created_at DESC';
break;
}
$stmt = db()->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
function get_product(int $id): ?array {
$stmt = db()->prepare('SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE p.id = :id');
$stmt->execute([':id' => $id]);
$product = $stmt->fetch();
return $product ?: null;
}
function format_price(float $price): string {
return '$' . number_format($price, 2);
}
function product_image_data(string $label): string {
$clean = preg_replace('/[^A-Za-z0-9]/', '', $label);
$text = strtoupper(substr($clean, 0, 2));
if ($text === '') {
$text = 'ES';
}
$svg = "<svg xmlns='http://www.w3.org/2000/svg' width='600' height='400' viewBox='0 0 600 400'><rect width='600' height='400' fill='#f1f3f6'/><text x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='Inter, Arial, sans-serif' font-size='96' fill='#111827'>" . $text . "</text></svg>";
return 'data:image/svg+xml;utf8,' . rawurlencode($svg);
}
function cart_count(): int {
$cart = $_SESSION['cart'] ?? [];
return array_sum($cart);
}
function cart_items(): array {
$cart = $_SESSION['cart'] ?? [];
if (!$cart) {
return [];
}
$ids = array_keys($cart);
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = db()->prepare(
"SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE p.id IN ($placeholders)"
);
$stmt->execute($ids);
$products = $stmt->fetchAll();
$indexed = [];
foreach ($products as $product) {
$indexed[(int) $product['id']] = $product;
}
$items = [];
foreach ($cart as $productId => $qty) {
$product = $indexed[(int) $productId] ?? null;
if (!$product) {
continue;
}
$lineTotal = ((float) $product['price']) * $qty;
$items[] = [
'product' => $product,
'quantity' => $qty,
'line_total' => $lineTotal
];
}
return $items;
}
function cart_total(): float {
$total = 0.0;
foreach (cart_items() as $item) {
$total += $item['line_total'];
}
return $total;
}
function cart_add(int $productId, int $quantity): void {
if ($quantity < 1) {
return;
}
$cart = $_SESSION['cart'] ?? [];
$cart[$productId] = ($cart[$productId] ?? 0) + $quantity;
$_SESSION['cart'] = $cart;
}
function cart_update(int $productId, int $quantity): void {
$cart = $_SESSION['cart'] ?? [];
if ($quantity < 1) {
unset($cart[$productId]);
} else {
$cart[$productId] = $quantity;
}
$_SESSION['cart'] = $cart;
}
function cart_clear(): void {
unset($_SESSION['cart']);
}
function create_order(array $customer, array $items): ?string {
if (!$items) {
return null;
}
$pdo = db();
$pdo->beginTransaction();
try {
$orderNumber = 'ES9-' . strtoupper(bin2hex(random_bytes(3)));
$total = 0.0;
foreach ($items as $item) {
$total += $item['line_total'];
}
$orderStmt = $pdo->prepare(
'INSERT INTO orders (order_number, customer_name, customer_email, customer_address, status, total_price) VALUES (:order_number, :customer_name, :customer_email, :customer_address, :status, :total_price)'
);
$orderStmt->execute([
':order_number' => $orderNumber,
':customer_name' => $customer['name'],
':customer_email' => $customer['email'],
':customer_address' => $customer['address'],
':status' => 'Processing',
':total_price' => $total
]);
$orderId = (int) $pdo->lastInsertId();
$itemStmt = $pdo->prepare(
'INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (:order_id, :product_id, :quantity, :price)'
);
foreach ($items as $item) {
$itemStmt->execute([
':order_id' => $orderId,
':product_id' => $item['product']['id'],
':quantity' => $item['quantity'],
':price' => $item['product']['price']
]);
}
$pdo->commit();
return $orderNumber;
} catch (Throwable $e) {
$pdo->rollBack();
return null;
}
}
function get_order_by_number(string $orderNumber): ?array {
$stmt = db()->prepare('SELECT * FROM orders WHERE order_number = :order_number');
$stmt->execute([':order_number' => $orderNumber]);
$order = $stmt->fetch();
return $order ?: null;
}
function get_order_items(int $orderId): array {
$stmt = db()->prepare(
'SELECT oi.*, p.name, p.description FROM order_items oi LEFT JOIN products p ON p.id = oi.product_id WHERE oi.order_id = :order_id'
);
$stmt->execute([':order_id' => $orderId]);
return $stmt->fetchAll();
}
function get_orders(): array {
$stmt = db()->query('SELECT * FROM orders ORDER BY created_at DESC');
return $stmt->fetchAll();
}
function update_order_status(int $orderId, string $status): void {
$stmt = db()->prepare('UPDATE orders SET status = :status WHERE id = :id');
$stmt->execute([':status' => $status, ':id' => $orderId]);
}