prepare(" SELECT questionID, questionnaireID, defaultText, type, orderIndex, isRequired, configJson FROM question WHERE questionnaireID = :qid ORDER BY orderIndex "); $stmt->execute([':qid' => $questionnaireID]); $questions = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($questions as &$q) { $q['isRequired'] = (int) $q['isRequired']; $q['orderIndex'] = (int) $q['orderIndex']; $q['configJson'] = $q['configJson'] ?: '{}'; $ao = $pdo->prepare(" SELECT answerOptionID, questionID, defaultText, points, orderIndex, nextQuestionId FROM answer_option WHERE questionID = :qid ORDER BY orderIndex "); $ao->execute([':qid' => $q['questionID']]); $q['answerOptions'] = $ao->fetchAll(PDO::FETCH_ASSOC); foreach ($q['answerOptions'] as &$opt) { $opt['points'] = (int) $opt['points']; $opt['orderIndex'] = (int) $opt['orderIndex']; } unset($opt); $tr = $pdo->prepare( 'SELECT languageCode, text FROM question_translation WHERE questionID = :qid' ); $tr->execute([':qid' => $q['questionID']]); $q['translations'] = $tr->fetchAll(PDO::FETCH_ASSOC); } unset($q); return $questions; } public static function findById(PDO $pdo, string $questionID): ?array { $stmt = $pdo->prepare('SELECT * FROM question WHERE questionID = :id'); $stmt->execute([':id' => $questionID]); $row = $stmt->fetch(PDO::FETCH_ASSOC); return $row === false ? null : $row; } public static function create( PDO $pdo, string $id, string $questionnaireID, string $defaultText, string $type, int $orderIndex, int $isRequired, string $configJson ): void { $pdo->prepare( 'INSERT INTO question (questionID, questionnaireID, defaultText, type, orderIndex, isRequired, configJson) VALUES (:id, :qid, :t, :ty, :o, :r, :cj)' )->execute([ ':id' => $id, ':qid' => $questionnaireID, ':t' => $defaultText, ':ty' => $type, ':o' => $orderIndex, ':r' => $isRequired, ':cj' => $configJson, ]); } public static function update( PDO $pdo, string $id, string $defaultText, string $type, int $orderIndex, int $isRequired, string $configJson ): void { $pdo->prepare( 'UPDATE question SET defaultText = :t, type = :ty, orderIndex = :o, isRequired = :r, configJson = :cj WHERE questionID = :id' )->execute([ ':t' => $defaultText, ':ty' => $type, ':o' => $orderIndex, ':r' => $isRequired, ':cj' => $configJson, ':id' => $id, ]); } public static function delete(PDO $pdo, string $id): void { $pdo->exec('PRAGMA foreign_keys = OFF;'); $pdo->beginTransaction(); try { $aoIds = $pdo->prepare('SELECT answerOptionID FROM answer_option WHERE questionID = :id'); $aoIds->execute([':id' => $id]); foreach ($aoIds->fetchAll(PDO::FETCH_COLUMN) as $aoid) { $pdo->prepare('DELETE FROM answer_option_translation WHERE answerOptionID = :id') ->execute([':id' => $aoid]); } $pdo->prepare('DELETE FROM answer_option WHERE questionID = :id')->execute([':id' => $id]); $pdo->prepare('DELETE FROM question_translation WHERE questionID = :id')->execute([':id' => $id]); $pdo->prepare('DELETE FROM client_answer WHERE questionID = :id')->execute([':id' => $id]); $pdo->prepare('DELETE FROM question WHERE questionID = :id')->execute([':id' => $id]); $pdo->commit(); } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } throw $e; } finally { $pdo->exec('PRAGMA foreign_keys = ON;'); } } public static function reorder(PDO $pdo, string $questionnaireID, array $orderedIds): void { $stmt = $pdo->prepare( 'UPDATE question SET orderIndex = :o WHERE questionID = :id AND questionnaireID = :qid' ); foreach ($orderedIds as $idx => $questionId) { $stmt->execute([ ':o' => (int) $idx, ':id' => $questionId, ':qid' => $questionnaireID, ]); } } public static function nextOrderIndex(PDO $pdo, string $questionnaireID): int { $max = $pdo->prepare( 'SELECT COALESCE(MAX(orderIndex), 0) + 1 FROM question WHERE questionnaireID = :id' ); $max->execute([':id' => $questionnaireID]); return (int) $max->fetchColumn(); } }