Your IP : 18.226.82.81
<?
/**
* @global $USER_FIELD_MANAGER CUserTypeManager
*/
global $USER_FIELD_MANAGER;
abstract class CAllTestAttempt
{
function CheckFields(&$arFields, $ID = false, $bCheckRights = true)
{
global $DB, $APPLICATION;
if ($ID===false && !is_set($arFields, "TEST_ID"))
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_ID"), "EMPTY_TEST_ID");
return false;
}
elseif (is_set($arFields, "TEST_ID"))
{
if ($bCheckRights)
$r = CTest::GetByID($arFields["TEST_ID"]);
else
{
$r = CTest::getList(
array(),
array(
'ID' => $arFields['TEST_ID'],
'CHECK_PERMISSIONS' => 'N'
)
);
}
if(!$r->Fetch())
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_ID_EX"), "ERROR_NO_TEST_ID");
return false;
}
}
if ($ID===false && !is_set($arFields, "STUDENT_ID"))
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_USER_ID"), "EMPTY_STUDENT_ID");
return false;
}
elseif (is_set($arFields, "STUDENT_ID"))
{
$dbResult = CUser::GetByID($arFields["STUDENT_ID"]);
if (!$dbResult->Fetch())
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_USER_ID_EX"), "ERROR_NO_STUDENT_ID");
return false;
}
}
if (is_set($arFields, "DATE_START") && (!$DB->IsDate($arFields["DATE_START"], false, LANG, "FULL")))
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_DATE_START"), "ERROR_DATE_START");
return false;
}
if (is_set($arFields, "DATE_END") && strlen($arFields["DATE_END"])>0 && (!$DB->IsDate($arFields["DATE_END"], false, LANG, "FULL")))
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_DATE_END"), "ERROR_DATE_END");
return false;
}
//Defaults
if (is_set($arFields, "STATUS") && !in_array($arFields["STATUS"], Array("B", "D", "F", "N")))
$arFields["STATUS"] = "B";
if (is_set($arFields, "COMPLETED") && $arFields["COMPLETED"] != "Y")
$arFields["COMPLETED"] = "N";
return true;
}
function Add($arFields)
{
global $DB, $USER_FIELD_MANAGER;
if(CTestAttempt::CheckFields($arFields) && $USER_FIELD_MANAGER->CheckFields("LEARN_ATTEMPT", 0, $arFields))
{
unset($arFields["ID"]);
//$ID = $DB->Add("b_learn_attempt", $arFields, Array(""), "learning");
$arInsert = $DB->PrepareInsert("b_learn_attempt", $arFields, "learning");
$ID = CTestAttempt::DoInsert($arInsert, $arFields);
CGradeBook::RecountAttempts($arFields["STUDENT_ID"], $arFields["TEST_ID"]);
if ($ID)
{
$USER_FIELD_MANAGER->Update("LEARN_ATTEMPT", $ID, $arFields);
}
return $ID;
}
return false;
}
function Update($ID, $arFields, $arParams = array())
{
global $DB, $USER_FIELD_MANAGER;
$ID = intval($ID);
if ($ID < 1) return false;
$bCheckRights = true;
if (isset($arParams['CHECK_PERMISSIONS']) && ($arParams['CHECK_PERMISSIONS'] === 'N'))
$bCheckRights = false;
if ($this->CheckFields($arFields, $ID, $bCheckRights) && $USER_FIELD_MANAGER->CheckFields("LEARN_ATTEMPT", 0, $arFields))
{
unset($arFields["ID"]);
unset($arFields["TEST_ID"]);
$arBinds=Array(
//""=>$arFields[""]
);
$strUpdate = $DB->PrepareUpdate("b_learn_attempt", $arFields, "learning");
$strSql = "UPDATE b_learn_attempt SET ".$strUpdate." WHERE ID=".$ID;
$DB->QueryBind($strSql, $arBinds, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$USER_FIELD_MANAGER->Update("LEARN_ATTEMPT", $ID, $arFields);
return true;
}
return false;
}
function Delete($ID)
{
global $DB, $USER_FIELD_MANAGER;
$ID = intval($ID);
if ($ID < 1) return false;
//Results
$strSql = "DELETE FROM b_learn_test_result WHERE ATTEMPT_ID = ".$ID;
if (!$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
//Attempt
$strSql = "DELETE FROM b_learn_attempt WHERE ID = ".$ID;
if (!$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
$USER_FIELD_MANAGER->Delete("LEARN_ATTEMPT", $ID);
return true;
}
function GetFilter($arFilter)
{
if (!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = Array();
foreach ($arFilter as $key => $val)
{
$res = CLearnHelper::MkOperationFilter($key);
$key = $res["FIELD"];
$cOperationType = $res["OPERATION"];
$key = strtoupper($key);
switch ($key)
{
case "ID":
case "TEST_ID":
case "STUDENT_ID":
case "SCORE":
case "MAX_SCORE":
case "QUESTIONS":
$arSqlSearch[] = CLearnHelper::FilterCreate("A.".$key, $val, "number", $bFullJoin, $cOperationType);
break;
case "SPEED":
$arSqlSearch[] = CLearnHelper::FilterCreate(self::getSpeedFieldSql(), $val, "number", $bFullJoin, $cOperationType);
break;
case "STATUS":
case "COMPLETED":
$arSqlSearch[] = CLearnHelper::FilterCreate("A.".$key, $val, "string_equal", $bFullJoin, $cOperationType);
break;
case "DATE_START":
case "DATE_END":
$arSqlSearch[] = CLearnHelper::FilterCreate("A.".$key, $val, "date", $bFullJoin, $cOperationType);
break;
case "USER":
$arSqlSearch[] = GetFilterQuery("U.ID, U.LOGIN, U.NAME, U.LAST_NAME",$val);
break;
case "USER_LOGIN":
$arSqlSearch[] = CLearnHelper::FilterCreate("U.LOGIN", $val, "string_equal", $bFullJoin, $cOperationType);
break;
case "USER_NAME":
$arSqlSearch[] = CLearnHelper::FilterCreate("U.NAME", $val, "string_equal", $bFullJoin, $cOperationType);
break;
case "USER_LAST_NAME":
$arSqlSearch[] = CLearnHelper::FilterCreate("U.LAST_NAME", $val, "string_equal", $bFullJoin, $cOperationType);
break;
}
}
return $arSqlSearch;
}
function GetByID($ID)
{
if ((int) $ID > 0)
return CTestAttempt::GetList(array(), array("ID" => (int) $ID));
else
return (new CDBResult());
}
function GetCount($TEST_ID, $STUDENT_ID)
{
global $DB;
$strSql =
"SELECT COUNT(*) as C ".
"FROM b_learn_attempt A ".
"WHERE A.TEST_ID = '".intval($TEST_ID)."' AND A.STUDENT_ID = '".intval($STUDENT_ID)."'";
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res_cnt = $res->Fetch();
return intval($res_cnt["C"]);
}
function IsTestCompleted($ATTEMPT_ID, $PERCENT)
{
global $DB;
$strSql =
"SELECT * ".
"FROM b_learn_test_result TR, b_learn_question Q ".
"WHERE TR.QUESTION_ID = Q.ID AND TR.CORRECT = 'N' AND Q.CORRECT_REQUIRED = 'Y' AND TR.ATTEMPT_ID = '".intval($ATTEMPT_ID)."'";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
if ($arStat = $res->Fetch())
return false;
$strSql =
"SELECT SUM(Q.POINT) as CNT_ALL, SUM(CASE WHEN TR.CORRECT = 'Y' THEN Q.POINT ELSE 0 END) as CNT_RIGHT ".
"FROM b_learn_test_result TR, b_learn_question Q ".
"WHERE TR.ATTEMPT_ID = '".intval($ATTEMPT_ID)."' AND TR.QUESTION_ID = Q.ID";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
if (!$arStat = $res->Fetch())
return false;
if($arStat["CNT_RIGHT"]<=0 || $arStat["CNT_ALL"] == 0)
return false;
// Do some magic due to IEEE 754
$epsilon = 0.001;
$scoreForSuccess = (float) ((int) $PERCENT);
$userScore = round( ($arStat["CNT_RIGHT"] / $arStat["CNT_ALL"]) * 100, 2);
$delta = abs($userScore - $scoreForSuccess);
$isTestComplete = false;
if ($userScore > $scoreForSuccess)
$isTestComplete = true;
elseif ($delta < $epsilon) // it means, that $userScore == $scoreForSuccess
$isTestComplete = true;
return ($isTestComplete);
}
function OnAttemptChange($ATTEMPT_ID, $bCOMPLETED = false)
{
global $DB;
$ATTEMPT_ID = intval($ATTEMPT_ID);
if ($ATTEMPT_ID < 1)
return false;
$strSql = "SELECT A.*, T.APPROVED, T.COMPLETED_SCORE, T.COURSE_ID ".
"FROM b_learn_attempt A ".
"INNER JOIN b_learn_test T ON A.TEST_ID = T.ID ".
"WHERE A.ID = '".$ATTEMPT_ID."' AND A.STATUS = 'F' ";
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if (!$arAttempt = $res->Fetch())
return false;
$COMPLETED = "N";
if (
$arAttempt["APPROVED"] == "Y" &&
intval($arAttempt["COMPLETED_SCORE"])>0 &&
CTestAttempt::IsTestCompleted($ATTEMPT_ID,$arAttempt["COMPLETED_SCORE"])
)
$COMPLETED = "Y";
if ($bCOMPLETED)
$COMPLETED = "Y";
$strSql =
"UPDATE b_learn_attempt SET COMPLETED = '".$COMPLETED."' ".
"WHERE ID = '".$ATTEMPT_ID."'";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
$strSql = "SELECT * FROM b_learn_gradebook WHERE STUDENT_ID='".$arAttempt["STUDENT_ID"]."' AND TEST_ID='".$arAttempt["TEST_ID"]."'";
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if (!$arGradeBook = $res->Fetch())
{
$arFields = Array(
"STUDENT_ID" => $arAttempt["STUDENT_ID"],
"TEST_ID" => $arAttempt["TEST_ID"],
"RESULT" => $arAttempt["SCORE"],
"MAX_RESULT" => intval($arAttempt["MAX_SCORE"]),
"COMPLETED" => $COMPLETED,
);
$at = new CGradeBook;
if (!$res = $at->Add($arFields))
return false;
CCertification::Certificate($arAttempt["STUDENT_ID"], $arAttempt["COURSE_ID"]);
}
else
{
$strSql =
"SELECT A.SCORE, A.MAX_SCORE FROM b_learn_attempt A ".
"WHERE A.STUDENT_ID = '".$arAttempt["STUDENT_ID"]."' AND A.TEST_ID = '".$arAttempt["TEST_ID"]."' ORDER BY COMPLETED DESC, SCORE DESC";
//AND A.COMPLETED = 'Y'
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if (!$arMaxScore = $res->Fetch())
return false;
if ($arGradeBook["COMPLETED"] == "Y")
$COMPLETED = "Y";
$strSql =
"UPDATE b_learn_gradebook SET RESULT = '".intval($arMaxScore["SCORE"])."', MAX_RESULT = '".intval($arMaxScore["MAX_SCORE"])."',COMPLETED = '".$COMPLETED."' ".
"WHERE ID = '".$arGradeBook["ID"]."'";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
CCertification::Certificate($arAttempt["STUDENT_ID"], $arAttempt["COURSE_ID"]);
}
return true;
}
function AttemptFinished($ATTEMPT_ID)
{
global $DB;
$ATTEMPT_ID = intval($ATTEMPT_ID);
if ($ATTEMPT_ID < 1)
return false;
$strSql =
"SELECT SUM(TR.POINT) as SCORE, SUM(Q.POINT) MAX_SCORE ".
"FROM b_learn_test_result TR ".
"INNER JOIN b_learn_question Q ON TR.QUESTION_ID = Q.ID ".
"WHERE ATTEMPT_ID = '".$ATTEMPT_ID."' ";
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if (!$ar = $res->Fetch())
return false;
$res = $this->Update($ATTEMPT_ID,
array(
"SCORE" => $ar["SCORE"],
"MAX_SCORE" => $ar["MAX_SCORE"],
"STATUS"=>"F",
"~DATE_END"=>CDatabase::CurrentTimeFunction(),
)
);
foreach(GetModuleEvents('learning', 'OnAfterAttemptFinished', true) as $arEvent)
ExecuteModuleEventEx($arEvent, array($ATTEMPT_ID));
if($res)
return CTestAttempt::OnAttemptChange($ATTEMPT_ID);
else
return false;
}
function RecountQuestions($ATTEMPT_ID)
{
global $DB;
$ATTEMPT_ID = intval($ATTEMPT_ID);
if ($ATTEMPT_ID < 1)
return false;
$strSql = "SELECT COUNT(*) CNT, SUM(TR.POINT) CNT_SUM, SUM(Q.POINT) MAX_POINT ".
"FROM b_learn_test_result TR ".
"INNER JOIN b_learn_question Q ON TR.QUESTION_ID = Q.ID ".
"WHERE TR.ATTEMPT_ID = ".$ATTEMPT_ID;
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if (!$ar = $res->Fetch())
return false;
$strSql = "UPDATE b_learn_attempt SET QUESTIONS = '".intval($ar["CNT"])."', SCORE = '".intval($ar["CNT_SUM"])."', MAX_SCORE = '".intval($ar["MAX_POINT"])."' WHERE ID = ".$ATTEMPT_ID;
if (!$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
return true;
}
function IsTestFailed($ATTEMPT_ID, $PERCENT)
{
global $DB;
$strSql =
"SELECT * ".
"FROM b_learn_test_result TR, b_learn_question Q ".
"WHERE TR.QUESTION_ID = Q.ID AND TR.CORRECT = 'N' AND TR.ANSWERED = 'Y' AND Q.CORRECT_REQUIRED = 'Y' AND TR.ATTEMPT_ID = '".intval($ATTEMPT_ID)."'";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return true;
if ($arStat = $res->Fetch())
return true;
$strSql =
"SELECT SUM(Q.POINT) as CNT_ALL, SUM(CASE WHEN TR.CORRECT = 'N' AND TR.ANSWERED = 'Y' THEN Q.POINT ELSE 0 END) as CNT_WRONG ".
"FROM b_learn_test_result TR, b_learn_question Q ".
"WHERE TR.ATTEMPT_ID = '".intval($ATTEMPT_ID)."' AND TR.QUESTION_ID = Q.ID";
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return true;
if (!$arStat = $res->Fetch())
return true;
if($arStat["CNT_ALL"] == 0)
{
return true;
}
elseif ($arStat["CNT_WRONG"]==0)
{
return false;
}
// Do some work due to IEEE 754
$epsilon = 0.001;
$cntNotFailed = $arStat["CNT_ALL"] - $arStat["CNT_WRONG"];
$scoreForSuccess = (float) ((int) $PERCENT);
$userScore = round( ($cntNotFailed / $arStat["CNT_ALL"]) * 100, 2);
$delta = abs($userScore - $scoreForSuccess);
$isTestFailed = true;
if ($userScore > $scoreForSuccess)
$isTestFailed = false;
elseif ($delta < $epsilon) // it means, that $userScore == $scoreForSuccess
$isTestFailed = false;
return ($isTestFailed);
}
public static function GetList($arOrder=array(), $arFilter=array(), $arSelect = array(), $arNavParams = array())
{
global $DB, $USER, $USER_FIELD_MANAGER;
$obUserFieldsSql = new CUserTypeSQL;
$obUserFieldsSql->SetEntity("LEARN_ATTEMPT", "A.ID");
$obUserFieldsSql->SetSelect($arSelect);
$obUserFieldsSql->SetFilter($arFilter);
$obUserFieldsSql->SetOrder($arOrder);
$arFields = array(
"ID" => "A.ID",
"TEST_ID" => "A.TEST_ID",
"OBY_DATE_END" => "A.DATE_END",
"STUDENT_ID" => "A.STUDENT_ID",
"DATE_START" => $DB->DateToCharFunction("A.DATE_START", "FULL"),
"DATE_END" => $DB->DateToCharFunction("A.DATE_END", "FULL"),
"STATUS" => "A.STATUS",
"COMPLETED" => "A.COMPLETED",
"SCORE" => "A.SCORE",
"MAX_SCORE" => "A.MAX_SCORE",
"QUESTIONS" => "A.QUESTIONS",
"TEST_NAME" => "T.NAME",
"USER_NAME" => $DB->Concat("'('",'U.LOGIN',"') '","CASE WHEN U.NAME IS NULL THEN '' ELSE U.NAME END","' '", "CASE WHEN U.LAST_NAME IS NULL THEN '' ELSE U.LAST_NAME END"),
"USER_ID" => "U.ID",
"MARK" => "TM.MARK",
"MESSAGE" => "TM.DESCRIPTION",
"LINKED_LESSON_ID" => "C.LINKED_LESSON_ID",
"COURSE_ID" => "C.ID",
"SPEED" => self::getSpeedFieldSql()
);
if (count($arSelect) <= 0 || in_array("*", $arSelect))
$arSelect = array_keys($arFields);
$arSqlSelect = array();
foreach($arSelect as $field)
{
$field = strtoupper($field);
if(array_key_exists($field, $arFields))
$arSqlSelect[$field] = $arFields[$field]." AS ".$field;
}
$sSelect = implode(",\n", $arSqlSelect);
if (!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = CTestAttempt::GetFilter($arFilter);
$strSqlSearch = "";
$arSqlSearchCnt = count($arSqlSearch);
for($i=0; $i<$arSqlSearchCnt; $i++)
if(strlen($arSqlSearch[$i])>0)
$strSqlSearch .= " AND ".$arSqlSearch[$i]." ";
$r = $obUserFieldsSql->GetFilter();
if(strlen($r)>0)
$strSqlSearch .= " AND (".$r.") ";
$bCheckPerm = 'ORPHANED VAR';
$strSqlFrom = '';
$strSql = static::_GetListSQLFormer($sSelect, $obUserFieldsSql, $bCheckPerm, $USER, $arFilter, $strSqlSearch, $strSqlFrom);
if (!is_array($arOrder))
$arOrder = Array();
foreach($arOrder as $by=>$order)
{
$by = strtolower($by);
$order = strtolower($order);
if ($order!="asc")
$order = "desc";
if ($by == "id")
$arSqlOrder[] = " A.ID ".$order." ";
elseif ($by == "test_id")
$arSqlOrder[] = " A.TEST_ID ".$order." ";
elseif ($by == "student_id")
$arSqlOrder[] = " A.STUDENT_ID ".$order." ";
elseif ($by == "date_start")
$arSqlOrder[] = " A.DATE_START ".$order." ";
elseif ($by == "date_end")
$arSqlOrder[] = " A.DATE_END ".$order." ";
elseif ($by == "status")
$arSqlOrder[] = " A.STATUS ".$order." ";
elseif ($by == "score")
$arSqlOrder[] = " A.SCORE ".$order." ";
elseif ($by == "max_score")
$arSqlOrder[] = " A.MAX_SCORE ".$order." ";
elseif ($by == "completed")
$arSqlOrder[] = " A.COMPLETED ".$order." ";
elseif ($by == "questions")
$arSqlOrder[] = " A.QUESTIONS ".$order." ";
elseif ($by == "user_name")
$arSqlOrder[] = " USER_NAME ".$order." ";
elseif ($by == "test_name")
$arSqlOrder[] = " TEST_NAME ".$order." ";
elseif ($by == "speed")
$arSqlOrder[] = " SPEED ".$order." ";
elseif ($s = $obUserFieldsSql->GetOrder($by))
$arSqlOrder[$by] = " ".$s." ".$order." ";
else
$arSqlOrder[] = " A.ID ".$order." ";
}
$strSqlOrder = "";
DelDuplicateSort($arSqlOrder);
$arSqlOrderCnt = count($arSqlOrder);
for ($i=0; $i<$arSqlOrderCnt; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= $strSqlOrder;
if ( ! empty($arNavParams) )
{
$nTopCount = null;
if (isset($arNavParams['NAV_PARAMS']['nPageTop']) && ($arNavParams['NAV_PARAMS']['nPageTop'] > 0))
$nTopCount = (int) $arNavParams['NAV_PARAMS']['nPageTop'];
else if (isset($arNavParams['nPageTop']))
$nTopCount = (int) $arNavParams['nPageTop'];
else if (isset($arNavParams['nTopCount']))
$nTopCount = (int) $arNavParams['nTopCount'];
else
{
$res_cnt = $DB->Query("SELECT COUNT(A.ID) as C " . $strSqlFrom);
$res_cnt = $res_cnt->fetch();
$res = new CDBResult();
$res->NavQuery($strSql, $res_cnt['C'], $arNavParams);
$res->SetUserFields($USER_FIELD_MANAGER->GetUserFields("LEARN_ATTEMPT"));
}
if ($nTopCount !== null)
{
$strSql = $DB->TopSql($strSql, $nTopCount);
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res->SetUserFields($USER_FIELD_MANAGER->GetUserFields("LEARN_ATTEMPT"));
}
}
else
{
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res->SetUserFields($USER_FIELD_MANAGER->GetUserFields("LEARN_ATTEMPT"));
}
return $res;
}
private static function getSpeedFieldSql()
{
$connection = \Bitrix\Main\Application::getConnection();
if ($connection instanceof \Bitrix\Main\DB\MssqlConnection)
{
return "DATEDIFF(s, A.DATE_START, A.DATE_END) / A.QUESTIONS";
}
elseif ($connection instanceof \Bitrix\Main\DB\OracleConnection)
{
return "round((A.DATE_END-A.DATE_START)*86400) / A.QUESTIONS";
}
else
{
return "round((unix_timestamp(IFNULL(A.DATE_END, A.DATE_START))-unix_timestamp(A.DATE_START)) / A.QUESTIONS)";
}
}
public static function CreateAttemptQuestions($ATTEMPT_ID)
{
global $APPLICATION, $DB, $DBType;
$ATTEMPT_ID = intval($ATTEMPT_ID);
$attempt = CTestAttempt::GetByID($ATTEMPT_ID);
if (!$arAttempt = $attempt->Fetch())
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_ATTEMPT_ID_EX"), "ERROR_NO_ATTEMPT_ID");
return false;
}
$test = CTest::GetByID($arAttempt["TEST_ID"]);
if (!$arTest = $test->Fetch())
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_ID_EX"), "ERROR_NO_TEST_ID");
return false;
}
$strSql = "DELETE FROM b_learn_test_result WHERE ATTEMPT_ID = ".$ATTEMPT_ID;
if (!$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
/**
* QUESTIONS_FROM values:
* 'L' - X questions from every lesson in course
* 'C' - X questions from every lesson from every chapter in the course
* In this case questions taken from immediate lessons of all chapters (X per chapter) in the course.
* In new data model it means, get X questions from every lesson in the course, except
* 1) immediate lessons-childs of the course and
* 2) lessons, contains other lessons (because, in old data model chapters doesn't contains questions)
*
* 'H' - all questions from the selected chapter (recursive) in the course
* This case must be ignored, because converter to new data model updates 'H' to 'R', but in case
* when chapter is not exists updates didn't become. So QUESTIONS_FROM stayed in 'H' value. And it means,
* that there is no chapter exists with QUESTIONS_FROM_ID, so we can't do work. And we should just
* ignore, for backward compatibility (so, don't throw an error).
* 'S' - all questions from the selected lesson (unilesson_id in QUESTIONS_FROM_ID)
* 'A' - all questions of the course (nothing interesting in QUESTIONS_FROM_ID)
*
* new values:
* 'R' - all questions from the tree with root at selected lesson (include questions of selected lesson)
* in the course (unilesson_id in QUESTIONS_FROM_ID)
*/
if ($arTest["QUESTIONS_FROM"] == "C" || $arTest["QUESTIONS_FROM"] == "L")
{
$courseId = $arTest['COURSE_ID'] + 0;
$courseLessonId = CCourse::CourseGetLinkedLesson ($courseId);
if ($courseLessonId === false)
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
$clauseAllChildsLessons = CLearnHelper::SQLClauseForAllSubLessons ($courseLessonId);
if ($arTest["QUESTIONS_FROM"] == "C") // X questions from every lessons from every chapter in the course
{
$strSql =
"SELECT Q.ID as QUESTION_ID, TLEUP.SOURCE_NODE as FROM_ID
FROM b_learn_lesson L
INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID
INNER JOIN b_learn_lesson_edges TLEUP ON L.ID = TLEUP.TARGET_NODE
LEFT OUTER JOIN b_learn_lesson_edges TLEDOWN ON L.ID = TLEDOWN.SOURCE_NODE "
. "WHERE L.ID IN (" . $clauseAllChildsLessons . ") \n" // only lessons from COURSE_ID = $arTest['COURSE_ID']
. " AND TLEDOWN.SOURCE_NODE IS NULL \n" // exclude lessons, contains other lessons ("chapters")
// include lessons in current course tree context only (and exclude immediate childs of course)
. " AND TLEUP.SOURCE_NODE IN (" . $clauseAllChildsLessons . ") \n"
. " AND Q.ACTIVE = 'Y' " // active questions only
. ($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "")
. "ORDER BY ".($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID");
}
else // 'L' X questions from every lesson in course
{
$strSql =
"SELECT Q.ID as QUESTION_ID, L.ID as FROM_ID ".
"FROM b_learn_lesson L ".
"INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID ".
"WHERE L.ID IN (" . $clauseAllChildsLessons . ") AND Q.ACTIVE = 'Y' ".
($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "").
"ORDER BY ".($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID");
}
if (!$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
return false;
$Values = Array();
$tmp = Array();
while ($arRecord = $res->Fetch())
{
if (is_set($tmp, $arRecord["FROM_ID"]))
{
if ($tmp[$arRecord["FROM_ID"]] < $arTest["QUESTIONS_AMOUNT"])
$tmp[$arRecord["FROM_ID"]]++;
else
continue;
}
else
{
$tmp[$arRecord["FROM_ID"]] = 1;
}
$Values[]= $arRecord["QUESTION_ID"];
}
if (empty($Values))
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
$DB->StartTransaction();
foreach ($Values as $ID)
{
$strSql = "INSERT INTO b_learn_test_result (ATTEMPT_ID, QUESTION_ID) VALUES (".$ATTEMPT_ID.",".$ID.")";
if (!$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__))
{
$DB->Rollback();
return false;
}
}
$DB->Commit();
}
elseif (($arTest["QUESTIONS_FROM"] == "H" || $arTest["QUESTIONS_FROM"] == "S" || $arTest["QUESTIONS_FROM"] == "R") && $arTest["QUESTIONS_FROM_ID"])
{
$WHERE = '';
if ($arTest["QUESTIONS_FROM"] == "H")
{
/**
* 'H' - all questions from the selected chapter (recursive) in the course
* This case must be ignored, because converter to new data model updates 'H' to 'R', but in case
* when chapter is not exists updates didn't become. So QUESTIONS_FROM stayed in 'H' value. And it means,
* that there is no chapter exists with QUESTIONS_FROM_ID, so we can't do work. And we should just
* ignore, for backward compatibility (so, don't throw an error).
*/
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
elseif ($arTest["QUESTIONS_FROM"] == 'R') // all questions from the tree with root at selected lesson (include questions of selected lesson) in the course (unilesson_id in QUESTIONS_FROM_ID)
{
$clauseAllChildsLessons = CLearnHelper::SQLClauseForAllSubLessons ($arTest['QUESTIONS_FROM_ID']);
$WHERE = " (L.ID IN(" . $clauseAllChildsLessons . ") OR (L.ID = " . ($arTest['QUESTIONS_FROM_ID'] + 0) . ")) ";
}
elseif ($arTest["QUESTIONS_FROM"] == 'S') // 'S' - all questions from the selected lesson (unilesson_id in QUESTIONS_FROM_ID)
{
$clauseAllChildsLessons = $arTest["QUESTIONS_FROM_ID"] + 0;
$WHERE = " (L.ID IN(" . $clauseAllChildsLessons . ") OR (L.ID = " . ($arTest['QUESTIONS_FROM_ID'] + 0) . ")) ";
}
else
{
return (false);
}
$strSql =
"SELECT Q.ID AS QUESTION_ID ".
"FROM b_learn_lesson L ".
"INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID ".
"WHERE " . $WHERE . " AND Q.ACTIVE = 'Y' ".
($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "").
"ORDER BY ".($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID ").
($arTest["QUESTIONS_AMOUNT"] > 0 ? "LIMIT ".$arTest["QUESTIONS_AMOUNT"] :"");
$success = false;
$rsQuestions = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$strSql = '';
if ($rsQuestions)
{
if ($DBType === 'oracle')
{
while ($arQuestion = $rsQuestions->fetch())
{
$strSql .= " \nINTO b_learn_test_result (ATTEMPT_ID, QUESTION_ID) "
. "VALUES (" . $ATTEMPT_ID . ", " . (int) $arQuestion['QUESTION_ID'] . ")";
}
if ($strSql !== '')
$strSql = "INSERT ALL " . $strSql . " \nSELECT 1 FROM DUAL";
}
else
{
$arSqlSubstrings = array();
while ($arQuestion = $rsQuestions->fetch())
$arSqlSubstrings[] = "(" . $ATTEMPT_ID . ", " . $arQuestion['QUESTION_ID'] . ")";
if ( ! empty($arSqlSubstrings) )
$strSql = "INSERT INTO b_learn_test_result (ATTEMPT_ID, QUESTION_ID) VALUES " . implode(",\n", $arSqlSubstrings);
}
if ($strSql !== '')
{
$rc = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if ($rc && intval($rc->AffectedRowsCount()) > 0)
$success = true;
}
}
if ( ! $success )
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
}
elseif ($arTest["QUESTIONS_FROM"] == 'A')
{
$courseId = $arTest['COURSE_ID'] + 0;
$courseLessonId = CCourse::CourseGetLinkedLesson ($courseId);
if ($courseLessonId === false)
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
$clauseAllChildsLessons = CLearnHelper::SQLClauseForAllSubLessons ($courseLessonId);
if ($DBType === 'mysql')
{
$strSql =
"SELECT Q.ID AS QUESTION_ID
FROM b_learn_lesson L
INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID
WHERE (L.ID IN (" . $clauseAllChildsLessons . ") OR (L.ID = " . ($courseLessonId + 0) . ") )
AND Q.ACTIVE = 'Y' "
. ($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "").
"ORDER BY " . ($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID ").
($arTest["QUESTIONS_AMOUNT"] > 0 ? "LIMIT " . ($arTest["QUESTIONS_AMOUNT"] + 0) : "");
}
elseif ($DBType === 'mssql')
{
$strSql =
"SELECT " . ($arTest["QUESTIONS_AMOUNT"] > 0 ? "TOP " . ($arTest["QUESTIONS_AMOUNT"] + 0) . " " :"") . " Q.ID AS QUESTION_ID
FROM b_learn_lesson L
INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID
WHERE (L.ID IN (" . $clauseAllChildsLessons . ") OR (L.ID = " . ($courseLessonId + 0) . ") )
AND Q.ACTIVE = 'Y' "
. ($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "").
"ORDER BY ".($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID");
}
else // oracle
{
$strSql =
"SELECT Q.ID AS QUESTION_ID
FROM b_learn_lesson L
INNER JOIN b_learn_question Q ON L.ID = Q.LESSON_ID
WHERE (L.ID IN (" . $clauseAllChildsLessons . ") OR (L.ID = " . ($courseLessonId + 0) . ") )
AND Q.ACTIVE = 'Y' "
. ($arTest["QUESTIONS_AMOUNT"] > 0 ? "AND ROWNUM <= ".$arTest["QUESTIONS_AMOUNT"]." " :"").
($arTest["INCLUDE_SELF_TEST"] != "Y" ? "AND Q.SELF = 'N' " : "").
"ORDER BY ".($arTest["RANDOM_QUESTIONS"] == "Y" ? CTest::GetRandFunction() : "L.SORT, Q.SORT, L.ID");
}
$success = false;
$rsQuestions = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$strSql = '';
if ($rsQuestions)
{
if ($DBType === 'oracle')
{
while ($arQuestion = $rsQuestions->fetch())
{
$strSql .= " \nINTO b_learn_test_result (ATTEMPT_ID, QUESTION_ID) "
. "VALUES (" . $ATTEMPT_ID . ", " . (int) $arQuestion['QUESTION_ID'] . ")";
}
if ($strSql !== '')
$strSql = "INSERT ALL " . $strSql . " \nSELECT 1 FROM DUAL";
}
else
{
$arSqlSubstrings = array();
while ($arQuestion = $rsQuestions->fetch())
$arSqlSubstrings[] = "(" . $ATTEMPT_ID . ", " . $arQuestion['QUESTION_ID'] . ")";
if ( ! empty($arSqlSubstrings) )
$strSql = "INSERT INTO b_learn_test_result (ATTEMPT_ID, QUESTION_ID) VALUES " . implode(",\n", $arSqlSubstrings);
}
if ($strSql !== '')
{
$rc = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if ($rc && intval($rc->AffectedRowsCount()) > 0)
$success = true;
}
}
if ( ! $success )
{
$APPLICATION->ThrowException(GetMessage("LEARNING_BAD_TEST_IS_EMPTY"), "ERROR_TEST_IS_EMPTY");
return false;
}
}
else
return (false);
$strSql = "UPDATE b_learn_attempt SET QUESTIONS = '".CTestResult::GetCount($ATTEMPT_ID)."' WHERE ID = ".$ATTEMPT_ID;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
return true;
}
}