diff --git a/assets/css/scss/_survey.scss b/assets/css/scss/_survey.scss new file mode 100644 index 00000000000..fe294b5569f --- /dev/null +++ b/assets/css/scss/_survey.scss @@ -0,0 +1,106 @@ +.ch-survey-report { + // ---- design tokens (tweak freely) ---- + $border: #e5e7eb; + $bg-soft: #f9fafb; + $bg-muted: #f3f4f6; + $text: #111827; + $shadow: 0 1px 2px rgba(0, 0, 0, .04); + + // ---- card ---- + .sr-card { + border: 1px solid $border; + border-radius: 12px; + box-shadow: $shadow; + margin-bottom: 18px; + + &__header { + padding: 12px 16px; + font-weight: 700; + background: $bg-soft; + border-bottom: 1px solid $border; + } + &__body { + padding: 12px 16px; + } + } + + // ---- compact table look used in the survey summary (#pdf_table) ---- + .sr-summary-table { + margin: 0; + border-radius: 10px; + overflow: hidden; + + th, + td { + border-color: $border; + color: $text; + background: #fff; + } + + th[scope="row"] { + width: 260px; + white-space: nowrap; + background: $bg-muted; // subtle contrast for labels + font-weight: 600; + vertical-align: middle; + } + + tr + tr { + th, + td { + border-top: 1px solid $border; + } + } + } + + // ---- generic “block” spacing helpers used in question sections ---- + .sr-block { + margin-top: 10px; + } + + // ---- optional: progress bar style used inside the “Graphic” column ---- + .sr-progress { + // outer track + background: #eef2ff; + border: 1px solid #c7d2fe; + height: 10px; + position: relative; + border-radius: 4px; + overflow: hidden; + + // inner fill + &__fill { + height: 100%; + width: 0; // set inline (e.g., style="width:66%") + background: #93c5fd; + } + } + + // ---- spacing for the number pagination row (if present) ---- + #question_report_questionnumbers { + margin: 10px 0 16px; + display: flex; + gap: 6px; + + li { + list-style: none; + + a { + display: block; + padding: 6px 10px; + border: 1px solid $border; + border-radius: 8px; + background: #fff; + color: $text; + text-decoration: none; + + &:hover { background: $bg-soft; } + } + + &.disabled a { + opacity: .6; + pointer-events: none; + } + } + } +} diff --git a/assets/css/scss/index.scss b/assets/css/scss/index.scss index f3be25762c0..12032ea6f9c 100755 --- a/assets/css/scss/index.scss +++ b/assets/css/scss/index.scss @@ -99,5 +99,6 @@ @include meta.load-css("userreluser"); @include meta.load-css('social'); @include meta.load-css('skill'); +@include meta.load-css('survey'); @include meta.load-css("libs/mediaelementjs/styles"); diff --git a/public/main/survey/survey.lib.php b/public/main/survey/survey.lib.php index d8dc1d2256f..8a7c484133b 100644 --- a/public/main/survey/survey.lib.php +++ b/public/main/survey/survey.lib.php @@ -32,19 +32,15 @@ public static function generate_unique_code(string $code, ?int $surveyId = null) if (empty($code)) { return false; } - $course_id = api_get_course_int_id(); $table = Database::get_course_table(TABLE_SURVEY); $code = Database::escape_string($code); $num = 0; $new_code = $code; while (true) { - if (isset($surveyId)) { - $sql = "SELECT * FROM $table - WHERE code = '$new_code' AND iid = $surveyId"; + $sql = "SELECT 1 FROM $table WHERE code = '$new_code' AND iid = $surveyId"; } else { - $sql = "SELECT * FROM $table - WHERE code = '$new_code'"; + $sql = "SELECT 1 FROM $table WHERE code = '$new_code'"; } $result = Database::query($sql); @@ -140,12 +136,11 @@ public static function get_survey( $survey_id = (int) $survey_id; $table_survey = Database::get_course_table(TABLE_SURVEY); - if (empty($courseInfo)) { + if (empty($courseInfo) || empty($survey_id)) { return []; } - $sql = "SELECT * FROM $table_survey - WHERE iid = $survey_id"; + $sql = "SELECT * FROM $table_survey WHERE iid = $survey_id"; $result = Database::query($sql); $return = []; @@ -154,27 +149,18 @@ public static function get_survey( if ($simple_return) { return $return; } - // We do this (temporarily) to have the array match the quickform elements immediately - // idealiter the fields in the db match the quickform fields - $return['survey_code'] = $return['code']; - $return['survey_title'] = $return['title']; - $return['survey_subtitle'] = $return['subtitle']; - $return['survey_language'] = $return['lang']; - $return['start_date'] = $return['avail_from']; - $return['end_date'] = $return['avail_till']; - $return['survey_share'] = $return['is_shared']; - $return['survey_introduction'] = $return['intro']; - $return['survey_thanks'] = $return['surveythanks']; - $return['survey_type'] = $return['survey_type']; - $return['one_question_per_page'] = $return['one_question_per_page']; - $return['show_form_profile'] = $return['show_form_profile']; - $return['input_name_list'] = isset($return['input_name_list']) ? $return['input_name_list'] : null; - $return['shuffle'] = $return['shuffle']; - $return['parent_id'] = $return['parent_id']; - $return['survey_version'] = $return['survey_version']; - $return['anonymous'] = $return['anonymous']; - $return['c_id'] = isset($return['c_id']) ? $return['c_id'] : 0; - $return['session_id'] = isset($return['session_id']) ? $return['session_id'] : 0; + $return['survey_code'] = $return['code']; + $return['survey_title'] = $return['title']; + $return['survey_subtitle'] = $return['subtitle']; + $return['survey_language'] = $return['lang']; + $return['start_date'] = $return['avail_from']; + $return['end_date'] = $return['avail_till']; + $return['survey_share'] = $return['is_shared']; + $return['survey_introduction'] = $return['intro']; + $return['survey_thanks'] = $return['surveythanks']; + $return['input_name_list'] = $return['input_name_list'] ?? null; + $return['c_id'] = $return['c_id'] ?? 0; + $return['session_id'] = $return['session_id'] ?? 0; } return $return; @@ -203,148 +189,95 @@ public static function generateSurveyCode($code) */ public static function store_survey($values) { + $return = ['id' => 0]; $session_id = api_get_session_id(); - $courseCode = api_get_course_id(); $table_survey = Database::get_course_table(TABLE_SURVEY); $shared_survey_id = 0; $displayQuestionNumber = isset($values['display_question_number']); $repo = Container::getSurveyRepository(); - if (!isset($values['survey_id'])) { - // Check if the code doesn't soon exists in this language + if (empty($values['survey_id'])) { + $normalizedCode = self::generateSurveyCode($values['survey_code'] ?? ''); + $lang = $values['survey_language'] ?? api_get_language_isocode(); + $sql = 'SELECT 1 FROM '.$table_survey.' - WHERE - code = "'.Database::escape_string($values['survey_code']).'" AND - lang = "'.Database::escape_string($values['survey_language']).'"'; + WHERE code = "'.Database::escape_string($normalizedCode).'" + AND lang = "'.Database::escape_string($lang).'"'; $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { Display::addFlash( - Display::return_message( - get_lang('This survey code soon exists in this language'), - 'error' - ) + Display::return_message(get_lang('This survey code soon exists in this language'), 'error') ); - $return['type'] = 'error'; - $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; - - return $return; - } - - if (!isset($values['anonymous'])) { - $values['anonymous'] = 0; + return ['type' => 'error', 'id' => 0]; } - $values['anonymous'] = (int) $values['anonymous']; + $values['anonymous'] = !empty($values['anonymous']) ? 1 : 0; + $onePerPage = !empty($values['one_question_per_page']) ? 1 : 0; + $shuffle = !empty($values['shuffle']) ? 1 : 0; $survey = new CSurvey(); - $extraParams = []; if (0 == $values['anonymous']) { - // Input_name_list - $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0; + $values['show_form_profile'] = !empty($values['show_form_profile']) ? 1 : 0; $survey->setShowFormProfile($values['show_form_profile']); if (1 == $values['show_form_profile']) { - // Input_name_list - $fields = explode(',', $values['input_name_list']); + $fields = explode(',', $values['input_name_list'] ?? ''); $field_values = ''; - foreach ($fields as &$field) { - if ('' != $field) { - if ('' == $values[$field]) { - $values[$field] = 0; - } - $field_values .= $field.':'.$values[$field].'@'; - } + foreach ($fields as $field) { + if ($field === '') { continue; } + $v = isset($values[$field]) && $values[$field] !== '' ? $values[$field] : 0; + $field_values .= $field.':'.$v.'@'; } - $extraParams['form_fields'] = $field_values; + $survey->setFormFields($field_values); } else { - $extraParams['form_fields'] = ''; + $survey->setFormFields(''); } - $survey->setFormFields($extraParams['form_fields']); + } else { + $survey->setFormFields(''); + $survey->setShowFormProfile(0); } - $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0; - $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0; - - if (1 == $values['survey_type']) { - $survey - ->setSurveyType(1) - ->setShuffle($values['shuffle']) - ->setOneQuestionPerPage($values['one_question_per_page']) - ; - // Logic for versioning surveys - if (!empty($values['parent_id'])) { - $parentId = (int) $values['parent_id']; - $sql = 'SELECT survey_version - FROM '.$table_survey.' - WHERE - parent_id = '.$parentId.' - ORDER BY survey_version DESC - LIMIT 1'; - $rs = Database::query($sql); - if (0 === Database::num_rows($rs)) { - $sql = 'SELECT survey_version FROM '.$table_survey.' - WHERE - iid = '.$parentId; - $rs = Database::query($sql); - $getversion = Database::fetch_assoc($rs); - if (empty($getversion['survey_version'])) { - $versionValue = ++$getversion['survey_version']; - } else { - $versionValue = $getversion['survey_version']; - } - } else { - $row = Database::fetch_assoc($rs); - $pos = api_strpos($row['survey_version'], '.'); - if (false === $pos) { - $row['survey_version'] = $row['survey_version'] + 1; - $versionValue = $row['survey_version']; - } else { - $getlast = explode('\.', $row['survey_version']); - $lastversion = array_pop($getlast); - $lastversion = $lastversion + 1; - $add = implode('.', $getlast); - if ('' != $add) { - $insertnewversion = $add.'.'.$lastversion; - } else { - $insertnewversion = $lastversion; - } - $versionValue = $insertnewversion; - } - } - $survey->setSurveyVersion($versionValue); - } + try { + $start = new \DateTime($values['start_date']); + $end = new \DateTime($values['end_date']); + } catch (\Exception $e) { + Display::addFlash(Display::return_message(get_lang('Invalid date'), 'error')); + return ['type' => 'error', 'id' => 0]; } - $course = api_get_course_entity(); + $course = api_get_course_entity(); $session = api_get_session_entity(); $survey - ->setCode(self::generateSurveyCode($values['survey_code'])) + ->setCode($normalizedCode) ->setTitle($values['survey_title']) - ->setSubtitle($values['survey_title']) - ->setLang($values['survey_language']) - ->setAvailFrom(new \DateTime($values['start_date'])) - ->setAvailTill(new \DateTime($values['end_date'])) + ->setSubtitle($values['survey_subtitle'] ?? '') + ->setLang($lang) + ->setAvailFrom($start) + ->setAvailTill($end) ->setIsShared($shared_survey_id) ->setTemplate('template') ->setIntro($values['survey_introduction']) ->setSurveyThanks($values['survey_thanks']) ->setDisplayQuestionNumber($displayQuestionNumber) - ->setAnonymous((string) $values['anonymous']) - ->setVisibleResults((int) $values['visible_results']) - ->setSurveyType((int) ($values['survey_type'] ?? 1)) + ->setAnonymous((string) ((int) $values['anonymous'])) + ->setVisibleResults((int) ($values['visible_results'] ?? SURVEY_VISIBLE_TUTOR)) + ->setSurveyType((int) ($values['survey_type'] ?? 0)) + ->setOneQuestionPerPage($onePerPage) + ->setShuffle($shuffle) ->setParent($course) - ->addCourseLink($course, $session) - ; + ->addCourseLink($course, $session); - if (isset($values['parent_id']) && !empty($values['parent_id'])) { - $parent = $repo->find($values['parent_id']); - $survey->setSurveyParent($parent); + if (!empty($values['parent_id'])) { + $parent = $repo->find((int) $values['parent_id']); + if ($parent) { + $survey->setSurveyParent($parent); + } } $repo->create($survey); + $survey_id = (int) $survey->getIid(); - $survey_id = $survey->getIid(); if ($survey_id > 0) { Event::addEvent( LOG_SURVEY_CREATED, @@ -357,65 +290,67 @@ public static function store_survey($values) ); } - if (1 == $values['survey_type'] && !empty($values['parent_id'])) { - self::copySurvey($values['parent_id'], $survey_id); + if ((int) ($values['survey_type'] ?? 0) === 1 && !empty($values['parent_id'])) { + self::copySurvey((int) $values['parent_id'], $survey_id); } Display::addFlash( - Display::return_message( - get_lang('The survey has been created successfully'), - 'success' - ) + Display::return_message(get_lang('The survey has been created successfully'), 'success') ); $return['id'] = $survey_id; } else { - // Check whether the code doesn't soon exists in this language - $sql = 'SELECT 1 FROM '.$table_survey.' - WHERE - code = "'.Database::escape_string($values['survey_code']).'" AND - lang = "'.Database::escape_string($values['survey_language']).'" AND - iid !='.intval($values['survey_id']); - $rs = Database::query($sql); - if (Database::num_rows($rs) > 0) { - Display::addFlash( - Display::return_message( - get_lang('This survey code soon exists in this language'), - 'error' - ) - ); - $return['type'] = 'error'; - $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; + $surveyId = (int) $values['survey_id']; - return $return; + /** @var CSurvey $survey */ + $survey = $repo->find($surveyId); + if (!$survey) { + Display::addFlash(Display::return_message(get_lang('Survey not found'), 'error')); + return ['type' => 'error', 'id' => $surveyId]; } - if (!isset($values['anonymous']) - || (isset($values['anonymous']) && '' == $values['anonymous']) - ) { - $values['anonymous'] = 0; + $inputCode = isset($values['survey_code']) ? self::generateSurveyCode($values['survey_code']) : $survey->getCode(); + $inputLang = $values['survey_language'] ?? $survey->getLang(); + $codeChanged = ($inputCode !== $survey->getCode()) || ($inputLang !== $survey->getLang()); + + if ($codeChanged) { + $sql = 'SELECT 1 FROM '.$table_survey.' + WHERE code = "'.Database::escape_string($inputCode).'" + AND lang = "'.Database::escape_string($inputLang).'" + AND iid <> '.(int) $surveyId; + $rs = Database::query($sql); + if (Database::num_rows($rs) > 0) { + Display::addFlash( + Display::return_message(get_lang('This survey code soon exists in this language'), 'error') + ); + return ['type' => 'error', 'id' => $surveyId]; + } + // Aplica nuevo code/lang si cambiaron + $survey->setCode($inputCode); + $survey->setLang($inputLang); } - /** @var CSurvey $survey */ - $survey = $repo->find($values['survey_id']); - - $survey->setOneQuestionPerPage(isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0); - $survey->setShuffle(isset($values['shuffle']) ? $values['shuffle'] : 0); + $values['anonymous'] = !empty($values['anonymous']) ? 1 : 0; + $onePerPage = !empty($values['one_question_per_page']) ? 1 : 0; + $shuffle = !empty($values['shuffle']) ? 1 : 0; + $showFormProfile = !empty($values['show_form_profile']) ? 1 : 0; + + try { + $start = !empty($values['start_date']) ? new \DateTime($values['start_date']) : $survey->getAvailFrom(); + $end = !empty($values['end_date']) ? new \DateTime($values['end_date']) : $survey->getAvailTill(); + } catch (\Exception $e) { + Display::addFlash(Display::return_message(get_lang('Invalid date'), 'error')); + return ['type' => 'error', 'id' => $surveyId]; + } if (0 == $values['anonymous']) { - $survey->setShowFormProfile(isset($values['show_form_profile']) ? $values['show_form_profile'] : 0); - $isFormProfile = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0; - if (1 == $isFormProfile) { - $fields = explode(',', $values['input_name_list']); + $survey->setShowFormProfile($showFormProfile); + if (1 == $showFormProfile) { + $fields = explode(',', $values['input_name_list'] ?? ''); $field_values = ''; - foreach ($fields as &$field) { - if ('' != $field) { - if (!isset($values[$field]) || - (isset($values[$field]) && '' == $values[$field]) - ) { - $values[$field] = 0; - } - $field_values .= $field.':'.$values[$field].'@'; - } + foreach ($fields as $field) { + if ($field === '') { continue; } + $v = isset($values[$field]) && $values[$field] !== '' ? $values[$field] : 0; + $field_values .= $field.':'.$v.'@'; } $survey->setFormFields($field_values); } else { @@ -428,48 +363,31 @@ public static function store_survey($values) $survey ->setTitle($values['survey_title']) - ->setSubtitle($values['survey_title']) - ->setLang($values['survey_language']) - ->setAvailFrom(new \DateTime($values['start_date'])) - ->setAvailTill(new \DateTime($values['end_date'])) + ->setSubtitle($values['survey_subtitle'] ?? '') + ->setAvailFrom($start) + ->setAvailTill($end) ->setIsShared($shared_survey_id) ->setTemplate('template') ->setIntro($values['survey_introduction']) ->setSurveyThanks($values['survey_thanks']) - ->setAnonymous((string) $values['anonymous']) - ->setVisibleResults((int) $values['visible_results']) + ->setAnonymous((string) ((int) $values['anonymous'])) + ->setVisibleResults((int) ($values['visible_results'] ?? SURVEY_VISIBLE_TUTOR)) ->setDisplayQuestionNumber($displayQuestionNumber) - ; - - $repo->update($survey); - /* - // Update into item_property (update) - api_item_property_update( - api_get_course_info(), - TOOL_SURVEY, - $values['survey_id'], - 'SurveyUpdated', - api_get_user_id() - );*/ + ->setOneQuestionPerPage($onePerPage) + ->setShuffle($shuffle); + + $em = Database::getManager(); + $em->persist($survey); + $em->flush(); Display::addFlash( - Display::return_message( - get_lang('The survey has been updated successfully'), - 'confirmation' - ) + Display::return_message(get_lang('The survey has been updated successfully'), 'confirmation') ); - - $return['id'] = $values['survey_id']; + $return['id'] = $surveyId; } $survey_id = (int) $return['id']; - - // Gradebook - $gradebook_option = false; - if (isset($values['survey_qualify_gradebook'])) { - $gradebook_option = $values['survey_qualify_gradebook'] > 0; - } - + $gradebook_option = !empty($values['survey_qualify_gradebook']); $gradebook_link_type = 8; $link_info = GradebookUtils::isResourceInCourseGradebook( api_get_course_int_id(), @@ -477,36 +395,33 @@ public static function store_survey($values) $survey_id, $session_id ); - - $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false; + $gradebook_link_id = $link_info['id'] ?? false; if ($gradebook_option) { - if ($survey_id > 0) { - $title_gradebook = ''; // Not needed here. - $description_gradebook = ''; // Not needed here. - $survey_weight = floatval($_POST['survey_weight']); - $max_score = 1; - - if (!$gradebook_link_id && isset($values['category_id'])) { - GradebookUtils::add_resource_to_course_gradebook( - $values['category_id'], - api_get_course_int_id(), - $gradebook_link_type, - $survey_id, - $title_gradebook, - $survey_weight, - $max_score, - $description_gradebook, - 1, - $session_id - ); - } else { - GradebookUtils::updateResourceFromCourseGradebook( - $gradebook_link_id, - api_get_course_int_id(), - $survey_weight - ); - } + $survey_weight = isset($values['survey_weight']) + ? (float) $values['survey_weight'] + : (isset($_POST['survey_weight']) ? (float) $_POST['survey_weight'] : 0.0); + $max_score = 1; + + if (!$gradebook_link_id && isset($values['category_id'])) { + GradebookUtils::add_resource_to_course_gradebook( + $values['category_id'], + api_get_course_int_id(), + $gradebook_link_type, + $survey_id, + '', + $survey_weight, + $max_score, + '', + 1, + $session_id + ); + } else { + GradebookUtils::updateResourceFromCourseGradebook( + $gradebook_link_id, + api_get_course_int_id(), + $survey_weight + ); } } else { // Delete everything of the gradebook for this $linkId @@ -1977,6 +1892,10 @@ public static function checkTimeAvailability(?CSurvey $survey): void api_not_allowed(true); } + if (api_is_allowed_to_edit()) { + return; + } + $utcZone = new DateTimeZone('UTC'); $startDate = $survey->getAvailFrom(); $endDate = $survey->getAvailTill(); diff --git a/public/main/survey/surveyUtil.class.php b/public/main/survey/surveyUtil.class.php index 3f1d204bbfa..3d0065c2a1f 100644 --- a/public/main/survey/surveyUtil.class.php +++ b/public/main/survey/surveyUtil.class.php @@ -241,30 +241,41 @@ public static function handleReportingActions(CSurvey $survey, array $people_fil self::display_comparative_report(); break; case 'completereport': - $surveysAnswered = SurveyManager::getInvitationsAnswered( + // Render once per unique (survey_id, lp_item_id) pair to avoid duplicates. + $answered = SurveyManager::getInvitationsAnswered( $survey->getCode(), api_get_course_int_id(), api_get_session_id() ); - if (!empty($surveysAnswered)) { - foreach ($surveysAnswered as $invitation) { - $surveyEntity = $invitation->getSurvey(); - if (!$surveyEntity) { - continue; - } + $rendered = []; + $showNames = ($survey->getAnonymous() === '0'); - $showNames = ($surveyEntity->getAnonymous() === '0'); + // If no invitations answered, still show a single consolidated report. + if (empty($answered)) { + echo self::displayCompleteReport($survey, 0, true, true, $showNames, 0); + break; + } - echo SurveyUtil::displayCompleteReport( - $surveyEntity, - 0, - true, - true, - $showNames, - (int) $invitation->getLpItemId() - ); + foreach ($answered as $inv) { + $s = $inv->getSurvey(); + if (!$s) { + continue; } + $key = $s->getIid().':'.(int) $inv->getLpItemId(); + if (isset($rendered[$key])) { + continue; // already rendered this bucket + } + $rendered[$key] = true; + + echo self::displayCompleteReport( + $s, + 0, // all users + true, // action bar + true, // filters + $showNames, // extra user fields only if not anonymous + (int) $inv->getLpItemId() + ); } break; case 'deleteuserreport': @@ -561,7 +572,6 @@ public static function displayUserReport(CSurvey $survey, $people_filled, $addAc public static function display_question_report(CSurvey $survey) { $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0; - // Determining the offset of the sql statement (the n-th question of the survey) $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question']; $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0; $surveyId = $survey->getIid(); @@ -574,13 +584,13 @@ public static function display_question_report(CSurvey $survey) $sessionCondition = api_get_session_condition($sessionId); } - // Database table definitions + // DB tables $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION); $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); - $actions = ''. + // Toolbar + $actions = ''. Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview')). ''; $actions .= Display::url( @@ -590,7 +600,9 @@ public static function display_question_report(CSurvey $survey) ); echo Display::toolbarAction('survey', [$actions]); + echo '
'; + // Survey header table (used for PDF too) $fromUntil = sprintf( get_lang('From %s until %s'), api_get_local_time($survey->getAvailFrom()), @@ -604,7 +616,8 @@ public static function display_question_report(CSurvey $survey) get_lang('Survey introduction') => cut(strip_tags($survey->getIntro()), $max), ]; - $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']); + $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table table-bordered table-sm sr-table']); + $row = 0; foreach ($data as $label => $item) { $table->setCellContents($row, 0, $label); @@ -612,18 +625,19 @@ public static function display_question_report(CSurvey $survey) $row++; } + // Question list $questions = $survey->getQuestions(); $numberOfQuestions = 0; - foreach ($questions as $question) { - if ('pagebreak' !== $question->getType()) { + foreach ($questions as $q) { + if ('pagebreak' !== $q->getType()) { $numberOfQuestions++; } } $newQuestionList = []; if ($numberOfQuestions > 0) { - $limitStatement = null; if (!$singlePage) { + // Pagination (question numbers) echo ''; - $limitStatement = " LIMIT $offset, 1"; } - // Getting the question information - /*$sql = "SELECT * FROM $table_survey_question - WHERE - survey_id = $surveyId AND - survey_question NOT LIKE '%{{%' AND - type <>'pagebreak' - ORDER BY sort ASC - $limitStatement"; - $result = Database::query($sql); - while ($row = Database::fetch_array($result)) {*/ - foreach ($questions as $question) { - if (strpos($question->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $question->getType()) { + // Build list (skip tagged/pagebreak) + foreach ($questions as $q) { + if (strpos($q->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $q->getType()) { continue; } - $newQuestionList[$question->getIid()] = $question; - } - } + $newQuestionList[$q->getIid()] = $q; + } + } + + // Pretty container + echo '
'; + + // Survey info card + // Survey info card (pretty, keeps #pdf_table for PDF export) + echo '
'; + echo '
'.get_lang('Survey').'
'; + echo '
'; + + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo '
'.get_lang('Survey title').''.cut(strip_tags($survey->getTitle()), $max).'
'.get_lang('Survey subtitle').''.cut(strip_tags($survey->getSubtitle()), $max).'
'.get_lang('Dates').''.$fromUntil.'
'.get_lang('Survey introduction').''.cut(strip_tags($survey->getIntro()), $max).'
'; + + echo '
'; + echo '
'; + echo '
'; /** @var CSurveyQuestion $question */ foreach ($newQuestionList as $question) { $chartData = []; $options = []; $questionId = $question->getIid(); - - echo '
'; - echo '
'; - echo strip_tags($question->getSurveyQuestion()); - echo '
'; $type = $question->getType(); + // Card wrapper per question + echo '
'; + echo '
'.get_lang('Question').'
'; + echo '
'; + + echo '
'.strip_tags($question->getSurveyQuestion()).'
'; + if ('score' === $type) { - /** @todo This function should return the options as this is needed further in the code */ - $options = self::display_question_report_score($survey, $question, $offset); + // Score-type + self::display_question_report_score($survey, $question, $offset); } elseif ('open' === $type || 'comment' === $type) { - echo '
'; - /** @todo Also get the user who has answered this */ + // Open/comment as list + echo '
    '; $sql = "SELECT * FROM $table_survey_answer - WHERE - survey_id= $surveyId AND - question_id = $questionId "; + WHERE survey_id= $surveyId AND question_id = $questionId "; $result = Database::query($sql); while ($row = Database::fetch_assoc($result)) { - echo $row['option_id'].'
    '; + echo '
  • '.api_htmlentities($row['option_id'], ENT_QUOTES).'
  • '; } - echo '
'; + echo '
'; } else { - // Getting the options ORDER BY sort ASC + // Choice-based questions $sql = "SELECT * FROM $table_survey_question_option - WHERE - survey_id = $surveyId AND - question_id = $questionId - ORDER BY sort ASC"; + WHERE survey_id = $surveyId AND question_id = $questionId + ORDER BY sort ASC"; $result = Database::query($sql); while ($row = Database::fetch_assoc($result)) { $options[$row['iid']] = $row; } - // Getting the answers + $sql = "SELECT *, count(iid) as total - FROM $table_survey_answer - WHERE - survey_id = $surveyId AND - question_id = $questionId - GROUP BY option_id, value"; + FROM $table_survey_answer + WHERE survey_id = $surveyId AND question_id = $questionId + GROUP BY option_id, value"; $result = Database::query($sql); $number_of_answers = []; $data = []; @@ -727,133 +760,111 @@ public static function display_question_report(CSurvey $survey) $data[$row['option_id']] = $row; } - foreach ($options as $option) { - $optionText = strip_tags($option['option_text']); + foreach ($options as $opt) { + $optionText = strip_tags($opt['option_text']); $optionText = html_entity_decode($optionText); - $votes = 0; - if (isset($data[$option['iid']]['total'])) { - $votes = $data[$option['iid']]['total']; - } - array_push($chartData, ['option' => $optionText, 'votes' => $votes]); + $votes = isset($data[$opt['iid']]['total']) ? $data[$opt['iid']]['total'] : 0; + $chartData[] = ['option' => $optionText, 'votes' => $votes]; } + $chartContainerId = 'chartContainer'.$questionId; - echo '
'; + echo '
'; echo self::drawChart($chartData, false, $chartContainerId, false); echo '
'; - // displaying the table: headers - echo ''; - echo ''; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - - // Displaying the table: the content + // Table (bordered/striped/compact) + echo '
 '.get_lang('Absolute total').''.get_lang('Percentage').''.get_lang('Graphic').'
'; + echo ' + + + + + '; + if (is_array($options)) { - foreach ($options as $key => &$value) { + foreach ($options as $key => $value) { if ('multiplechoiceother' === $type && 'other' === $value['option_text']) { $value['option_text'] = get_lang('Please specify:'); } - - $absolute_number = null; - if (isset($data[$value['iid']])) { - $absolute_number = $data[$value['iid']]['total']; - } + $absolute_number = isset($data[$value['iid']]) ? $data[$value['iid']]['total'] : 0; if ('percentage' === $type && empty($absolute_number)) { continue; } - $number_of_answers[$option['question_id']] = isset($number_of_answers[$option['question_id']]) - ? $number_of_answers[$option['question_id']] - : 0; - if (0 == $number_of_answers[$option['question_id']]) { - $answers_number = 0; - } else { - $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100; - } - echo ' '; + $qid = $value['question_id'] ?? null; + $totalAnswers = $qid && isset($number_of_answers[$qid]) ? $number_of_answers[$qid] : 0; + $percentage = $totalAnswers ? ($absolute_number / $totalAnswers * 100) : 0; + + echo ''; echo ''; echo ''; - echo ''; + echo ''; + echo ''; echo ''; - echo ' '; + // Simple progress bar (no external JS/CSS needed) + $w = max(0, min(100, round($percentage, 2))); + echo '
' + .'
' + .'
'; + echo ''; + echo ''; } } - $optionResult = ''; + $optionResult = '0'; if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) { - if (0 == $number_of_answers[$option['question_id']]) { - $optionResult = '0'; - } else { - $optionResult = $number_of_answers[$option['question_id']]; - } + $optionResult = $number_of_answers[$option['question_id']] ?: '0'; } - // displaying the table: footer (totals) - echo ' - - - - - -
 '.get_lang('Absolute total').''.get_lang('Percentage').''.get_lang('Graphic').'
'.$value['option_text'].''; if (0 != $absolute_number) { echo ''.$absolute_number.''; + .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='.$value['iid'].'">'.$absolute_number.''; } else { echo '0'; } - - echo ' '.round($answers_number, 2).' %'.round($percentage, 2).' %'; - $size = $answers_number * 2; - if ($size > 0) { - echo '
-   -
'; - } else { - echo '
'.get_lang("No data available").'
'; - } - echo '
'.get_lang('Total').''.$optionResult.'  
'; + echo ' + '.get_lang('Total').' + '.$optionResult.' +   +   + '; + echo ''; } - echo '
'; - } - echo '
'; - // Survey information, needed for the PDF export. - echo Display::page_subheader(get_lang('Survey')).'
'; - $table->display(); + echo '
'; // body + echo '
'; // card + } + echo '
'; // #question_results + echo '
'; // .sr-container + // People who chose specific option if (isset($_GET['viewoption'])) { + echo '
'; + echo '
'.get_lang('Details').'
'; echo '
'; echo '

'.get_lang('People who have chosen this answer').': ' .strip_tags($options[Security::remove_XSS($_GET['viewoption'])]['option_text']).'

'; if (is_numeric($_GET['value'])) { $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'"; + } else { + $sql_restriction = ''; } $sql = "SELECT user FROM $table_survey_answer - WHERE - c_id = $course_id AND - option_id = '".Database::escape_string($_GET['viewoption'])."' - $sql_restriction $sessionCondition"; + WHERE c_id = $course_id + AND option_id = '".Database::escape_string($_GET['viewoption'])."' + $sql_restriction $sessionCondition"; $result = Database::query($sql); echo ''; - echo '
'; + echo '
'; } + echo ''; } /** @@ -863,7 +874,6 @@ public static function display_question_report(CSurvey $survey) */ public static function display_question_report_score(CSurvey $survey, CSurveyQuestion $question, $offset) { - // Database table definitions $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : ''; $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); $surveyId = $survey->getIid(); @@ -876,109 +886,84 @@ public static function display_question_report_score(CSurvey $survey, CSurveyQue $sessionCondition = api_get_session_condition($sessionId); } - foreach ($options as $option) { - $options[$option->getIid()] = $option; + foreach ($options as $opt) { + $options[$opt->getIid()] = $opt; } - // Getting the answers + // Answers summary $sql = "SELECT *, count(iid) as total - FROM $table_survey_answer - WHERE - survey_id= $surveyId AND - question_id = '".$questionId."' - $sessionCondition - GROUP BY option_id, value"; + FROM $table_survey_answer + WHERE survey_id= $surveyId AND question_id = '".$questionId."' + $sessionCondition + GROUP BY option_id, value"; $result = Database::query($sql); $number_of_answers = 0; + $data = []; while ($row = Database::fetch_array($result)) { $number_of_answers += $row['total']; $data[$row['option_id']][$row['value']] = $row; } + // Chart data $chartData = []; /** @var CSurveyQuestionOption $option */ foreach ($options as $option) { $optionId = $option->getIid(); - $optionText = strip_tags($option->getOptionText()); - $optionText = html_entity_decode($optionText); + $optionText = html_entity_decode(strip_tags($option->getOptionText())); for ($i = 1; $i <= $question->getMaxValue(); $i++) { - $votes = null; - if (isset($data[$optionId][$i])) { - $votes = $data[$optionId][$i]['total']; - } - - if (empty($votes)) { - $votes = '0'; - } - array_push( - $chartData, - [ - 'serie' => $optionText, - 'option' => $i, - 'votes' => $votes, - ] - ); + $votes = isset($data[$optionId][$i]) ? $data[$optionId][$i]['total'] : 0; + $chartData[] = ['serie' => $optionText, 'option' => $i, 'votes' => $votes]; } } - echo '
'; + + echo '
'; + echo '
'; echo self::drawChart($chartData, true); echo '
'; - // Displaying the table: headers - echo ''; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - // Displaying the table: the content + // Table (styled) + echo '
 '.get_lang('Score').''.get_lang('Absolute total').''.get_lang('Percentage').''.get_lang('Graphic').'
'; + echo ' + + + + + + '; + foreach ($options as $key => $value) { $optionId = $value->getIid(); for ($i = 1; $i <= $question->getMaxValue(); $i++) { - $absolute_number = null; - if (isset($data[$optionId][$i])) { - $absolute_number = $data[$optionId][$i]['total']; + $absolute_number = isset($data[$optionId][$i]) ? $data[$optionId][$i]['total'] : 0; + + $percentage = 0; + $size = 0; + if (!empty($number_of_answers)) { + $percentage = round($absolute_number / $number_of_answers * 100, 2); + $size = $percentage; // 0..100 } echo ''; echo ''; echo ''; - echo ''; - - $percentage = 0; - $size = 0; - if (!empty($number_of_answers)) { - $percentage = round($absolute_number / $number_of_answers * 100, 2); - $size = ($absolute_number / $number_of_answers * 100 * 2); - } echo ''; echo ''; - echo ' '; - } - } - // Displaying the table: footer (totals) - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; + echo '
' + .'
' + .'
'; + echo ''; + echo ''; + } + } + + echo ' + + '; echo '
 '.get_lang('Score').''.get_lang('Absolute total').''.get_lang('Percentage').''.get_lang('Graphic').'
'.$value->getOptionText().''.$i.''.$absolute_number.''.$percentage.' %'; - if ($size > 0) { - echo '
-   -
'; - } - echo '
'.get_lang('Total').' '.$number_of_answers.'  
'.get_lang('Total').': '.$number_of_answers.'
'; + echo '
'; } /** @@ -993,20 +978,19 @@ public static function display_question_report_score(CSurvey $survey, CSurveyQue */ public static function displayCompleteReport( CSurvey $survey, - $userId = 0, - $addActionBar = true, - $addFilters = true, - $addExtraFields = true, - $lpItemId = 0 + $userId = 0, + $addActionBar = true, + $addFilters = true, + $addExtraFields = true, + $lpItemId = 0 ) { - // Database table definitions + // DB tables $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION); $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); $surveyId = $survey->getIid(); $course_id = api_get_course_int_id(); - if (empty($surveyId) || empty($course_id)) { return ''; } @@ -1023,33 +1007,28 @@ public static function displayCompleteReport( $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : ''; $content = ''; + + // Optional LP header if (!empty($lpItemId)) { $tableLp = Database::get_course_table(TABLE_LP_MAIN); $tableLpItem = Database::get_course_table(TABLE_LP_ITEM); - $sql = "SELECT l.name, - li.title - FROM $tableLpItem li - INNER JOIN $tableLp l - ON l.iid = li.lp_id AND - l.c_id = li.c_id - WHERE li.c_id = $course_id AND - li.iid = $lpItemId"; + $sql = "SELECT l.name, li.title + FROM $tableLpItem li + INNER JOIN $tableLp l ON l.iid = li.lp_id AND l.c_id = li.c_id + WHERE li.c_id = $course_id AND li.iid = $lpItemId"; $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { $row = Database::fetch_assoc($rs); - $lpName = $row['name']; - $lpItemTitle = $row['title']; - $content .= '

'.$lpName.' : '.$lpItemTitle.'

'; + $content .= '
' + .get_lang('Learning path') + .'

'.$row['name'].' : '.$row['title'].'

'; } } + // Toolbar if ($addActionBar) { - $actions = '' - .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'), - [], - ICON_SIZE_MEDIUM - ) + $actions = '' + .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'), [], ICON_SIZE_MEDIUM) .''; $actions .= '' .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).''; @@ -1060,50 +1039,36 @@ public static function displayCompleteReport( $content .= Display::toolbarAction('survey', [$actions]); - // The form - $content .= '
'; - $content .= ''; - $content .= ''; - $content .= '
'; - $content .= '
'; - $content .= ''; - $content .= ''; - $content .= '
'; - $content .= '
'; - $content .= ''; - $content .= ''; - $content .= '
'; - } - - $content .= '
'; - $content .= '
'; - // Getting the number of options per question - $content .= ''; - $content .= '
'; + // Export forms + $content .= ' + + '; + $content .= '
+ +
'; + $content .= '
+ +
'; + } + // Open card + form + table + $content .= '
' + .get_lang('Complete report').'
'; + + $content .= '
'; + $content .= ''; + + // Header row (filters + profile attrs) + $content .= ''; } @@ -1113,15 +1078,7 @@ class = "save" isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter']) ) { - // Show user fields section with a big th colspan that spans over all fields - $extra_user_fields = UserManager::get_extra_fields( - 0, - 0, - 5, - 'ASC', - false, - true - ); + $extra_user_fields = UserManager::get_extra_fields(0, 0, 5, 'ASC', false, true); $num = count($extra_user_fields); if ($num > 0) { $content .= ''; + $content .= ''; $display_extra_user_fields = true; } } } + // Questions headers $sql = "SELECT - q.iid question_id, - q.type, - q.survey_question, - count(o.iid) as number_of_options - FROM $table_survey_question q - LEFT JOIN $table_survey_question_option o - ON q.iid = o.question_id - WHERE - survey_question NOT LIKE '%{{%' AND - q.survey_id = '".$surveyId."' - GROUP BY q.iid - ORDER BY q.sort ASC"; + q.iid question_id, q.type, q.survey_question, count(o.iid) as number_of_options + FROM $table_survey_question q + LEFT JOIN $table_survey_question_option o ON q.iid = o.question_id + WHERE survey_question NOT LIKE '%{{%' AND q.survey_id = '".$surveyId."' + GROUP BY q.iid ORDER BY q.sort ASC"; $result = Database::query($sql); $questions = []; while ($row = Database::fetch_array($result)) { - // We show the questions if - // 1. there is no question filter and the export button has not been clicked - // 2. there is a quesiton filter but the question is selected for display if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) || - (is_array($_POST['questions_filter']) && - in_array($row['question_id'], $_POST['questions_filter'])) + (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter'])) ) { - // We do not show comment and pagebreak question types if ('pagebreak' !== $row['type']) { - $content .= ' 0 && 'percentage' !== $row['type']) { - $content .= ' colspan="'.$row['number_of_options'].'"'; - } - $content .= '>'; + $content .= ' 0 && 'percentage' !== $row['type']) ? ' colspan="'.$row['number_of_options'].'"' : '').'>'; $content .= ''; - $content .= ''; + $content .= ''; } - // No column at all if it's not a question } $questions[$row['question_id']] = $row; } - $content .= ' '; - - // Getting all the questions and options - $content .= ' '; - $content .= ' '; // the user column + $content .= ''; + // Second header row (user + extra fields + options) + $content .= ''; if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] || - isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter']) + isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter']) ) { if ($addExtraFields) { - // show the fields names for user fields - foreach ($extra_user_fields as &$field) { + foreach ($extra_user_fields as $field) { $content .= ''; } } } - // cells with option (none for open question) $sql = "SELECT - sq.iid question_id, - sq.survey_id, - sq.survey_question, - sq.display, - sq.sort, - sq.type, - sqo.iid question_option_id, - sqo.option_text, - sqo.sort as option_sort - FROM $table_survey_question sq - LEFT JOIN $table_survey_question_option sqo - ON sq.iid = sqo.question_id - WHERE - survey_question NOT LIKE '%{{%' AND - sq.survey_id = $surveyId - ORDER BY sq.sort ASC, sqo.sort ASC"; + sq.iid question_id, sq.survey_id, sq.survey_question, sq.display, sq.sort, sq.type, + sqo.iid question_option_id, sqo.option_text, sqo.sort as option_sort + FROM $table_survey_question sq + LEFT JOIN $table_survey_question_option sqo ON sq.iid = sqo.question_id + WHERE survey_question NOT LIKE '%{{%' AND sq.survey_id = $surveyId + ORDER BY sq.sort ASC, sqo.sort ASC"; $result = Database::query($sql); $display_percentage_header = 1; $possible_answers = []; - // in order to display only once the cell option (and not 100 times) while ($row = Database::fetch_array($result)) { - // We show the options if - // 1. there is no question filter and the export button has not been clicked - // 2. there is a question filter but the question is selected for display if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) || (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter'])) ) { - // we do not show comment and pagebreak question types if ('open' == $row['type'] || 'comment' == $row['type']) { $content .= ''; $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; @@ -1240,49 +1158,38 @@ class = "save" } elseif ('percentage' == $row['type']) { $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) { - $content .= ''; + $content .= ''; $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; $display_percentage_header = 1; } } } + $content .= ''; - $content .= ' '; - + // User filter $userCondition = ''; if (!empty($userId)) { $userId = (int) $userId; $userCondition = " AND user = $userId "; } - // Getting all the answers of the users + // Collect answers grouped by user $old_user = ''; $answers_of_user = []; $sql = "SELECT * FROM $table_survey_answer - WHERE - survey_id = $surveyId - $userCondition - $sessionCondition - $lpItemCondition - ORDER BY iid, user ASC"; + WHERE survey_id = $surveyId + $userCondition + $sessionCondition + $lpItemCondition + ORDER BY iid, user ASC"; $result = Database::query($sql); $i = 1; while ($row = Database::fetch_array($result)) { if ($old_user != $row['user'] && '' != $old_user) { - $userParam = $old_user; - if (0 != $survey->getAnonymous()) { - $userParam = $i; - $i++; - } + $userParam = (0 != $survey->getAnonymous()) ? $i : $old_user; + if (0 != $survey->getAnonymous()) { $i++; } $content .= self::display_complete_report_row( - $survey, - $possible_answers, - $answers_of_user, - $userParam, - $questions, - $display_extra_user_fields + $survey, $possible_answers, $answers_of_user, $userParam, $questions, $display_extra_user_fields ); $answers_of_user = []; } @@ -1297,24 +1204,13 @@ class = "save" $old_user = $row['user']; } - $userParam = $old_user; - if (0 != $survey->getAnonymous()) { - $userParam = $i; - $i++; - } - + $userParam = (0 != $survey->getAnonymous()) ? $i : $old_user; $content .= self::display_complete_report_row( - $survey, - $possible_answers, - $answers_of_user, - $userParam, - $questions, - $display_extra_user_fields + $survey, $possible_answers, $answers_of_user, $userParam, $questions, $display_extra_user_fields ); - // This is to display the last user - $content .= '
'; if ($addFilters) { if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) || (isset($_POST['export_report']) && $_POST['export_report']) ) { - $content .= ''; - } - $content .= ''; + $content .= ''; + } + $content .= ''; $content .= ' 0 ? ' colspan="'.$num.'"' : '').'>'; @@ -1130,105 +1087,66 @@ class = "save" $content .= ' '; } $content .= get_lang('Profile attributes'); - $content .= ''; - $content .= '
 
 '.$field[3].' - '; - $content .= $row['option_text']; - $content .= ''.$row['option_text'].'
'; - $content .= '
'; + $content .= '
'; + $content .= '
'; // close card+container return $content; } @@ -2068,31 +1964,17 @@ public static function export_complete_report_row_xls( */ public static function display_comparative_report() { - // Allowed question types for comparative report - $allowed_question_types = [ - 'yesno', - 'multiplechoice', - 'multipleresponse', - 'dropdown', - 'percentage', - 'score', - ]; - + $allowed_question_types = ['yesno','multiplechoice','multipleresponse','dropdown','percentage','score']; $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0; - // Getting all the questions $questions = SurveyManager::get_questions($surveyId); - // Actions bar - $actions = '' + // Toolbar + $actions = '' .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview')) .''; echo Display::toolbarAction('survey', [$actions]); - // Displaying an information message that only the questions with predefined answers can be used in a comparative report echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false); $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : ''; @@ -2110,56 +1992,39 @@ public static function display_comparative_report() $optionsY = ['----']; $defaults = []; foreach ($questions as $key => &$question) { - // Ignored tagged questions - if ($question) { - if (false !== strpos($question['question'], '{{')) { - $question = null; - continue; - } + if ($question && false !== strpos($question['question'], '{{')) { + $question = null; + continue; } - if (is_array($allowed_question_types)) { - if (in_array($question['type'], $allowed_question_types)) { - if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) { - $defaults['xaxis'] = $question['question_id']; - } - - if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) { - $defaults['yaxis'] = $question['question_id']; - } - - $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90); - $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90); + if (in_array($question['type'], $allowed_question_types)) { + if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) { + $defaults['xaxis'] = $question['question_id']; } + if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) { + $defaults['yaxis'] = $question['question_id']; + } + $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90); + $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90); } } - $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX); $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY); - $form->addButtonSearch(get_lang('Compare questions')); $form->setDefaults($defaults); $form->display(); - // Getting all the information of the x axis - if (is_numeric($xAxis)) { - $question_x = SurveyManager::get_question($xAxis); - } - - // Getting all the information of the y axis - if (is_numeric($yAxis)) { - $question_y = SurveyManager::get_question($yAxis); - } + if (is_numeric($xAxis)) { $question_x = SurveyManager::get_question($xAxis); } + if (is_numeric($yAxis)) { $question_y = SurveyManager::get_question($yAxis); } - if (is_numeric($xAxis) && is_numeric($yAxis) && $question_x && $question_y) { - // Getting the answers of the two questions + if (is_numeric($xAxis) && is_numeric($yAxis) && !empty($question_x) && !empty($question_y)) { $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis); $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis); - // Displaying the table - $tableHtml = ''; + $tableHtml = '
'; $xOptions = []; - // The header - $tableHtml .= ''; + + // Header + $tableHtml .= ''; for ($ii = 0; $ii <= count($question_x['answers']); $ii++) { if (0 == $ii) { $tableHtml .= ''; @@ -2168,22 +2033,19 @@ public static function display_comparative_report() for ($x = 1; $x <= $question_x['maximum_score']; $x++) { $tableHtml .= ''; } - $x = ''; } else { $tableHtml .= ''; } - $optionText = strip_tags($question_x['answers'][$ii - 1]); - $optionText = html_entity_decode($optionText); - array_push($xOptions, trim($optionText)); + $optionText = html_entity_decode(strip_tags($question_x['answers'][$ii - 1])); + $xOptions[] = trim($optionText); } } - $tableHtml .= ''; + $tableHtml .= ''; + $chartData = []; - // The main part + // Body for ($ij = 0; $ij < count($question_y['answers']); $ij++) { - $currentYQuestion = strip_tags($question_y['answers'][$ij]); - $currentYQuestion = html_entity_decode($currentYQuestion); - // The Y axis is a scoring question type so we have more rows than the options (actually options * maximum score) + $currentYQuestion = html_entity_decode(strip_tags($question_y['answers'][$ij])); if ('score' == $question_y['type']) { for ($y = 1; $y <= $question_y['maximum_score']; $y++) { $tableHtml .= ''; @@ -2194,57 +2056,34 @@ public static function display_comparative_report() $tableHtml .= ''; break; } else { - $tableHtml .= ''; + $tableHtml .= ''; + $chartData[] = ['serie' => [$currentYQuestion, $xOptions[$ii - 1]], 'option' => $x, 'votes' => $votes]; } } } else { if (0 == $ii) { $tableHtml .= ''; } else { - $tableHtml .= ''; + $tableHtml .= ''; + $chartData[] = ['serie' => [$currentYQuestion, $xOptions[$ii - 1]], 'option' => $y, 'votes' => $votes]; } } } $tableHtml .= ''; } } else { - // The Y axis is NOT a score question type so the number of rows = the number of options $tableHtml .= ''; for ($ii = 0; $ii <= count($question_x['answers']); $ii++) { if ('score' == $question_x['type']) { @@ -2253,59 +2092,40 @@ public static function display_comparative_report() $tableHtml .= ''; break; } else { - $tableHtml .= ''; + $tableHtml .= ''; + $chartData[] = ['serie' => [$currentYQuestion, $xOptions[$ii - 1]], 'option' => $x, 'votes' => $votes]; } } } else { if (0 == $ii) { $tableHtml .= ''; } else { - $tableHtml .= ''; + $tableHtml .= ''; + $chartData[] = ['serie' => $xOptions[$ii - 1], 'option' => $currentYQuestion, 'votes' => $votes]; } } } $tableHtml .= ''; } } - $tableHtml .= '
 '.$question_x['answers'][($ii - 1)].'
'.$x.'
'.$question_x['answers'][($ii - 1)].'
'.$question_y['answers'][($ij)].' '.$y.''; $votes = self::comparative_check( - $answers_x, - $answers_y, + $answers_x, $answers_y, $question_x['answersid'][($ii - 1)], $question_y['answersid'][($ij)], - $x, - $y - ); - $tableHtml .= $votes; - array_push( - $chartData, - [ - 'serie' => [$currentYQuestion, $xOptions[$ii - 1]], - 'option' => $x, - 'votes' => $votes, - ] + $x, $y ); - $tableHtml .= ''.$votes.''.$question_y['answers'][$ij].' '.$y.''; $votes = self::comparative_check( - $answers_x, - $answers_y, + $answers_x, $answers_y, $question_x['answersid'][($ii - 1)], $question_y['answersid'][($ij)], - 0, - $y + 0, $y ); - $tableHtml .= $votes; - array_push( - $chartData, - [ - 'serie' => [$currentYQuestion, $xOptions[$ii - 1]], - 'option' => $y, - 'votes' => $votes, - ] - ); - $tableHtml .= ''.$votes.'
'.$question_y['answers'][$ij].''; $votes = self::comparative_check( - $answers_x, - $answers_y, + $answers_x, $answers_y, $question_x['answersid'][($ii - 1)], $question_y['answersid'][($ij)], - $x, - 0 - ); - $tableHtml .= $votes; - array_push( - $chartData, - [ - 'serie' => [$currentYQuestion, $xOptions[$ii - 1]], - 'option' => $x, - 'votes' => $votes, - ] + $x, 0 ); - $tableHtml .= ''.$votes.''.$question_y['answers'][($ij)].''; $votes = self::comparative_check( - $answers_x, - $answers_y, + $answers_x, $answers_y, $question_x['answersid'][($ii - 1)], $question_y['answersid'][($ij)] ); - $tableHtml .= $votes; - array_push( - $chartData, - [ - 'serie' => $xOptions[$ii - 1], - 'option' => $currentYQuestion, - 'votes' => $votes, - ] - ); - $tableHtml .= ''.$votes.'
'; - echo '
'; - echo self::drawChart($chartData, true); - echo '
'; + $tableHtml .= ''; + + echo '
' + .get_lang('Comparative report').'
'; + echo '
'.self::drawChart($chartData, true).'
'; echo $tableHtml; + echo '
'; } }