- Fix item edit template with proper form structure - Update items template with correct Bootstrap classes - Fix Apache configuration for proper routing - Update main index.php for correct redirects - Improves UI consistency and navigation flow
176 lines
8.4 KiB
PHP
Executable File
176 lines
8.4 KiB
PHP
Executable File
<?php
|
|
|
|
$autoloadPath = __DIR__ . '/../vendor/autoload.php';
|
|
if (!file_exists($autoloadPath)) {
|
|
http_response_code(500);
|
|
die("FATAL ERROR: Composer autoloader not found. Please run 'composer install' in the project root.");
|
|
}
|
|
require $autoloadPath;
|
|
|
|
require __DIR__ . '/../config.php';
|
|
|
|
use App\Router;
|
|
use App\Controllers\ItemController;
|
|
use App\Controllers\CategoryController;
|
|
use App\Database;
|
|
use App\Models\Category;
|
|
|
|
// Initialize Database (ensures tables exist)
|
|
Database::getInstance();
|
|
|
|
$router = new Router();
|
|
|
|
// --- Language Switch Route ---
|
|
$router->addRoute('GET', '/lang/{locale}', function ($locale) {
|
|
if (in_array($locale, SUPPORTED_LOCALES)) {
|
|
$_SESSION['locale'] = $locale;
|
|
}
|
|
// Redirect back to the page the user came from, or home
|
|
$referer = $_SERVER['HTTP_REFERER'] ?? '/';
|
|
header("Location: " . $referer);
|
|
exit;
|
|
});
|
|
|
|
// --- Web Routes (Full Page/Initial Load) ---
|
|
$router->addRoute('GET', '/', [ItemController::class, 'overview']);
|
|
$router->addRoute('GET', '/categories', [CategoryController::class, 'index']);
|
|
$router->addRoute('GET', '/parts', [ItemController::class, 'addForm']);
|
|
$router->addRoute('GET', '/print/{id:\d+}', [ItemController::class, 'printQR']);
|
|
|
|
// --- API Routes (AJAX Content) ---
|
|
// These routes return only the Twig block content, not the full layout.
|
|
$router->addRoute('GET', '/api/items', [ItemController::class, 'listItems']);
|
|
$router->addRoute('GET', '/api/items/{id:\d+}', [ItemController::class, 'getItem']);
|
|
$router->addRoute('GET', '/api/categories/list', [CategoryController::class, 'listCategoriesJson']);
|
|
$router->addRoute('GET', '/api/categories/{id}', [CategoryController::class, 'getCategory']);
|
|
|
|
// Categories with optional filter
|
|
$router->addRoute('GET', '/api/categories', function() {
|
|
$categoryId = $_GET['category'] ?? null;
|
|
if ($categoryId) {
|
|
// Show category details with items
|
|
$controller = new CategoryController();
|
|
$controller->showCategory($categoryId);
|
|
} else {
|
|
// Show all categories
|
|
$controller = new CategoryController();
|
|
$controller->listCategories();
|
|
}
|
|
});
|
|
|
|
// Parts with optional item filter
|
|
$router->addRoute('GET', '/api/parts', function() {
|
|
$itemId = $_GET['item'] ?? null;
|
|
if ($itemId) {
|
|
// Show item details/edit form
|
|
$controller = new ItemController();
|
|
$controller->editItem($itemId);
|
|
} else {
|
|
// Show add form
|
|
$controller = new ItemController();
|
|
$controller->renderAddForm();
|
|
}
|
|
});
|
|
$router->addRoute('GET', '/api/tree', function() {
|
|
try {
|
|
$db = Database::getInstance();
|
|
$categories = Category::getAll($db);
|
|
|
|
function build_category_tree($categories, $db, $parentId = null, $visited = [], $depth = 0, $nodeCount = 0) {
|
|
if ($depth > 5 || $nodeCount > 100) return [];
|
|
$tree = [];
|
|
foreach ($categories as $cat) {
|
|
if ($cat['parent_id'] == $parentId && !in_array($cat['id'], $visited)) {
|
|
$visited[] = $cat['id'];
|
|
|
|
// Get items for this category
|
|
$itemsStmt = $db->prepare('SELECT id, name FROM items WHERE category_id = :category_id ORDER BY name');
|
|
$itemsStmt->execute([':category_id' => $cat['id']]);
|
|
$items = $itemsStmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$node = [
|
|
'id' => $cat['id'],
|
|
'name' => $cat['name'],
|
|
'items' => $items,
|
|
'children' => build_category_tree($categories, $db, $cat['id'], $visited, $depth + 1, $nodeCount)
|
|
];
|
|
$tree[] = $node;
|
|
$nodeCount++;
|
|
if ($nodeCount > 100) break;
|
|
}
|
|
}
|
|
return $tree;
|
|
}
|
|
|
|
function render_category_tree($nodes, $depth = 0) {
|
|
if ($depth > 5) return '';
|
|
$html = '';
|
|
foreach ($nodes as $node) {
|
|
$indent = str_repeat('│ ', $depth);
|
|
$isLast = false;
|
|
|
|
$html .= '<li class="tree-item" style="list-style: none; padding: 2px 0;">';
|
|
$html .= '<span class="tree-node" style="cursor: pointer;" onclick="toggleNode(this)">';
|
|
$html .= $indent . '├── ';
|
|
$html .= '<i class="bi bi-folder-fill text-warning"></i> ';
|
|
$html .= '<a href="#" class="category-link" style="text-decoration: none; color: inherit; outline: none; box-shadow: none; border: none; background: transparent;" data-route="/categories?category=' . $node['id'] . '">';
|
|
$html .= htmlspecialchars($node['name']);
|
|
$html .= '</a>';
|
|
$html .= '</span>';
|
|
|
|
// Add items as sub-items
|
|
if (!empty($node['items'])) {
|
|
$itemIndent = str_repeat('│ ', $depth + 1);
|
|
foreach ($node['items'] as $index => $item) {
|
|
$isLastItem = $index === count($node['items']) - 1;
|
|
$prefix = $isLastItem ? '└── ' : '├── ';
|
|
|
|
$html .= '<li class="tree-item" style="list-style: none; padding: 2px 0;">';
|
|
$html .= $itemIndent . $prefix;
|
|
$html .= '<i class="bi bi-file-earmark-text" style="color: #6c757d;"></i> ';
|
|
$html .= '<a href="#" class="item-link" style="text-decoration: none; color: inherit; outline: none; box-shadow: none; border: none; background: transparent;" data-route="/parts?item=' . $item['id'] . '">';
|
|
$html .= htmlspecialchars($item['name']);
|
|
$html .= '</a>';
|
|
$html .= '</li>';
|
|
}
|
|
}
|
|
|
|
// Add subcategories
|
|
if (!empty($node['children'])) {
|
|
$html .= '<ul style="list-style: none; padding-left: 0; margin: 0;">';
|
|
$html .= render_category_tree($node['children'], $depth + 1);
|
|
$html .= '</ul>';
|
|
}
|
|
|
|
$html .= '</li>';
|
|
}
|
|
return $html;
|
|
}
|
|
|
|
$nodeCount = 0;
|
|
$categoryTree = build_category_tree($categories, $db, null, [], 0, $nodeCount);
|
|
$html = '<ul style="list-style: none; padding-left: 0; margin: 0; font-family: monospace;">' . render_category_tree($categoryTree) . '</ul>';
|
|
if (strlen($html) > 10000) {
|
|
$html = '<ul style="list-style: none; padding-left: 0; margin: 0;"><li style="padding: 2px 0;">📁 <a href="#" style="text-decoration: none; color: inherit; outline: none; box-shadow: none; border: none; background: transparent;" data-route="/">Overview</a></li><li style="padding: 2px 0;">📁 <a href="#" style="text-decoration: none; color: inherit; outline: none; box-shadow: none; border: none; background: transparent;" data-route="/categories">Categories</a></li><li style="padding: 2px 0;">📁 <a href="#" style="text-decoration: none; color: inherit; outline: none; box-shadow: none; border: none; background: transparent;" data-route="/parts">Parts</a></li></ul>';
|
|
}
|
|
header('Content-Type: text/html');
|
|
echo $html;
|
|
} catch (Exception $e) {
|
|
header('Content-Type: text/html');
|
|
echo '<ul style="list-style: none; padding-left: 0; margin: 0;"><li style="padding: 2px 0;">📁 <a href="#" class="text-decoration-none text-dark" data-route="/">Overview</a></li><li style="padding: 2px 0;">📁 <a href="#" class="text-decoration-none text-dark" data-route="/categories">Categories</a></li><li style="padding: 2px 0;">📁 <a href="#" class="text-decoration-none text-dark" data-route="/parts">Parts</a></li></ul>';
|
|
}
|
|
});
|
|
|
|
// --- API CRUD Routes ---
|
|
// Items
|
|
$router->addRoute('POST', '/api/items', [ItemController::class, 'create']);
|
|
$router->addRoute('POST', '/api/items/{id:\d+}', [ItemController::class, 'update']);
|
|
$router->addRoute('DELETE', '/api/items/{id:\d+}', [ItemController::class, 'delete']);
|
|
|
|
// Categories
|
|
$router->addRoute('POST', '/api/categories', [CategoryController::class, 'create']);
|
|
$router->addRoute('PUT', '/api/categories/{id:\d+}', [CategoryController::class, 'update']);
|
|
$router->addRoute('DELETE', '/api/categories/{id:\d+}', [CategoryController::class, 'delete']);
|
|
|
|
|
|
$router->dispatch(); |