first commit
This commit is contained in:
130
src/Controllers/CategoryController.php
Executable file
130
src/Controllers/CategoryController.php
Executable file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use App\Models\Category;
|
||||
|
||||
class CategoryController
|
||||
{
|
||||
// Renders the full layout for categories page load
|
||||
public static function index()
|
||||
{
|
||||
global $twig;
|
||||
echo $twig->render('layout.twig', ['active_page' => 'categories']);
|
||||
}
|
||||
|
||||
// Get single category (JSON)
|
||||
public static function getCategory($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$category = Category::getById($db, $id);
|
||||
if ($category) {
|
||||
echo json_encode($category);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Category not found']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the HTML content for the categories page (used by AJAX)
|
||||
public static function listCategories()
|
||||
{
|
||||
global $twig;
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$categories = Category::getAll($db);
|
||||
|
||||
// Render only the content block
|
||||
echo $twig->render('categories.twig', [
|
||||
'categories' => $categories,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching categories: " . $e->getMessage());
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// CRUD operations (returns JSON)
|
||||
public static function create() {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$data = $_POST;
|
||||
|
||||
$name = trim($data['new_category_name'] ?? '');
|
||||
$parentId = !empty($data['parent_category_id']) ? (int)$data['parent_category_id'] : null;
|
||||
|
||||
if (empty($name)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Category name is required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$category = new Category($db, null, $name, $parentId);
|
||||
if ($category->save()) {
|
||||
echo json_encode(['success' => true, 'message' => 'Category added successfully', 'id' => $category->getId()]);
|
||||
} else {
|
||||
throw new Exception('Failed to save category');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function update($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$data = json_decode(file_get_contents('php://input'), true) ?? $_POST;
|
||||
|
||||
$existing = Category::getById($db, $id);
|
||||
if (!$existing) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Category not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
$name = trim($data['category_name'] ?? $existing['name']);
|
||||
|
||||
if (empty($name)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Category name is required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$category = new Category($db, $id, $name);
|
||||
if ($category->save()) {
|
||||
echo json_encode(['success' => true, 'message' => 'Category updated successfully']);
|
||||
} else {
|
||||
throw new Exception('Failed to update category');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
if (Category::delete($db, $id)) {
|
||||
echo json_encode(['success' => true, 'message' => 'Category deleted successfully']);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Category not found']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
167
src/Controllers/ItemController.php
Executable file
167
src/Controllers/ItemController.php
Executable file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use App\Models\Item;
|
||||
use App\Models\Category;
|
||||
|
||||
class ItemController
|
||||
{
|
||||
// Renders the full layout for overview page load
|
||||
public static function overview()
|
||||
{
|
||||
global $twig;
|
||||
echo $twig->render('layout.twig', ['active_page' => 'overview']);
|
||||
}
|
||||
|
||||
// Renders the full layout for add parts page
|
||||
public static function addForm()
|
||||
{
|
||||
global $twig;
|
||||
echo $twig->render('layout.twig', ['active_page' => 'parts']);
|
||||
}
|
||||
|
||||
// Get single item (JSON)
|
||||
public static function getItem($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$item = Item::getById($db, $id);
|
||||
if ($item) {
|
||||
echo json_encode($item);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Part not found']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the HTML content for the add parts page (used by AJAX)
|
||||
public static function renderAddForm()
|
||||
{
|
||||
global $twig;
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$categories = Category::getAll($db);
|
||||
|
||||
// Render only the content block
|
||||
echo $twig->render('parts.twig', [
|
||||
'categories' => $categories,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error rendering add form: " . $e->getMessage());
|
||||
echo "Error: Could not load add form.";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the HTML content for the items page (used by AJAX)
|
||||
public static function listItems()
|
||||
{
|
||||
global $twig;
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$search = trim($_GET['search'] ?? '');
|
||||
$categoryId = !empty($_GET['category_id']) ? (int)$_GET['category_id'] : null;
|
||||
|
||||
$items = Item::getAllFiltered($db, $search, $categoryId);
|
||||
$categories = Category::getAll($db);
|
||||
|
||||
// Render only the content block
|
||||
echo $twig->render('items.twig', [
|
||||
'items' => $items,
|
||||
'categories' => $categories,
|
||||
'search' => $search,
|
||||
'selected_category' => $categoryId,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching items: " . $e->getMessage());
|
||||
echo "Error: Could not load items.";
|
||||
}
|
||||
}
|
||||
|
||||
// CRUD operations (returns JSON)
|
||||
public static function create() {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$data = $_POST;
|
||||
|
||||
$name = trim($data['item_name'] ?? '');
|
||||
$description = trim($data['item_description'] ?? '');
|
||||
$categoryId = !empty($data['category_id']) ? (int)$data['category_id'] : null;
|
||||
|
||||
if (empty($name)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Part name is required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$item = new Item($db, null, $name, $description, $categoryId);
|
||||
if ($item->save()) {
|
||||
echo json_encode(['success' => true, 'message' => 'Part added successfully']);
|
||||
} else {
|
||||
throw new Exception('Failed to save part');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function update($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$data = json_decode(file_get_contents('php://input'), true) ?? $_POST;
|
||||
|
||||
$existing = Item::getById($db, $id);
|
||||
if (!$existing) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Part not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
$name = trim($data['item_name'] ?? $existing['name']);
|
||||
$description = trim($data['item_description'] ?? $existing['description']);
|
||||
$categoryId = isset($data['category_id']) && $data['category_id'] !== '' ? (int)$data['category_id'] : $existing['category_id'];
|
||||
|
||||
if (empty($name)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Part name is required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$item = new Item($db, $id, $name, $description, $categoryId);
|
||||
if ($item->save()) {
|
||||
echo json_encode(['success' => true, 'message' => 'Part updated successfully']);
|
||||
} else {
|
||||
throw new Exception('Failed to update part');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete($id) {
|
||||
header('Content-Type: application/json');
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
if (Item::delete($db, $id)) {
|
||||
echo json_encode(['success' => true, 'message' => 'Part deleted successfully']);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Part not found']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/Database.php
Executable file
46
src/Database.php
Executable file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
class Database {
|
||||
private static ?PDO $instance = null;
|
||||
// Gebruik de globale constante DB_PATH uit config.php
|
||||
private static string $dbFile = DB_PATH;
|
||||
|
||||
public static function getInstance(): PDO {
|
||||
if (self::$instance === null) {
|
||||
try {
|
||||
self::$instance = new PDO('sqlite:' . self::$dbFile);
|
||||
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
self::createTables();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database connection failed: " . $e->getMessage());
|
||||
// Verbeterde foutmelding voor de gebruiker
|
||||
die("FATAL ERROR: Database connection failed. This is often a permission issue.
|
||||
<br>Error: " . $e->getMessage() . "
|
||||
<br>Database Path: " . self::$dbFile . "
|
||||
<br>Please ensure the web server user (www-data) has write permissions to the database file and its directory.");
|
||||
}
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private static function createTables(): void {
|
||||
$db = self::getInstance();
|
||||
$db->exec('CREATE TABLE IF NOT EXISTS categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
parent_id INTEGER DEFAULT NULL
|
||||
)');
|
||||
$db->exec('CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
category_id INTEGER,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id)
|
||||
)');
|
||||
}
|
||||
}
|
||||
40
src/Database.php~
Executable file
40
src/Database.php~
Executable file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
class Database {
|
||||
private static ?PDO $instance = null;
|
||||
private static string $dbFile = '/var/www/localweb/collections.sqlite';
|
||||
|
||||
public static function getInstance(): PDO {
|
||||
if (self::$instance === null) {
|
||||
try {
|
||||
self::$instance = new PDO('sqlite:' . self::$dbFile);
|
||||
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
self::createTables();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database connection failed: " . $e->getMessage());
|
||||
throw new PDOException("Database connection failed: could not open database file. Please check server logs for details.");
|
||||
}
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private static function createTables(): void {
|
||||
$db = self::getInstance();
|
||||
$db->exec('CREATE TABLE IF NOT EXISTS categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE
|
||||
)');
|
||||
$db->exec('CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
category_id INTEGER,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id)
|
||||
)');
|
||||
}
|
||||
}
|
||||
113
src/Models/Category.php
Executable file
113
src/Models/Category.php
Executable file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
class Category {
|
||||
private PDO $db;
|
||||
private ?int $id;
|
||||
private string $name;
|
||||
private ?int $parentId;
|
||||
|
||||
public function __construct(PDO $db, ?int $id = null, string $name = '', ?int $parentId = null) {
|
||||
$this->db = $db;
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->parentId = $parentId;
|
||||
}
|
||||
|
||||
public function getId(): ?int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): void {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getParentId(): ?int {
|
||||
return $this->parentId;
|
||||
}
|
||||
|
||||
public function setParentId(?int $parentId): void {
|
||||
$this->parentId = $parentId;
|
||||
}
|
||||
|
||||
public static function getAll(PDO $db): array {
|
||||
try {
|
||||
$stmt = $db->query('SELECT c.id, c.name, c.parent_id, p.name as parent_name FROM categories c LEFT JOIN categories p ON c.parent_id = p.id ORDER BY c.name');
|
||||
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
// Add full path
|
||||
foreach ($categories as &$category) {
|
||||
$category['path'] = self::getFullPath($db, $category['id']);
|
||||
}
|
||||
return $categories;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to get all categories - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getFullPath(PDO $db, int $id, string $separator = ' / '): string {
|
||||
$category = self::getById($db, $id);
|
||||
if (!$category) return '';
|
||||
if ($category['parent_id']) {
|
||||
return self::getFullPath($db, $category['parent_id'], $separator) . $separator . $category['name'];
|
||||
} else {
|
||||
return $category['name'];
|
||||
}
|
||||
}
|
||||
|
||||
public static function getById(PDO $db, int $id): ?array {
|
||||
try {
|
||||
$stmt = $db->prepare('SELECT id, name, parent_id FROM categories WHERE id = :id');
|
||||
$stmt->execute([':id' => $id]);
|
||||
$category = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $category ?: null;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to get category by ID - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function save(): bool {
|
||||
if ($this->id === null) {
|
||||
// Add new category
|
||||
try {
|
||||
$stmt = $this->db->prepare('INSERT INTO categories (name, parent_id) VALUES (:name, :parent_id)');
|
||||
$stmt->execute([':name' => $this->name, ':parent_id' => $this->parentId]);
|
||||
$this->id = (int)$this->db->lastInsertId();
|
||||
return true;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to save category - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
// Update category
|
||||
try {
|
||||
$stmt = $this->db->prepare('UPDATE categories SET name = :name, parent_id = :parent_id WHERE id = :id');
|
||||
$stmt->execute([':name' => $this->name, ':parent_id' => $this->parentId, ':id' => $this->id]);
|
||||
return true;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to update category - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete(PDO $db, int $id): bool {
|
||||
try {
|
||||
$stmt = $db->prepare('DELETE FROM categories WHERE id = :id');
|
||||
$stmt->execute([':id' => $id]);
|
||||
return $stmt->rowCount() > 0;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to delete category - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
168
src/Models/Item.php
Executable file
168
src/Models/Item.php
Executable file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
class Item {
|
||||
private PDO $db;
|
||||
private ?int $id;
|
||||
private string $name;
|
||||
private ?string $description;
|
||||
private ?int $categoryId;
|
||||
private ?string $categoryName;
|
||||
|
||||
public function __construct(PDO $db, ?int $id = null, string $name = '', ?string $description = null, ?int $categoryId = null, ?string $categoryName = null) {
|
||||
$this->db = $db;
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->description = $description;
|
||||
$this->categoryId = $categoryId;
|
||||
$this->categoryName = $categoryName;
|
||||
}
|
||||
|
||||
public function getId(): ?int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): void {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): void {
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
public function getCategoryId(): ?int {
|
||||
return $this->categoryId;
|
||||
}
|
||||
|
||||
public function setCategoryId(?int $categoryId): void {
|
||||
$this->categoryId = $categoryId;
|
||||
}
|
||||
|
||||
public function getCategoryName(): ?string {
|
||||
return $this->categoryName;
|
||||
}
|
||||
|
||||
public static function getAll(PDO $db): array {
|
||||
return self::getAllFiltered($db, '', null);
|
||||
}
|
||||
|
||||
public static function getAllFiltered(PDO $db, string $search, ?int $categoryId): array {
|
||||
try {
|
||||
$query = 'SELECT i.id, i.name, i.description, c.name as category_name, i.category_id
|
||||
FROM items i
|
||||
LEFT JOIN categories c ON i.category_id = c.id
|
||||
WHERE 1=1';
|
||||
$params = [];
|
||||
|
||||
if (!empty($search)) {
|
||||
$query .= ' AND i.name LIKE :search';
|
||||
$params[':search'] = '%' . $search . '%';
|
||||
}
|
||||
|
||||
if ($categoryId !== null) {
|
||||
$query .= ' AND i.category_id = :category_id';
|
||||
$params[':category_id'] = $categoryId;
|
||||
}
|
||||
|
||||
$query .= ' ORDER BY i.name';
|
||||
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to get filtered items - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getById(PDO $db, int $id): ?array {
|
||||
try {
|
||||
$stmt = $db->prepare(
|
||||
'SELECT i.id, i.name, i.description, c.name as category_name, i.category_id
|
||||
FROM items i
|
||||
LEFT JOIN categories c ON i.category_id = c.id
|
||||
WHERE i.id = :id'
|
||||
);
|
||||
$stmt->execute([':id' => $id]);
|
||||
$item = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $item ?: null;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to get item by ID - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function save(): bool {
|
||||
if ($this->id === null) {
|
||||
// Add new item
|
||||
try {
|
||||
$stmt = $this->db->prepare(
|
||||
'INSERT INTO items (name, description, category_id)
|
||||
VALUES (:name, :description, :category_id)'
|
||||
);
|
||||
$stmt->execute([
|
||||
':name' => $this->name,
|
||||
':description' => $this->description,
|
||||
':category_id' => $this->categoryId
|
||||
]);
|
||||
$this->id = (int)$this->db->lastInsertId();
|
||||
return true;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to save item - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
// Update item (optional, not implemented in current controllers)
|
||||
try {
|
||||
$stmt = $this->db->prepare(
|
||||
'UPDATE items
|
||||
SET name = :name, description = :description, category_id = :category_id
|
||||
WHERE id = :id'
|
||||
);
|
||||
$stmt->execute([
|
||||
':name' => $this->name,
|
||||
':description' => $this->description,
|
||||
':category_id' => $this->categoryId,
|
||||
':id' => $this->id
|
||||
]);
|
||||
return true;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to update item - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete(PDO $db, int $id): bool {
|
||||
try {
|
||||
$stmt = $db->prepare('DELETE FROM items WHERE id = :id');
|
||||
$stmt->execute([':id' => $id]);
|
||||
return $stmt->rowCount() > 0;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Model Error: Failed to delete item - " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'category_id' => $this->categoryId,
|
||||
'category_name' => $this->categoryName
|
||||
];
|
||||
}
|
||||
}
|
||||
48
src/Router.php
Executable file
48
src/Router.php
Executable file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
class Router {
|
||||
private array $routes = [];
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function addRoute(string $method, string $path, mixed $handler): void {
|
||||
$this->routes[] = ['method' => $method, 'path' => $path, 'handler' => $handler];
|
||||
}
|
||||
|
||||
public function dispatch() {
|
||||
$dispatcher = \FastRoute\simpleDispatcher(function($r) {
|
||||
foreach ($this->routes as $route) {
|
||||
$r->addRoute($route['method'], $route['path'], $route['handler']);
|
||||
}
|
||||
});
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
$path = parse_url($uri, PHP_URL_PATH);
|
||||
$routeInfo = $dispatcher->dispatch($method, $path);
|
||||
|
||||
switch ($routeInfo[0]) {
|
||||
case \FastRoute\Dispatcher::NOT_FOUND:
|
||||
// Handle 404
|
||||
http_response_code(404);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Not Found']);
|
||||
break;
|
||||
case \FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
|
||||
// Handle 405
|
||||
$allowedMethods = $routeInfo[1];
|
||||
http_response_code(405);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Method Not Allowed', 'allowed' => $allowedMethods]);
|
||||
break;
|
||||
case \FastRoute\Dispatcher::FOUND:
|
||||
$handler = $routeInfo[1];
|
||||
$vars = $routeInfo[2];
|
||||
// Call the handler with route variables
|
||||
$handler(...array_values($vars));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/Services/TranslationService.php
Executable file
35
src/Services/TranslationService.php
Executable file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\Loader\JsonFileLoader;
|
||||
|
||||
class TranslationService
|
||||
{
|
||||
private string $langDir;
|
||||
private array $supportedLocales;
|
||||
private string $defaultLocale;
|
||||
|
||||
public function __construct(string $langDir, array $supportedLocales, string $defaultLocale)
|
||||
{
|
||||
$this->langDir = $langDir;
|
||||
$this->supportedLocales = $supportedLocales;
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
}
|
||||
|
||||
public function getTranslator(string $locale): Translator
|
||||
{
|
||||
$translator = new Translator($locale);
|
||||
$translator->addLoader('json', new JsonFileLoader());
|
||||
|
||||
foreach ($this->supportedLocales as $supportedLocale) {
|
||||
$filePath = $this->langDir . '/' . $supportedLocale . '.json';
|
||||
if (file_exists($filePath)) {
|
||||
$translator->addResource('json', $filePath, $supportedLocale);
|
||||
}
|
||||
}
|
||||
|
||||
return $translator;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user