248 lines
9.0 KiB
PHP
248 lines
9.0 KiB
PHP
<?php
|
|
/**
|
|
* Statistics API
|
|
* GET ?action=summary&survey_id=X — Summary statistics
|
|
* GET ?action=detail&survey_id=X — Detailed per-question stats
|
|
*/
|
|
|
|
require_once __DIR__ . '/../config/database.php';
|
|
require_once __DIR__ . '/../config/auth.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
requireLogin();
|
|
|
|
$action = $_GET['action'] ?? 'summary';
|
|
$surveyId = (int)($_GET['survey_id'] ?? 0);
|
|
|
|
if (!$surveyId) jsonResponse(['error' => 'Missing survey_id'], 400);
|
|
|
|
// Check access
|
|
$db = getDB();
|
|
if (!isAdmin()) {
|
|
$stmt = $db->prepare("SELECT user_id FROM surveys WHERE id = ?");
|
|
$stmt->execute([$surveyId]);
|
|
$survey = $stmt->fetch();
|
|
if (!$survey || $survey['user_id'] != $_SESSION['user_id']) {
|
|
jsonResponse(['error' => 'ไม่มีสิทธิ์'], 403);
|
|
}
|
|
}
|
|
|
|
switch ($action) {
|
|
case 'summary':
|
|
getSummary($surveyId);
|
|
break;
|
|
case 'detail':
|
|
getDetail($surveyId);
|
|
break;
|
|
default:
|
|
jsonResponse(['error' => 'Invalid action'], 400);
|
|
}
|
|
|
|
function getSummary($surveyId) {
|
|
$db = getDB();
|
|
|
|
// Total responses
|
|
$stmt = $db->prepare("SELECT COUNT(*) as total FROM survey_responses WHERE survey_id = ?");
|
|
$stmt->execute([$surveyId]);
|
|
$total = $stmt->fetch()['total'];
|
|
|
|
// Get survey info
|
|
$stmt = $db->prepare("SELECT title, status, created_at FROM surveys WHERE id = ?");
|
|
$stmt->execute([$surveyId]);
|
|
$surveyInfo = $stmt->fetch();
|
|
|
|
// Get overall mean and SD for radio/rating questions
|
|
$stmt = $db->prepare("
|
|
SELECT
|
|
AVG(CAST(ra.answer_value AS DECIMAL(10,2))) as overall_mean,
|
|
STDDEV(CAST(ra.answer_value AS DECIMAL(10,2))) as overall_sd
|
|
FROM response_answers ra
|
|
JOIN survey_questions sq ON ra.question_id = sq.id
|
|
JOIN survey_sections ss ON sq.section_id = ss.id
|
|
WHERE ss.survey_id = ? AND sq.question_type = 'radio' AND sq.options IS NULL AND ra.answer_value REGEXP '^[0-9]+$'
|
|
");
|
|
$stmt->execute([$surveyId]);
|
|
$overall = $stmt->fetch();
|
|
|
|
jsonResponse([
|
|
'survey' => $surveyInfo,
|
|
'total_responses' => (int)$total,
|
|
'overall_mean' => $overall['overall_mean'] ? round((float)$overall['overall_mean'], 2) : 0,
|
|
'overall_sd' => $overall['overall_sd'] ? round((float)$overall['overall_sd'], 2) : 0
|
|
]);
|
|
}
|
|
|
|
function getDetail($surveyId) {
|
|
$db = getDB();
|
|
|
|
// Total responses
|
|
$stmt = $db->prepare("SELECT COUNT(*) as total FROM survey_responses WHERE survey_id = ?");
|
|
$stmt->execute([$surveyId]);
|
|
$totalResponses = (int)$stmt->fetch()['total'];
|
|
|
|
// Get sections with questions
|
|
$stmt = $db->prepare("SELECT * FROM survey_sections WHERE survey_id = ? ORDER BY section_number");
|
|
$stmt->execute([$surveyId]);
|
|
$sections = $stmt->fetchAll();
|
|
|
|
$result = [];
|
|
|
|
foreach ($sections as $section) {
|
|
$qStmt = $db->prepare("SELECT * FROM survey_questions WHERE section_id = ? ORDER BY order_num");
|
|
$qStmt->execute([$section['id']]);
|
|
$questions = $qStmt->fetchAll();
|
|
|
|
$sectionStats = [
|
|
'section_number' => $section['section_number'],
|
|
'title' => $section['title'],
|
|
'headings' => [],
|
|
'questions' => []
|
|
];
|
|
|
|
// Load headings for this section
|
|
$headingStmt = $db->prepare("SELECT * FROM survey_headings WHERE section_id = ? ORDER BY order_num");
|
|
$headingStmt->execute([$section['id']]);
|
|
$headings = $headingStmt->fetchAll();
|
|
|
|
foreach ($questions as $q) {
|
|
$qStat = [
|
|
'id' => $q['id'],
|
|
'heading_id' => $q['heading_id'] ?? null,
|
|
'question_text' => $q['question_text'],
|
|
'question_type' => $q['question_type']
|
|
];
|
|
|
|
if ($q['question_type'] === 'radio' && empty($q['options'])) {
|
|
// Calculate mean, SD, frequency for rating questions (1-5)
|
|
$aStmt = $db->prepare("
|
|
SELECT answer_value, COUNT(*) as cnt
|
|
FROM response_answers
|
|
WHERE question_id = ? AND answer_value REGEXP '^[0-9]+$'
|
|
GROUP BY answer_value
|
|
ORDER BY answer_value
|
|
");
|
|
$aStmt->execute([$q['id']]);
|
|
$freqData = $aStmt->fetchAll();
|
|
|
|
$frequencies = [];
|
|
$values = [];
|
|
$totalAnswers = 0;
|
|
|
|
for ($i = 1; $i <= 5; $i++) {
|
|
$frequencies[$i] = ['value' => $i, 'count' => 0, 'percentage' => 0];
|
|
}
|
|
|
|
foreach ($freqData as $fd) {
|
|
$val = (int)$fd['answer_value'];
|
|
if ($val >= 1 && $val <= 5) {
|
|
$frequencies[$val]['count'] = (int)$fd['cnt'];
|
|
$totalAnswers += (int)$fd['cnt'];
|
|
for ($j = 0; $j < (int)$fd['cnt']; $j++) {
|
|
$values[] = $val;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate percentages
|
|
foreach ($frequencies as &$f) {
|
|
$f['percentage'] = $totalAnswers > 0 ? round(($f['count'] / $totalAnswers) * 100, 1) : 0;
|
|
}
|
|
unset($f);
|
|
|
|
// Calculate mean
|
|
$mean = count($values) > 0 ? array_sum($values) / count($values) : 0;
|
|
|
|
// Calculate SD
|
|
$sd = 0;
|
|
if (count($values) > 1) {
|
|
$sumSquaredDiff = 0;
|
|
foreach ($values as $v) {
|
|
$sumSquaredDiff += pow($v - $mean, 2);
|
|
}
|
|
$sd = sqrt($sumSquaredDiff / (count($values) - 1));
|
|
}
|
|
|
|
// Interpretation
|
|
$interpretation = '';
|
|
if ($mean >= 4.51) $interpretation = 'มากที่สุด';
|
|
elseif ($mean >= 3.51) $interpretation = 'มาก';
|
|
elseif ($mean >= 2.51) $interpretation = 'ปานกลาง';
|
|
elseif ($mean >= 1.51) $interpretation = 'น้อย';
|
|
else $interpretation = 'น้อยที่สุด';
|
|
|
|
$qStat['mean'] = round($mean, 2);
|
|
$qStat['sd'] = round($sd, 2);
|
|
$qStat['interpretation'] = $interpretation;
|
|
$qStat['frequencies'] = array_values($frequencies);
|
|
$qStat['total_answers'] = $totalAnswers;
|
|
|
|
} elseif ($q['question_type'] === 'text') {
|
|
// Collect text responses
|
|
$aStmt = $db->prepare("
|
|
SELECT answer_value FROM response_answers
|
|
WHERE question_id = ? AND answer_value != ''
|
|
ORDER BY id DESC
|
|
");
|
|
$aStmt->execute([$q['id']]);
|
|
$qStat['text_responses'] = array_column($aStmt->fetchAll(), 'answer_value');
|
|
$qStat['total_answers'] = count($qStat['text_responses']);
|
|
|
|
} elseif (in_array($q['question_type'], ['dropdown', 'checkbox', 'radio'])) {
|
|
// Frequency for dropdown/checkbox/custom radio
|
|
$aStmt = $db->prepare("
|
|
SELECT answer_value, COUNT(*) as cnt
|
|
FROM response_answers
|
|
WHERE question_id = ?
|
|
GROUP BY answer_value
|
|
ORDER BY cnt DESC
|
|
");
|
|
$aStmt->execute([$q['id']]);
|
|
$freqData = $aStmt->fetchAll();
|
|
|
|
$totalAnswers = array_sum(array_column($freqData, 'cnt'));
|
|
$qStat['frequencies'] = array_map(function($fd) use ($totalAnswers) {
|
|
return [
|
|
'value' => $fd['answer_value'],
|
|
'count' => (int)$fd['cnt'],
|
|
'percentage' => $totalAnswers > 0 ? round(((int)$fd['cnt'] / $totalAnswers) * 100, 1) : 0
|
|
];
|
|
}, $freqData);
|
|
$qStat['total_answers'] = $totalAnswers;
|
|
}
|
|
|
|
$sectionStats['questions'][] = $qStat;
|
|
}
|
|
|
|
// Build heading stats groups
|
|
$headingStats = [];
|
|
foreach ($headings as $h) {
|
|
$hStat = [
|
|
'id' => $h['id'],
|
|
'title' => $h['title'],
|
|
'description' => $h['description'],
|
|
'questions' => []
|
|
];
|
|
foreach ($sectionStats['questions'] as $qs) {
|
|
if (($qs['heading_id'] ?? null) == $h['id']) {
|
|
$hStat['questions'][] = $qs;
|
|
}
|
|
}
|
|
$headingStats[] = $hStat;
|
|
}
|
|
$sectionStats['headings'] = $headingStats;
|
|
|
|
// Filter loose questions (no heading)
|
|
$sectionStats['questions'] = array_values(array_filter($sectionStats['questions'], function($qs) {
|
|
return empty($qs['heading_id']);
|
|
}));
|
|
|
|
$result[] = $sectionStats;
|
|
}
|
|
|
|
jsonResponse([
|
|
'total_responses' => $totalResponses,
|
|
'sections' => $result
|
|
]);
|
|
}
|