diff --git a/README.md b/README.md index 854e593..835cf28 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Szkielet komponentu Joomla 6 do gromadzenia pytań testowych. - filtrowanie listy pytań po kategorii, - przełącznik widoku listy: same pytania albo pytania z odpowiedziami, - frontendowy widok pytań filtrowany po symbolu arkusza egzaminacyjnego, +- frontendowy widok testu na podstawie wybranego zestawu pytań, - pozycję menu „Arkusz egzaminacyjny” z opcjonalnym symbolem arkusza, - listę wyboru dostępnych symboli arkuszy na stronie klienckiej, - możliwość rozwiązania arkusza i wyświetlenia wyniku oraz odpowiedzi poprawnych i zaznaczonych, @@ -24,6 +25,6 @@ Szkielet komponentu Joomla 6 do gromadzenia pytań testowych. ## Instalacja -W Joomla wybierz **System → Install → Install from Folder** i wskaż ten katalog. Manifestem instalacyjnym jest `com_testquestions.xml` (wersja 1.13.5). +W Joomla wybierz **System → Install → Install from Folder** i wskaż ten katalog. Manifestem instalacyjnym jest `com_testquestions.xml` (wersja 1.14.0). Po instalacji komponent jest dostępny w panelu administratora jako **Pytania testowe**. diff --git a/administrator/components/com_testquestions/sql/updates/mysql/1.14.0.sql b/administrator/components/com_testquestions/sql/updates/mysql/1.14.0.sql new file mode 100644 index 0000000..897d15c --- /dev/null +++ b/administrator/components/com_testquestions/sql/updates/mysql/1.14.0.sql @@ -0,0 +1 @@ +-- No database changes required for version 1.14.0. diff --git a/com_testquestions.xml b/com_testquestions.xml index 6b1930d..036f9a4 100644 --- a/com_testquestions.xml +++ b/com_testquestions.xml @@ -4,7 +4,7 @@ 2026-10-14 Komponent GNU General Public License version 2 or later - 1.13.5 + 1.14.0 COM_TESTQUESTIONS_DESCRIPTION com_testquestions Komponent\Component\Testquestions diff --git a/components/com_testquestions/language/en-GB/com_testquestions.ini b/components/com_testquestions/language/en-GB/com_testquestions.ini index 5e582de..7edce07 100644 --- a/components/com_testquestions/language/en-GB/com_testquestions.ini +++ b/components/com_testquestions/language/en-GB/com_testquestions.ini @@ -17,3 +17,5 @@ COM_TESTQUESTIONS_MENU_ITEM_TITLE="Arkusz egzaminacyjny" COM_TESTQUESTIONS_MENU_ITEM_DESCRIPTION="Wyświetla pytania z wybranego arkusza egzaminacyjnego." COM_TESTQUESTIONS_MENU_TEST_SYMBOL_DESC="Opcjonalnie wybierz symbol arkusza, który ma być wyświetlany po wejściu z menu." COM_TESTQUESTIONS_ENTER_ANSWER="Wpisz odpowiedź" +COM_TESTQUESTIONS_SET_DURATION="Czas trwania testu" +COM_TESTQUESTIONS_SET_NOT_FOUND="Nie znaleziono wybranego zestawu testowego." diff --git a/components/com_testquestions/language/en-GB/com_testquestions.sys.ini b/components/com_testquestions/language/en-GB/com_testquestions.sys.ini index 89e8afb..e8996cf 100644 --- a/components/com_testquestions/language/en-GB/com_testquestions.sys.ini +++ b/components/com_testquestions/language/en-GB/com_testquestions.sys.ini @@ -1,3 +1,6 @@ COM_TESTQUESTIONS="Pytania testowe" COM_TESTQUESTIONS_MENU_ITEM_TITLE="Arkusz egzaminacyjny" COM_TESTQUESTIONS_MENU_ITEM_DESCRIPTION="Wyświetla pytania z wybranego arkusza egzaminacyjnego." +COM_TESTQUESTIONS_SET_MENU_ITEM_TITLE="Zestaw testowy" +COM_TESTQUESTIONS_SET_MENU_ITEM_DESCRIPTION="Wyświetla test na podstawie wybranego zestawu pytań." +COM_TESTQUESTIONS_SET_SELECT="Zestaw pytań" diff --git a/components/com_testquestions/src/Model/SetModel.php b/components/com_testquestions/src/Model/SetModel.php new file mode 100644 index 0000000..8d549ab --- /dev/null +++ b/components/com_testquestions/src/Model/SetModel.php @@ -0,0 +1,59 @@ +getMenu()->getActive(); + $menuSetId = $menu ? (int) $menu->getParams()->get('set_id', 0) : 0; + + return $application->getInput()->getInt('set_id', $menuSetId); + } + + public function getSet() + { + $db = Factory::getContainer()->get('DatabaseDriver'); + $setId = $this->getSetId(); + + if ($setId < 1) { + return null; + } + + return $db->setQuery( + $db->getQuery(true) + ->select(['s.*', 'sub.title AS subject_title']) + ->from($db->quoteName('#__testquestions_sets', 's')) + ->leftJoin($db->quoteName('#__testquestions_subjects', 'sub') . ' ON sub.id = s.subject_id') + ->where('s.id = ' . $setId) + ->where('s.published = 1') + )->loadObject(); + } + + public function getItems() + { + $db = Factory::getContainer()->get('DatabaseDriver'); + $setId = $this->getSetId(); + + if ($setId < 1) { + return []; + } + + return $db->setQuery( + $db->getQuery(true) + ->select(['q.id', 'q.question_type', 'q.question', 'q.answer_a', 'q.answer_b', 'q.answer_c', 'q.answer_d', 'q.answer_open', 'q.correct_answer', 'q.image']) + ->from($db->quoteName('#__testquestions_set_questions', 'sq')) + ->innerJoin($db->quoteName('#__testquestions_questions', 'q') . ' ON q.id = sq.question_id') + ->where('sq.set_id = ' . $setId) + ->where('q.published = 1') + ->order('sq.ordering ASC, q.id ASC') + )->loadObjectList(); + } +} diff --git a/components/com_testquestions/src/View/Set/HtmlView.php b/components/com_testquestions/src/View/Set/HtmlView.php new file mode 100644 index 0000000..8061646 --- /dev/null +++ b/components/com_testquestions/src/View/Set/HtmlView.php @@ -0,0 +1,67 @@ +set = $this->get('Set'); + $this->items = $this->get('Items'); + $this->results = $this->buildResults($this->items); + + return parent::display($tpl); + } + + protected function buildResults(array $items) + { + $input = Factory::getApplication()->getInput(); + + if ($input->getCmd('task') !== 'check' || $input->getMethod() !== 'POST') { + return null; + } + + $answers = (array) $input->post->get('answers', [], 'array'); + $results = []; + $correct = 0; + + foreach ($items as $item) { + $selected = isset($answers[$item->id]) ? trim((string) $answers[$item->id]) : ''; + $isCorrect = false; + + if ($item->question_type === 'open') { + $patterns = preg_split('/\s*\|\s*/', (string) $item->answer_open, -1, PREG_SPLIT_NO_EMPTY); + foreach ($patterns as $pattern) { + if (mb_strtolower(trim($pattern), 'UTF-8') === mb_strtolower($selected, 'UTF-8')) { + $isCorrect = true; + break; + } + } + } else { + $isCorrect = (string) $item->correct_answer === $selected; + } + + if ($isCorrect) { + $correct++; + } + + $results[$item->id] = ['selected' => $selected, 'correct' => $isCorrect]; + } + + return [ + 'items' => $results, + 'correct' => $correct, + 'total' => count($items), + 'percentage' => count($items) ? round(($correct / count($items)) * 100, 2) : 0, + ]; + } +} diff --git a/components/com_testquestions/tmpl/set/default.php b/components/com_testquestions/tmpl/set/default.php new file mode 100644 index 0000000..ecfb635 --- /dev/null +++ b/components/com_testquestions/tmpl/set/default.php @@ -0,0 +1,56 @@ + +
+ set) : ?> +
+ +
+ set->subject_title) : ?>
set->subject_title, ENT_QUOTES, 'UTF-8'); ?>
+

set->title, ENT_QUOTES, 'UTF-8'); ?>

+ set->duration > 0) : ?>
: set->duration; ?> min
+ set->image) : ?>
+ set->test_content) : ?>
set->test_content; ?>
+
+ results) : ?> +
: results['correct']; ?> / results['total']; ?> (results['percentage'], ENT_QUOTES, 'UTF-8'); ?>%)
+ + items) : ?> +
+ items as $number => $item) : ?> +
+
question; ?>
+ image) : ?>
+ question_type === 'open') : ?> +
+ + +
+ +
    + $answerField) : ?> + results && $this->results['items'][$item->id]['selected'] === (string) ($answerIndex + 1); ?> + results && (string) $item->correct_answer === (string) ($answerIndex + 1); ?> +
  1. + +
  2. + +
+ + results) : ?> +
+ results['items'][$item->id]['correct'] ? '✓ ' . \Joomla\CMS\Language\Text::_('COM_TESTQUESTIONS_ANSWER_CORRECT') : '✗ ' . \Joomla\CMS\Language\Text::_('COM_TESTQUESTIONS_ANSWER_INCORRECT'); ?> + question_type === 'closed') : ?> — : correct_answer); ?> — : answer_open, ENT_QUOTES, 'UTF-8'); ?> +
+ +
+ + + + + +
+ + +
diff --git a/components/com_testquestions/tmpl/set/default.xml b/components/com_testquestions/tmpl/set/default.xml new file mode 100644 index 0000000..a0ae1a2 --- /dev/null +++ b/components/com_testquestions/tmpl/set/default.xml @@ -0,0 +1,13 @@ + + + + COM_TESTQUESTIONS_SET_MENU_ITEM_DESCRIPTION + + +
+ +
+
+