new system prototype
This commit is contained in:
291
api/translations.php
Normal file
291
api/translations.php
Normal file
@ -0,0 +1,291 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../common.php';
|
||||
require_once __DIR__ . '/../db_init.php';
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
$tokenRec = require_valid_token();
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
$validTypes = ['question', 'answer_option', 'string', 'language'];
|
||||
|
||||
switch ($method) {
|
||||
|
||||
case 'GET':
|
||||
// GET ?languages=1 -> list all languages
|
||||
if (isset($_GET['languages'])) {
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
||||
$rows = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC);
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true, "languages" => $rows]);
|
||||
break;
|
||||
}
|
||||
|
||||
// GET ?questionnaireID=X -> batch: all keys + all translations for a questionnaire
|
||||
$qnID = $_GET['questionnaireID'] ?? '';
|
||||
if ($qnID) {
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
||||
|
||||
$languages = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Question keys + translations
|
||||
$qStmt = $pdo->prepare("
|
||||
SELECT q.questionID, q.defaultText, q.configJson
|
||||
FROM question q WHERE q.questionnaireID = :id ORDER BY q.orderIndex
|
||||
");
|
||||
$qStmt->execute([':id' => $qnID]);
|
||||
$dbQuestions = $qStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$entries = [];
|
||||
$stringKeys = [];
|
||||
|
||||
foreach ($dbQuestions as $dbQ) {
|
||||
$entries[] = [
|
||||
'key' => $dbQ['defaultText'],
|
||||
'type' => 'question',
|
||||
'entityId' => $dbQ['questionID'],
|
||||
];
|
||||
|
||||
// Answer option keys
|
||||
$aoStmt = $pdo->prepare("
|
||||
SELECT answerOptionID, defaultText FROM answer_option
|
||||
WHERE questionID = :qid ORDER BY orderIndex
|
||||
");
|
||||
$aoStmt->execute([':qid' => $dbQ['questionID']]);
|
||||
foreach ($aoStmt->fetchAll(PDO::FETCH_ASSOC) as $ao) {
|
||||
$entries[] = [
|
||||
'key' => $ao['defaultText'],
|
||||
'type' => 'answer_option',
|
||||
'entityId' => $ao['answerOptionID'],
|
||||
];
|
||||
}
|
||||
|
||||
// String keys from configJson
|
||||
$config = json_decode($dbQ['configJson'] ?: '{}', true) ?: [];
|
||||
foreach (['textKey','textKey1','textKey2','hint','hint1','hint2'] as $field) {
|
||||
if (!empty($config[$field])) $stringKeys[$config[$field]] = true;
|
||||
}
|
||||
if (!empty($config['symptoms']) && is_array($config['symptoms'])) {
|
||||
foreach ($config['symptoms'] as $s) $stringKeys[$s] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($stringKeys) as $sk) {
|
||||
$entries[] = [
|
||||
'key' => $sk,
|
||||
'type' => 'string',
|
||||
'entityId' => $sk,
|
||||
];
|
||||
}
|
||||
|
||||
// Fetch all existing translations for these entities
|
||||
$translations = [];
|
||||
|
||||
// question translations
|
||||
$qIds = array_filter(array_map(fn($e) => $e['type'] === 'question' ? $e['entityId'] : null, $entries));
|
||||
if ($qIds) {
|
||||
$ph = implode(',', array_fill(0, count($qIds), '?'));
|
||||
$stmt = $pdo->prepare("SELECT questionID AS entityId, languageCode, text FROM question_translation WHERE questionID IN ($ph)");
|
||||
$stmt->execute(array_values($qIds));
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
||||
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
||||
}
|
||||
}
|
||||
|
||||
// answer_option translations
|
||||
$aoIds = array_filter(array_map(fn($e) => $e['type'] === 'answer_option' ? $e['entityId'] : null, $entries));
|
||||
if ($aoIds) {
|
||||
$ph = implode(',', array_fill(0, count($aoIds), '?'));
|
||||
$stmt = $pdo->prepare("SELECT answerOptionID AS entityId, languageCode, text FROM answer_option_translation WHERE answerOptionID IN ($ph)");
|
||||
$stmt->execute(array_values($aoIds));
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
||||
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
||||
}
|
||||
}
|
||||
|
||||
// string translations
|
||||
$sKeys = array_filter(array_map(fn($e) => $e['type'] === 'string' ? $e['entityId'] : null, $entries));
|
||||
if ($sKeys) {
|
||||
$ph = implode(',', array_fill(0, count($sKeys), '?'));
|
||||
$stmt = $pdo->prepare("SELECT stringKey AS entityId, languageCode, text FROM string_translation WHERE stringKey IN ($ph)");
|
||||
$stmt->execute(array_values($sKeys));
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
||||
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
||||
}
|
||||
}
|
||||
|
||||
// Attach translations to entries
|
||||
foreach ($entries as &$e) {
|
||||
$e['translations'] = $translations[$e['entityId']] ?? (object)[];
|
||||
}
|
||||
unset($e);
|
||||
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"languages" => $languages,
|
||||
"entries" => $entries,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Original single-entity fetch
|
||||
$type = $_GET['type'] ?? '';
|
||||
$id = $_GET['id'] ?? '';
|
||||
if (!in_array($type, $validTypes, true) || (!$id && $type !== 'string')) {
|
||||
http_response_code(400);
|
||||
echo json_encode(["error" => "type (question|answer_option|string) and id required"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
||||
if ($type === 'question') {
|
||||
$stmt = $pdo->prepare("SELECT languageCode, text FROM question_translation WHERE questionID = :id");
|
||||
$stmt->execute([':id' => $id]);
|
||||
} elseif ($type === 'answer_option') {
|
||||
$stmt = $pdo->prepare("SELECT languageCode, text FROM answer_option_translation WHERE answerOptionID = :id");
|
||||
$stmt->execute([':id' => $id]);
|
||||
} else {
|
||||
if ($id) {
|
||||
$stmt = $pdo->prepare("SELECT stringKey, languageCode, text FROM string_translation WHERE stringKey = :id");
|
||||
$stmt->execute([':id' => $id]);
|
||||
} else {
|
||||
$stmt = $pdo->query("SELECT stringKey, languageCode, text FROM string_translation ORDER BY stringKey, languageCode");
|
||||
}
|
||||
}
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true, "translations" => $rows]);
|
||||
break;
|
||||
|
||||
case 'PUT':
|
||||
require_role(['admin', 'supervisor'], $tokenRec);
|
||||
$body = json_decode(file_get_contents('php://input'), true);
|
||||
$type = $body['type'] ?? '';
|
||||
|
||||
// Language management
|
||||
if ($type === 'language') {
|
||||
$lang = trim($body['languageCode'] ?? '');
|
||||
$name = trim($body['name'] ?? '');
|
||||
if (!$lang) {
|
||||
http_response_code(400);
|
||||
echo json_encode(["error" => "languageCode required"]);
|
||||
exit;
|
||||
}
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
||||
try {
|
||||
$pdo->prepare("INSERT INTO language (languageCode, name) VALUES (:lc, :n)
|
||||
ON CONFLICT(languageCode) DO UPDATE SET name = excluded.name")
|
||||
->execute([':lc' => $lang, ':n' => $name]);
|
||||
qdb_save($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true]);
|
||||
} catch (Throwable $e) {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(["error" => "Server error"]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$id = $body['id'] ?? '';
|
||||
$lang = trim($body['languageCode'] ?? '');
|
||||
$text = $body['text'] ?? '';
|
||||
if (!in_array($type, $validTypes, true) || !$id || !$lang) {
|
||||
http_response_code(400);
|
||||
echo json_encode(["error" => "type, id, and languageCode required"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
||||
try {
|
||||
if ($type === 'question') {
|
||||
$pdo->prepare("INSERT INTO question_translation (questionID, languageCode, text)
|
||||
VALUES (:id, :lang, :t)
|
||||
ON CONFLICT(questionID, languageCode) DO UPDATE SET text = excluded.text")
|
||||
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
||||
} elseif ($type === 'answer_option') {
|
||||
$pdo->prepare("INSERT INTO answer_option_translation (answerOptionID, languageCode, text)
|
||||
VALUES (:id, :lang, :t)
|
||||
ON CONFLICT(answerOptionID, languageCode) DO UPDATE SET text = excluded.text")
|
||||
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
||||
} else {
|
||||
$pdo->prepare("INSERT INTO string_translation (stringKey, languageCode, text)
|
||||
VALUES (:id, :lang, :t)
|
||||
ON CONFLICT(stringKey, languageCode) DO UPDATE SET text = excluded.text")
|
||||
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
||||
}
|
||||
qdb_save($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true]);
|
||||
} catch (Throwable $e) {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(["error" => "Server error"]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
require_role(['admin', 'supervisor'], $tokenRec);
|
||||
$body = json_decode(file_get_contents('php://input'), true);
|
||||
$type = $body['type'] ?? '';
|
||||
|
||||
// Language deletion
|
||||
if ($type === 'language') {
|
||||
$lang = trim($body['languageCode'] ?? '');
|
||||
if (!$lang) {
|
||||
http_response_code(400);
|
||||
echo json_encode(["error" => "languageCode required"]);
|
||||
exit;
|
||||
}
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
||||
try {
|
||||
$pdo->prepare("DELETE FROM language WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
||||
$pdo->prepare("DELETE FROM question_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
||||
$pdo->prepare("DELETE FROM answer_option_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
||||
$pdo->prepare("DELETE FROM string_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
||||
qdb_save($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true]);
|
||||
} catch (Throwable $e) {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(["error" => "Server error"]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$id = $body['id'] ?? '';
|
||||
$lang = trim($body['languageCode'] ?? '');
|
||||
if (!in_array($type, $validTypes, true) || !$id || !$lang) {
|
||||
http_response_code(400);
|
||||
echo json_encode(["error" => "type, id, and languageCode required"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
||||
try {
|
||||
if ($type === 'question') {
|
||||
$pdo->prepare("DELETE FROM question_translation WHERE questionID = :id AND languageCode = :lang")
|
||||
->execute([':id' => $id, ':lang' => $lang]);
|
||||
} elseif ($type === 'answer_option') {
|
||||
$pdo->prepare("DELETE FROM answer_option_translation WHERE answerOptionID = :id AND languageCode = :lang")
|
||||
->execute([':id' => $id, ':lang' => $lang]);
|
||||
} else {
|
||||
$pdo->prepare("DELETE FROM string_translation WHERE stringKey = :id AND languageCode = :lang")
|
||||
->execute([':id' => $id, ':lang' => $lang]);
|
||||
}
|
||||
qdb_save($tmpDb, $lockFp);
|
||||
echo json_encode(["success" => true]);
|
||||
} catch (Throwable $e) {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(["error" => "Server error"]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(405);
|
||||
echo json_encode(["error" => "Method not allowed"]);
|
||||
}
|
||||
Reference in New Issue
Block a user