Files
NidoAi/backend/src/Controllers/ShiftDefinitionController.php
2026-03-07 00:15:59 +01:00

224 lines
9.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controllers;
use App\Database;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
class ShiftDefinitionController
{
private Connection $db;
public function __construct()
{
try {
$this->db = Database::getConnection();
} catch (\Throwable $e) {
error_log("Failed to get DB connection in ShiftDefinitionController: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
exit;
}
}
/**
* Mostra un elenco di definizioni di turno.
* GET /api/shift-definitions
*/
public function index(): void
{
try {
$queryBuilder = $this->db->createQueryBuilder();
$shifts = $queryBuilder
->select('*')
->from('shift_definitions')
->orderBy('start_time', 'ASC') // Ordina per orario inizio
->fetchAllAssociative();
echo json_encode($shifts);
} catch (\Throwable $e) {
http_response_code(500);
error_log("Error fetching shift definitions: " . $e->getMessage());
echo json_encode(['error' => 'Failed to fetch shift definitions']);
}
}
/**
* Mostra una definizione di turno specifica.
* GET /api/shift-definitions/{id}
*/
public function show(array $vars): void
{
$id = $vars['id'] ?? null;
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
try {
$shift = $this->db->fetchAssociative('SELECT * FROM shift_definitions WHERE id = ?', [$id]);
if ($shift === false) {
http_response_code(404);
echo json_encode(['error' => "Shift definition with ID {$id} not found"]);
} else {
echo json_encode($shift);
}
} catch (\Throwable $e) {
http_response_code(500);
error_log("Error fetching shift definition {$id}: " . $e->getMessage());
echo json_encode(['error' => 'Failed to fetch shift definition']);
}
}
/**
* Crea una nuova definizione di turno.
* POST /api/shift-definitions
*/
public function store(): void
{
$input = json_decode(file_get_contents('php://input'), true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
}
// Validazione campi obbligatori
if (empty($input['name']) || empty($input['start_time']) || empty($input['end_time'])) {
http_response_code(400);
echo json_encode(['error' => 'Missing required fields: name, start_time, end_time']);
return;
}
// Validazione formato orario (HH:MM o HH:MM:SS)
$timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
if (!preg_match($timeRegex, $input['start_time']) || !preg_match($timeRegex, $input['end_time'])) {
http_response_code(400);
echo json_encode(['error' => 'Invalid time format. Use HH:MM or HH:MM:SS.']);
return;
}
// Validazione logica orari (opzionale, ma utile)
if (strtotime($input['end_time']) <= strtotime($input['start_time'])) {
http_response_code(400);
echo json_encode(['error' => 'End time must be after start time.']);
return;
}
$dataToInsert = [
'name' => $input['name'],
'start_time' => $input['start_time'],
'end_time' => $input['end_time'],
'notes' => $input['notes'] ?? null,
];
try {
$result = $this->db->insert('shift_definitions', $dataToInsert);
if ($result === false || $result === 0) { throw new \Exception("Failed to insert shift definition."); }
$newId = $this->db->lastInsertId();
http_response_code(201);
$this->show(['id' => $newId]);
} catch (UniqueConstraintViolationException $e) {
http_response_code(409);
error_log("Error creating shift definition (duplicate name?): " . $e->getMessage());
echo json_encode(['error' => 'Failed to create shift definition. Name might already exist.']);
} catch (\Throwable $e) {
http_response_code(500);
error_log("Error creating shift definition: " . $e->getMessage());
echo json_encode(['error' => 'Failed to create shift definition']);
}
}
/**
* Aggiorna una definizione di turno esistente.
* PUT /api/shift-definitions/{id}
*/
public function update(array $vars): void
{
$id = $vars['id'] ?? null;
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
$input = json_decode(file_get_contents('php://input'), true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
}
if (empty($input)) { http_response_code(400); echo json_encode(['error' => 'Missing update data']); return; }
// Validazione formato orario se presenti
$timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
if (isset($input['start_time']) && !preg_match($timeRegex, $input['start_time'])) {
http_response_code(400); echo json_encode(['error' => 'Invalid start_time format.']); return;
}
if (isset($input['end_time']) && !preg_match($timeRegex, $input['end_time'])) {
http_response_code(400); echo json_encode(['error' => 'Invalid end_time format.']); return;
}
// Validazione logica orari se entrambi presenti
$startTime = $input['start_time'] ?? null;
$endTime = $input['end_time'] ?? null;
if ($startTime && $endTime && strtotime($endTime) <= strtotime($startTime)) {
http_response_code(400); echo json_encode(['error' => 'End time must be after start time.']); return;
}
// Validazione con orari esistenti se solo uno viene fornito (più complessa, omessa per brevità)
$dataToUpdate = [];
$allowedFields = ['name', 'start_time', 'end_time', 'notes'];
foreach ($allowedFields as $field) {
if (array_key_exists($field, $input)) {
$dataToUpdate[$field] = ($input[$field] === '') ? null : $input[$field];
}
}
if (empty($dataToUpdate)) { http_response_code(400); echo json_encode(['error' => 'No valid fields provided for update']); return; }
try {
$existing = $this->db->fetchOne('SELECT 1 FROM shift_definitions WHERE id = ?', [$id]);
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Shift definition with ID {$id} not found"]); return; }
$this->db->update('shift_definitions', $dataToUpdate, ['id' => $id]);
$this->show(['id' => $id]);
} catch (UniqueConstraintViolationException $e) {
http_response_code(409);
error_log("Error updating shift definition {$id} (duplicate name?): " . $e->getMessage());
echo json_encode(['error' => 'Failed to update shift definition. Name might already exist.']);
} catch (\Throwable $e) {
http_response_code(500);
error_log("Error updating shift definition {$id}: " . $e->getMessage());
echo json_encode(['error' => 'Failed to update shift definition']);
}
}
/**
* Elimina una definizione di turno.
* DELETE /api/shift-definitions/{id}
*/
public function delete(array $vars): void
{
$id = $vars['id'] ?? null;
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
try {
// Aggiungere qui controlli se la definizione è usata in turni effettivi?
$existing = $this->db->fetchOne('SELECT 1 FROM shift_definitions WHERE id = ?', [$id]);
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Shift definition with ID {$id} not found"]); return; }
$deletedRows = $this->db->delete('shift_definitions', ['id' => $id]);
if ($deletedRows > 0) {
http_response_code(204); // No Content
} else {
http_response_code(500);
error_log("Failed to delete shift definition {$id}, delete returned 0 rows affected.");
echo json_encode(['error' => 'Failed to delete shift definition']);
}
} catch (\Throwable $e) {
// Gestire ForeignKeyConstraintViolationException se la definizione è usata altrove
http_response_code(500);
error_log("Error deleting shift definition {$id}: " . $e->getMessage());
echo json_encode(['error' => 'Failed to delete shift definition. It might be in use.']);
}
}
}