conn = $conn; } // ======================================== // Field Definitions // ======================================== /** * Get all field definitions */ public function getAllDefinitions($category = null, $activeOnly = true) { $sql = "SELECT * FROM custom_field_definitions WHERE 1=1"; $params = []; $types = ''; if ($activeOnly) { $sql .= " AND is_active = 1"; } if ($category !== null) { $sql .= " AND (category = ? OR category IS NULL)"; $params[] = $category; $types .= 's'; } $sql .= " ORDER BY display_order ASC, field_id ASC"; if (!empty($params)) { $stmt = $this->conn->prepare($sql); $stmt->bind_param($types, ...$params); $stmt->execute(); $result = $stmt->get_result(); } else { $result = $this->conn->query($sql); } $fields = []; while ($row = $result->fetch_assoc()) { if ($row['field_options']) { $row['field_options'] = json_decode($row['field_options'], true); } $fields[] = $row; } if (isset($stmt)) { $stmt->close(); } return $fields; } /** * Get a single field definition */ public function getDefinition($fieldId) { $sql = "SELECT * FROM custom_field_definitions WHERE field_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('i', $fieldId); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); $stmt->close(); if ($row && $row['field_options']) { $row['field_options'] = json_decode($row['field_options'], true); } return $row; } /** * Create a new field definition */ public function createDefinition($data) { $options = null; if (isset($data['field_options']) && !empty($data['field_options'])) { $options = json_encode($data['field_options']); } $sql = "INSERT INTO custom_field_definitions (field_name, field_label, field_type, field_options, category, is_required, display_order, is_active) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('sssssiii', $data['field_name'], $data['field_label'], $data['field_type'], $options, $data['category'], $data['is_required'] ?? 0, $data['display_order'] ?? 0, $data['is_active'] ?? 1 ); if ($stmt->execute()) { $id = $this->conn->insert_id; $stmt->close(); return ['success' => true, 'field_id' => $id]; } $error = $stmt->error; $stmt->close(); return ['success' => false, 'error' => $error]; } /** * Update a field definition */ public function updateDefinition($fieldId, $data) { $options = null; if (isset($data['field_options']) && !empty($data['field_options'])) { $options = json_encode($data['field_options']); } $sql = "UPDATE custom_field_definitions SET field_name = ?, field_label = ?, field_type = ?, field_options = ?, category = ?, is_required = ?, display_order = ?, is_active = ? WHERE field_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('sssssiiiii', $data['field_name'], $data['field_label'], $data['field_type'], $options, $data['category'], $data['is_required'] ?? 0, $data['display_order'] ?? 0, $data['is_active'] ?? 1, $fieldId ); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } /** * Delete a field definition */ public function deleteDefinition($fieldId) { // This will cascade delete all values due to FK constraint $sql = "DELETE FROM custom_field_definitions WHERE field_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('i', $fieldId); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } // ======================================== // Field Values // ======================================== /** * Get all field values for a ticket */ public function getValuesForTicket($ticketId) { $sql = "SELECT cfv.*, cfd.field_name, cfd.field_label, cfd.field_type, cfd.field_options FROM custom_field_values cfv JOIN custom_field_definitions cfd ON cfv.field_id = cfd.field_id WHERE cfv.ticket_id = ? ORDER BY cfd.display_order ASC"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('s', $ticketId); $stmt->execute(); $result = $stmt->get_result(); $values = []; while ($row = $result->fetch_assoc()) { if ($row['field_options']) { $row['field_options'] = json_decode($row['field_options'], true); } $values[$row['field_name']] = $row; } $stmt->close(); return $values; } /** * Set a field value for a ticket (insert or update) */ public function setValue($ticketId, $fieldId, $value) { $sql = "INSERT INTO custom_field_values (ticket_id, field_id, field_value) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE field_value = VALUES(field_value), updated_at = CURRENT_TIMESTAMP"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('sis', $ticketId, $fieldId, $value); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } /** * Set multiple field values for a ticket */ public function setValues($ticketId, $values) { $results = []; foreach ($values as $fieldId => $value) { $results[$fieldId] = $this->setValue($ticketId, $fieldId, $value); } return $results; } /** * Delete all field values for a ticket */ public function deleteValuesForTicket($ticketId) { $sql = "DELETE FROM custom_field_values WHERE ticket_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('s', $ticketId); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } } ?>