В битриксе есть очень полезный модуль – обучение. Благодаря ему можно легко обучать новичков и контролировать уровень знаний опытных сотрудников. По результатам обучения сотрудники проходят тесты и получают баллы.
Задача
В целях повышения мотивации к безошибочному прохождению теста создать страницу, на которой будет выводиться список лучших результатов теста.
Поиск решения
Т.к. ничего похожего в стандартном модуле нет, кастомизирование шаблонов сразу отпадает.
Сначала я решил, что всё просто. И сделать нужную выборку можно простой настройкой фильтра метода CTestAttempt::GetList(), но не тут то было.
Оказывается, в битриксе нет понятия номера попытки прохождения теста. Если просто отсортировать попытки по полученным баллам, то в выборке будут участвовать как самые худшие, так и самые лучшие попытки.
В итоге те? кто сдал тест с первого раза плохо будут в списке лузеров, и они же могут быть в списке лучших, т.к. пройти тест второй раз никто не мешает.
Найденное решение
Сначала я всё-таки сделал общий топ по всем попыткам. Но пользователи очень сильно возбубнили и пришлось делать два отдельных топа – по первой попытке и по лучшей попытке от каждого пользователя.
В итоге получился вот такой вот код для первых попыток:
-
<?$testList = CTest::GetList(
-
("SORT"=>"ASC"),
-
("ACTIVE" => "Y", "MIN_PERMISSION" => "R")
-
);//получаем список тестов
-
-
while ($arTest = $testList->GetNext()){?>
-
<div id="testList">
-
<h2><?=$arTest[‘NAME’]?></h2>
-
<table class="testList-table">
-
<tr>
-
<td class="testList-best-top"><span>Лучшие результаты</span></td>
-
<td class="testList-bad-top"><span>Худшие результаты</span></td>
-
</tr>
-
-
<tr class="testList-result">
-
<td class="testList-result-best">
-
<table class="testList-result-table">
-
<thead>
-
<td class="testList-position">Место
-
</td>
-
-
<td class="testList-user-name">Имя
-
</td>
-
-
<td class="testList-score">Балл
-
</td>
-
</thead>
-
-
<tbody>
-
<?$attemptListByDate = CTestAttempt::GetList(
-
("DATE_START" => "ASC"),
-
("TEST_ID" => $arTest[‘ID’],"STATUS" => "F")
-
);//получаем список попыток по дате
-
-
while ($arAttemptByDate = $attemptListByDate->GetNext()){
-
if(!($arAttemptByDate[‘USER_NAME’],$arUsers)){//проверяем уникальность попытки
-
if(($arAttemptByDate[‘SCORE’] != "") && ($arAttemptByDate[‘SCORE’] != "0")){
-
$arUsers[] = $arAttemptByDate[‘USER_NAME’];
-
$arAttemptScore[] = $arAttemptByDate[‘SCORE’];
-
}
-
}
-
}//создаём массив первых попыток
-
-
($arAttemptScore);//сортируем очки по убыванию
-
-
$attemptCount = 0;
-
-
while (($element = ($arAttemptScore)) && ($attemptCount != 5)){//проходим по 5ти первым элементам массива
-
$key = ($arAttemptScore);//номер попытки
-
$f_USER_NAME = (")", $arUsers[$key]);//извлекаем имя пользователя?>
-
<tr>
-
<td class="testList-position"><? (1 + $attemptCount);?>
-
</td>
-
-
<td class="testList-user-name"><?=$f_USER_NAME[1]?>
-
</td>
-
-
<td class="testList-user-score"><?=$arAttemptScore[$key]?>
-
</td>
-
</tr>
-
-
<?$attemptCount++;
-
($arAttemptScore);//переводим фокус
-
}?>
-
-
</tbody>
-
</table>
-
<td class="testList-result-bad">
-
<table class="testList-result-table">
-
<thead>
-
<td class="testList-score">Балл
-
</td>
-
-
<td class="testList-user-name">Имя
-
</td>
-
-
<td class="testList-position">Место
-
</td>
-
</thead>
-
-
<tbody>
-
<?($arAttemptScore);//сортируем очки по возрастанию
-
-
$attemptCount = 0;?>
-
-
<?while (($element = ($arAttemptScore)) && ($attemptCount != 5)){//проходим по 5ти первым элементам массива
-
$key = ($arAttemptScore);//номер попытки
-
$f_USER_NAME = (")", $arUsers[$key]);//извлекаем имя пользователя?>
-
<tr>
-
<td class="testList-user-score"><?=$arAttemptScore[$key]?>
-
</td>
-
-
<td class="testList-user-name"><?=$f_USER_NAME[1]?>
-
</td>
-
-
<td class="testList-position"><? (1 + $attemptCount);?>
-
</td>
-
</tr>
-
-
<?$attemptCount++;
-
($arAttemptScore);//переводим фокус
-
}?>
-
</tbody>
-
</table>
-
</td>
-
</tr>
-
-
<tr>
-
<td class="testList-bottom-best"> </span></td>
-
<td class="testList-bottom-bad"> </td>
-
</tr>
-
</table>
-
</div>
-
-
<?($arUsers,$arAttemptByDate,$arAttemptScore);//очищаем переменные?>
-
-
<?}//конец вывода тестов?>
И для лучших попыток:
-
<?if (!("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)();?>
-
-
<?$testList = CTest::GetList(
-
("SORT"=>"ASC"),
-
("ACTIVE" => "Y", "MIN_PERMISSION" => "R")
-
);//получаем список тестов
-
-
while ($arTest = $testList->GetNext()){?>
-
<div id="testList">
-
<h2><?=$arTest[‘NAME’]?></h2>
-
<table class="testList-table">
-
<tr>
-
<td class="testList-best-top"><span>Лучшие результаты</span></td>
-
<td class="testList-bad-top"><span>Худшие результаты</span></td>
-
</tr>
-
-
<tr class="testList-result">
-
<td class="testList-result-best">
-
<table class="testList-result-table">
-
<thead>
-
<td class="testList-position">Место
-
</td>
-
-
<td class="testList-user-name">Имя
-
</td>
-
-
<td class="testList-score">Балл
-
</td>
-
</thead>
-
-
<tbody>
-
<?$attemptListByDate = CTestAttempt::GetList(
-
("SCORE" => "DESC","DATE_START" => "ASC"),
-
("TEST_ID" => $arTest[‘ID’],"STATUS" => "F")
-
);//получаем список попыток по дате
-
-
while ($arAttemptByDate = $attemptListByDate->GetNext()){
-
if(!($arAttemptByDate[‘USER_NAME’],$arUsers)){//проверяем уникальность попытки
-
if(($arAttemptByDate[‘SCORE’] != "") && ($arAttemptByDate[‘SCORE’] != "0")){
-
$arUsers[] = $arAttemptByDate[‘USER_NAME’];
-
$arAttemptScore[] = $arAttemptByDate[‘SCORE’];
-
}
-
}
-
}//создаём массив попыток
-
-
($arAttemptScore);//сортируем очки по убыванию
-
-
$attemptCount = 0;
-
-
while (($element = ($arAttemptScore)) && ($attemptCount != 5)){//проходим по 5ти первым элементам массива
-
$key = ($arAttemptScore);//номер попытки
-
$f_USER_NAME = (")", $arUsers[$key]);//извлекаем имя пользователя?>
-
<tr>
-
<td class="testList-position"><? (1 + $attemptCount);?>
-
</td>
-
-
<td class="testList-user-name"><?=$f_USER_NAME[1]?>
-
</td>
-
-
<td class="testList-user-score"><?=$arAttemptScore[$key]?>
-
</td>
-
</tr>
-
-
<?$attemptCount++;
-
($arAttemptScore);//переводим фокус
-
}?>
-
-
</tbody>
-
</table>
-
<td class="testList-result-bad">
-
<table class="testList-result-table">
-
<thead>
-
<td class="testList-score">Балл
-
</td>
-
-
<td class="testList-user-name">Имя
-
</td>
-
-
<td class="testList-position">Место
-
</td>
-
</thead>
-
-
<tbody>
-
<?($arAttemptScore);//сортируем очки по возрастанию
-
-
$attemptCount = 0;?>
-
-
<?while (($element = ($arAttemptScore)) && ($attemptCount != 5)){//проходим по 5ти первым элементам массива
-
$key = ($arAttemptScore);//номер попытки
-
$f_USER_NAME = (")", $arUsers[$key]);//извлекаем имя пользователя?>
-
<tr>
-
<td class="testList-user-score"><?=$arAttemptScore[$key]?>
-
</td>
-
-
<td class="testList-user-name"><?=$f_USER_NAME[1]?>
-
</td>
-
-
<td class="testList-position"><? (1 + $attemptCount);?>
-
</td>
-
</tr>
-
-
<?$attemptCount++;
-
($arAttemptScore);//переводим фокус
-
}?>
-
</tbody>
-
</table>
-
</td>
-
</tr>
-
-
<tr>
-
<td class="testList-bottom-best"> </span></td>
-
<td class="testList-bottom-bad"> </td>
-
</tr>
-
</table>
-
</div>
-
-
<?($arUsers,$arAttemptByDate,$arAttemptScore);//очищаем переменные?>
-
-
<?}//конец вывода тестов?>
Внешне это выглядит вот так (все фамилии вымышлены совпадения случайны)

Bitrix - лучшие и худшие результаты тестов
Такая табличка выводится на каждый тест, к которому имеет доступ пользователь.
Итог
В результате получилась классная пузомерка, хорошо мотивирующая сотрудников искать правильные ответы на тесты.
За попытки отвечает класс у которого есть метод .
Ему нужно передать идентификатор студента, который можно получить воспользовавшись методом класса . USER_ID текущего пользователя у вас в профиле есть.
Если вы не продумаете как скрыть эту информацию, то она будет доступна всем
P.S. не смотрите на код, который написан выше, так писать не стоит
[Ответить]