Complete port of all 163 API endpoints from Lucee/CFML to PHP 8.3. Shared helpers in api/helpers.php (DB, auth, request/response, security). PDO prepared statements throughout. Same JSON response shapes as CFML.
181 lines
7.2 KiB
PHP
181 lines
7.2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/**
|
|
* Menu CRUD API
|
|
*
|
|
* Actions: list, get, save, delete, reorder, setDefault
|
|
* POST body: { "BusinessID": 37, "action": "list", ... }
|
|
*/
|
|
|
|
$data = readJsonBody();
|
|
$businessID = (int) ($data['BusinessID'] ?? 0);
|
|
|
|
if ($businessID === 0) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_business_id', 'MESSAGE' => 'BusinessID is required']);
|
|
}
|
|
|
|
$action = strtolower($data['action'] ?? 'list');
|
|
|
|
try {
|
|
switch ($action) {
|
|
|
|
case 'list':
|
|
$qMenus = queryTimed("
|
|
SELECT ID, Name, Description, DaysActive, StartTime, EndTime, SortOrder, IsActive
|
|
FROM Menus
|
|
WHERE BusinessID = ? AND IsActive = 1
|
|
ORDER BY SortOrder, Name
|
|
", [$businessID]);
|
|
|
|
$menus = [];
|
|
foreach ($qMenus as $m) {
|
|
$catCount = queryOne("
|
|
SELECT COUNT(*) as cnt FROM Categories
|
|
WHERE BusinessID = ? AND MenuID = ?
|
|
", [$businessID, $m['ID']]);
|
|
|
|
$menus[] = [
|
|
'MenuID' => (int) $m['ID'],
|
|
'Name' => $m['Name'],
|
|
'Description' => $m['Description'] ?? '',
|
|
'DaysActive' => (int) $m['DaysActive'],
|
|
'StartTime' => !empty($m['StartTime']) ? (new DateTime($m['StartTime']))->format('H:i') : '',
|
|
'EndTime' => !empty($m['EndTime']) ? (new DateTime($m['EndTime']))->format('H:i') : '',
|
|
'SortOrder' => (int) $m['SortOrder'],
|
|
'CategoryCount' => (int) $catCount['cnt'],
|
|
];
|
|
}
|
|
|
|
jsonResponse(['OK' => true, 'MENUS' => $menus, 'COUNT' => count($menus)]);
|
|
|
|
case 'get':
|
|
$menuID = (int) ($data['MenuID'] ?? 0);
|
|
if ($menuID === 0) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_id', 'MESSAGE' => 'MenuID is required']);
|
|
}
|
|
|
|
$menu = queryOne("SELECT * FROM Menus WHERE ID = ? AND BusinessID = ?", [$menuID, $businessID]);
|
|
if (!$menu) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'menu_not_found', 'MESSAGE' => 'Menu not found']);
|
|
}
|
|
|
|
jsonResponse(['OK' => true, 'MENU' => [
|
|
'MenuID' => (int) $menu['ID'],
|
|
'Name' => $menu['Name'],
|
|
'Description' => $menu['Description'] ?? '',
|
|
'DaysActive' => (int) $menu['DaysActive'],
|
|
'StartTime' => !empty($menu['StartTime']) ? (new DateTime($menu['StartTime']))->format('H:i') : '',
|
|
'EndTime' => !empty($menu['EndTime']) ? (new DateTime($menu['EndTime']))->format('H:i') : '',
|
|
'SortOrder' => (int) $menu['SortOrder'],
|
|
'IsActive' => (int) $menu['IsActive'],
|
|
]]);
|
|
|
|
case 'save':
|
|
$menuID = (int) ($data['MenuID'] ?? 0);
|
|
$menuName = trim($data['Name'] ?? '');
|
|
$menuDescription = trim($data['Description'] ?? '');
|
|
$menuDaysActive = (int) ($data['DaysActive'] ?? 127);
|
|
$menuStartTime = !empty($data['StartTime']) ? trim($data['StartTime']) : null;
|
|
$menuEndTime = !empty($data['EndTime']) ? trim($data['EndTime']) : null;
|
|
$menuSortOrder = (int) ($data['SortOrder'] ?? 0);
|
|
|
|
if ($menuName === '') {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_name', 'MESSAGE' => 'Menu name is required']);
|
|
}
|
|
|
|
if ($menuID > 0) {
|
|
queryTimed("
|
|
UPDATE Menus SET
|
|
Name = ?, Description = ?, DaysActive = ?,
|
|
StartTime = ?, EndTime = ?, SortOrder = ?
|
|
WHERE ID = ? AND BusinessID = ?
|
|
", [$menuName, $menuDescription, $menuDaysActive, $menuStartTime, $menuEndTime, $menuSortOrder, $menuID, $businessID]);
|
|
|
|
jsonResponse(['OK' => true, 'MenuID' => $menuID, 'ACTION' => 'updated']);
|
|
} else {
|
|
queryTimed("
|
|
INSERT INTO Menus (
|
|
BusinessID, Name, Description,
|
|
DaysActive, StartTime, EndTime,
|
|
SortOrder, IsActive, AddedOn
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, 1, NOW())
|
|
", [$businessID, $menuName, $menuDescription, $menuDaysActive, $menuStartTime, $menuEndTime, $menuSortOrder]);
|
|
|
|
$newID = (int) lastInsertId();
|
|
jsonResponse(['OK' => true, 'MenuID' => $newID, 'ACTION' => 'created']);
|
|
}
|
|
|
|
case 'delete':
|
|
$menuID = (int) ($data['MenuID'] ?? 0);
|
|
if ($menuID === 0) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_id', 'MESSAGE' => 'MenuID is required']);
|
|
}
|
|
|
|
$catCheck = queryOne("
|
|
SELECT COUNT(*) as cnt FROM Categories
|
|
WHERE MenuID = ? AND BusinessID = ?
|
|
", [$menuID, $businessID]);
|
|
|
|
if ((int) $catCheck['cnt'] > 0) {
|
|
queryTimed("
|
|
UPDATE Categories SET MenuID = 0
|
|
WHERE MenuID = ? AND BusinessID = ?
|
|
", [$menuID, $businessID]);
|
|
}
|
|
|
|
queryTimed("
|
|
UPDATE Menus SET IsActive = 0
|
|
WHERE ID = ? AND BusinessID = ?
|
|
", [$menuID, $businessID]);
|
|
|
|
jsonResponse([
|
|
'OK' => true,
|
|
'MenuID' => $menuID,
|
|
'ACTION' => 'deleted',
|
|
'CategoriesUnassigned' => (int) $catCheck['cnt'],
|
|
]);
|
|
|
|
case 'reorder':
|
|
$menuOrder = $data['MenuOrder'] ?? [];
|
|
if (!is_array($menuOrder) || count($menuOrder) === 0) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_order', 'MESSAGE' => 'MenuOrder array is required']);
|
|
}
|
|
|
|
foreach ($menuOrder as $i => $id) {
|
|
queryTimed("
|
|
UPDATE Menus SET SortOrder = ?
|
|
WHERE ID = ? AND BusinessID = ?
|
|
", [$i, (int) $id, $businessID]);
|
|
}
|
|
|
|
jsonResponse(['OK' => true, 'ACTION' => 'reordered']);
|
|
|
|
case 'setdefault':
|
|
$menuID = (int) ($data['MenuID'] ?? 0);
|
|
|
|
if ($menuID > 0) {
|
|
$check = queryOne("
|
|
SELECT ID FROM Menus WHERE ID = ? AND BusinessID = ? AND IsActive = 1
|
|
", [$menuID, $businessID]);
|
|
|
|
if (!$check) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'invalid_menu', 'MESSAGE' => 'Menu not found or not active']);
|
|
}
|
|
}
|
|
|
|
queryTimed("
|
|
UPDATE Businesses SET DefaultMenuID = ?
|
|
WHERE ID = ?
|
|
", [$menuID === 0 ? null : $menuID, $businessID]);
|
|
|
|
jsonResponse(['OK' => true, 'ACTION' => 'defaultSet', 'DefaultMenuID' => $menuID]);
|
|
|
|
default:
|
|
apiAbort(['OK' => false, 'ERROR' => 'invalid_action', 'MESSAGE' => 'Unknown action: ' . $action]);
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage(), 'DETAIL' => '']);
|
|
}
|