229 lines
9.4 KiB
PHP
229 lines
9.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Core\Database;
|
|
|
|
use App\Core\Config;
|
|
use PDO;
|
|
use PDOException;
|
|
|
|
class Database
|
|
{
|
|
private static ?PDO $instance = null;
|
|
|
|
public static function getConnection(): PDO
|
|
{
|
|
if (self::$instance === null) {
|
|
$connection = Config::get('DB_CONNECTION', 'sqlite');
|
|
|
|
try {
|
|
if ($connection === 'sqlite') {
|
|
$databasePath = Config::get('DB_DATABASE', __DIR__ . '/../../../storage/database.sqlite');
|
|
$dir = dirname($databasePath);
|
|
if (!is_dir($dir)) {
|
|
mkdir($dir, 0777, true);
|
|
}
|
|
|
|
self::$instance = new PDO("sqlite:{$databasePath}", null, null, [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
]);
|
|
|
|
self::$instance->exec('PRAGMA foreign_keys = ON;');
|
|
} else {
|
|
$host = Config::get('DB_HOST', '127.0.0.1');
|
|
$port = Config::get('DB_PORT', '3306');
|
|
$database = Config::get('DB_DATABASE', 'order_system');
|
|
$username = Config::get('DB_USERNAME', 'root');
|
|
$password = Config::get('DB_PASSWORD', '');
|
|
|
|
$dsn = "mysql:host={$host};port={$port};dbname={$database};charset=utf8mb4";
|
|
self::$instance = new PDO($dsn, $username, $password, [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
]);
|
|
}
|
|
} catch (PDOException $e) {
|
|
die('Database Connection Error: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Initializes database tables and seed data for the Collaborative Canteen Ordering System
|
|
*/
|
|
public static function initSchema(): void
|
|
{
|
|
$db = self::getConnection();
|
|
$isSqlite = Config::get('DB_CONNECTION', 'sqlite') === 'sqlite';
|
|
|
|
// Auto-migration check: If old schema exists without user_id / creator_id, drop old tables
|
|
if ($isSqlite) {
|
|
$checkTable = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='employee_orders'")->fetchColumn();
|
|
if ($checkTable) {
|
|
$columns = $db->query("PRAGMA table_info(employee_orders)")->fetchAll();
|
|
$hasUserId = false;
|
|
foreach ($columns as $col) {
|
|
if ($col['name'] === 'user_id') {
|
|
$hasUserId = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$hasUserId) {
|
|
$db->exec("DROP TABLE IF EXISTS employee_order_items;");
|
|
$db->exec("DROP TABLE IF EXISTS employee_orders;");
|
|
$db->exec("DROP TABLE IF EXISTS session_menus;");
|
|
$db->exec("DROP TABLE IF EXISTS daily_sessions;");
|
|
$db->exec("DROP TABLE IF EXISTS employees;");
|
|
$db->exec("DROP TABLE IF EXISTS users;");
|
|
$db->exec("DROP TABLE IF EXISTS orders;");
|
|
$db->exec("DROP TABLE IF EXISTS order_items;");
|
|
$db->exec("DROP TABLE IF EXISTS products;");
|
|
$db->exec("DROP TABLE IF EXISTS customers;");
|
|
}
|
|
}
|
|
}
|
|
|
|
$autoIncrement = $isSqlite ? 'AUTOINCREMENT' : 'AUTO_INCREMENT';
|
|
$dateTimeDefault = $isSqlite ? "DATETIME DEFAULT (datetime('now', 'localtime'))" : 'DATETIME DEFAULT CURRENT_TIMESTAMP';
|
|
|
|
// Users Table
|
|
$db->exec("
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY {$autoIncrement},
|
|
name VARCHAR(255) NOT NULL,
|
|
username VARCHAR(100) NOT NULL UNIQUE,
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
created_at {$dateTimeDefault}
|
|
);
|
|
");
|
|
|
|
// Daily Sessions Table
|
|
$db->exec("
|
|
CREATE TABLE IF NOT EXISTS daily_sessions (
|
|
id INTEGER PRIMARY KEY {$autoIncrement},
|
|
creator_id INTEGER NOT NULL,
|
|
session_date DATE NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
canteen_name VARCHAR(255) NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'open',
|
|
notes TEXT DEFAULT NULL,
|
|
created_at {$dateTimeDefault},
|
|
updated_at {$dateTimeDefault},
|
|
FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
");
|
|
|
|
// Session Menus Table
|
|
$db->exec("
|
|
CREATE TABLE IF NOT EXISTS session_menus (
|
|
id INTEGER PRIMARY KEY {$autoIncrement},
|
|
session_id INTEGER NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
final_price DECIMAL(10,2) DEFAULT 0.00,
|
|
created_at {$dateTimeDefault},
|
|
FOREIGN KEY (session_id) REFERENCES daily_sessions(id) ON DELETE CASCADE
|
|
);
|
|
");
|
|
|
|
// Employee Orders Table
|
|
$db->exec("
|
|
CREATE TABLE IF NOT EXISTS employee_orders (
|
|
id INTEGER PRIMARY KEY {$autoIncrement},
|
|
session_id INTEGER NOT NULL,
|
|
user_id INTEGER NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'unpaid',
|
|
notes TEXT DEFAULT NULL,
|
|
total_bill DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
|
created_at {$dateTimeDefault},
|
|
updated_at {$dateTimeDefault},
|
|
FOREIGN KEY (session_id) REFERENCES daily_sessions(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
");
|
|
|
|
// Employee Order Items Table
|
|
$db->exec("
|
|
CREATE TABLE IF NOT EXISTS employee_order_items (
|
|
id INTEGER PRIMARY KEY {$autoIncrement},
|
|
employee_order_id INTEGER NOT NULL,
|
|
session_menu_id INTEGER DEFAULT NULL,
|
|
item_name VARCHAR(255) NOT NULL,
|
|
quantity INTEGER NOT NULL DEFAULT 1,
|
|
unit_price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
|
total_price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
|
notes VARCHAR(255) DEFAULT NULL,
|
|
created_at {$dateTimeDefault},
|
|
FOREIGN KEY (employee_order_id) REFERENCES employee_orders(id) ON DELETE CASCADE
|
|
);
|
|
");
|
|
|
|
// Check if seed data exists
|
|
$stmt = $db->query("SELECT COUNT(*) FROM users");
|
|
$count = (int)$stmt->fetchColumn();
|
|
|
|
if ($count === 0) {
|
|
self::seedInitialData($db);
|
|
}
|
|
}
|
|
|
|
private static function seedInitialData(PDO $db): void
|
|
{
|
|
$hash = password_hash('password', PASSWORD_DEFAULT);
|
|
|
|
// Seed Users
|
|
$users = [
|
|
['Dea (Coordinator)', 'dea', 'dea@company.com', $hash],
|
|
['Alex Turner', 'alex', 'alex@company.com', $hash],
|
|
['Sarah Jenkins', 'sarah', 'sarah@company.com', $hash],
|
|
['Budi Santoso', 'budi', 'budi@company.com', $hash],
|
|
['Michael Chen', 'michael', 'michael@company.com', $hash],
|
|
];
|
|
|
|
$stmtUser = $db->prepare("INSERT INTO users (name, username, email, password_hash) VALUES (?, ?, ?, ?)");
|
|
foreach ($users as $u) {
|
|
$stmtUser->execute($u);
|
|
}
|
|
|
|
// Seed Today's Session created by Dea (id = 1)
|
|
$today = date('Y-m-d');
|
|
$title = "Dea's Lunch Hub - Kantin Bu Siti";
|
|
$stmtSession = $db->prepare("INSERT INTO daily_sessions (creator_id, session_date, title, canteen_name, status, notes) VALUES (1, ?, ?, 'Kantin Bu Siti', 'open', 'Please submit your lunch orders before 11:30 AM!')");
|
|
$stmtSession->execute([$today, $title]);
|
|
$sessionId = (int)$db->lastInsertId();
|
|
|
|
// Seed Menu Items
|
|
$menuItems = [
|
|
'Ayam Bakar Madu + Nasi',
|
|
'Ayam Geprek Sambal Bawang + Nasi',
|
|
'Nasi Goreng Spesial',
|
|
'Mie Goreng Seafood',
|
|
'Soto Ayam Lamongan + Nasi',
|
|
'Gado-Gado Lontong',
|
|
'Tahu & Tempe Goreng (Extra)',
|
|
'Es Teh Manis',
|
|
'Es Jeruk Segar',
|
|
];
|
|
|
|
$stmtMenu = $db->prepare("INSERT INTO session_menus (session_id, name, final_price) VALUES (?, ?, 0.00)");
|
|
foreach ($menuItems as $item) {
|
|
$stmtMenu->execute([$sessionId, $item]);
|
|
}
|
|
|
|
// Seed an order for Alex (user_id = 2)
|
|
$stmtOrder = $db->prepare("INSERT INTO employee_orders (session_id, user_id, status, notes, total_bill) VALUES (?, 2, 'unpaid', 'Pedas sedang ya', 0.00)");
|
|
$stmtOrder->execute([$sessionId]);
|
|
$alexOrderId = (int)$db->lastInsertId();
|
|
|
|
$stmtItem = $db->prepare("INSERT INTO employee_order_items (employee_order_id, session_menu_id, item_name, quantity, unit_price, total_price, notes) VALUES (?, ?, ?, ?, 0.00, 0.00, ?)");
|
|
$stmtItem->execute([$alexOrderId, 1, 'Ayam Bakar Madu + Nasi', 1, 'Pedas sedang']);
|
|
$stmtItem->execute([$alexOrderId, 8, 'Es Teh Manis', 1, 'Kurang manis / less sugar']);
|
|
}
|
|
}
|