Minor: Format code

pull/5880/head
Angel Fernando Quiroz Campos 11 months ago
parent 7e95c3dd30
commit 7c5857d456
No known key found for this signature in database
GPG Key ID: B284841AE3E562CD
  1. 6
      main/admin/add_users_to_usergroup.php
  2. 4
      main/admin/db.php
  3. 2
      main/auth/sort_my_courses.php
  4. 5
      main/coursecopy/export_moodle.php
  5. 9
      main/inc/ajax/session_clock.ajax.php
  6. 93
      main/inc/lib/Compilatio.php
  7. 379
      main/inc/lib/MoodleImport.php
  8. 7
      main/inc/lib/display.lib.php
  9. 120
      main/inc/lib/document.lib.php
  10. 2
      main/inc/lib/exercise.lib.php
  11. 4
      main/inc/lib/formvalidator/FormValidator.class.php
  12. 16
      main/inc/lib/message.lib.php
  13. 191
      main/inc/lib/moodleexport/ActivityExport.php
  14. 226
      main/inc/lib/moodleexport/AssignExport.php
  15. 236
      main/inc/lib/moodleexport/CourseExport.php
  16. 166
      main/inc/lib/moodleexport/FeedbackExport.php
  17. 163
      main/inc/lib/moodleexport/FileExport.php
  18. 56
      main/inc/lib/moodleexport/FolderExport.php
  19. 184
      main/inc/lib/moodleexport/ForumExport.php
  20. 138
      main/inc/lib/moodleexport/GlossaryExport.php
  21. 541
      main/inc/lib/moodleexport/MoodleExport.php
  22. 58
      main/inc/lib/moodleexport/PageExport.php
  23. 375
      main/inc/lib/moodleexport/QuizExport.php
  24. 98
      main/inc/lib/moodleexport/ResourceExport.php
  25. 136
      main/inc/lib/moodleexport/SectionExport.php
  26. 52
      main/inc/lib/moodleexport/UrlExport.php
  27. 2
      main/lp/storageapi.php
  28. 6
      main/session/add_users_to_session.php
  29. 4
      main/survey/survey.php
  30. 2
      main/survey/surveyUtil.class.php
  31. 2
      main/work/work.lib.php
  32. 3
      plugin/zoom/lib/ZoomPlugin.php
  33. 1
      plugin/zoom/meeting.php
  34. 4
      src/Chamilo/CourseBundle/Component/CourseCopy/CourseSelectForm.php

@ -191,13 +191,13 @@ if (ChamiloApi::isAjaxRequest() && $_SERVER['REQUEST_METHOD'] === 'POST' && isse
'id' => $user['id'],
'username' => $user['username'],
'firstname' => $user['firstname'],
'lastname' => $user['lastname']
'lastname' => $user['lastname'],
];
}
header('Content-Type: application/json');
echo json_encode($users);
die();
exit();
}
$first_letter_user = '';
@ -528,7 +528,7 @@ echo '</div>';
</button>
</span>
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="show_last_ten_users_button" title="<?php echo get_lang('ShowLastTenUsers') ?>">
<button class="btn btn-default" type="button" id="show_last_ten_users_button" title="<?php echo get_lang('ShowLastTenUsers'); ?>">
<i class="fa fa-clock-o"></i>
</button>
</span>

@ -3,9 +3,11 @@
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
if (!api_is_global_platform_admin()) {
die('Please connect as a global administrator to access this page');
exit('Please connect as a global administrator to access this page');
}
echo "In this version, the script allowing you to connect to the database from your Chamilo interface has been
deprecated/removed due to increasing reports about a possible vulnerability (which we agree with, in principle).
To use this feature, please download Adminer as one single PHP file from https://www.adminer.org/#download,

@ -19,7 +19,7 @@ $authorizedActions = [
'deletecoursecategory',
'createcoursecategory',
'set_collapsable',
'unsubscribe'
'unsubscribe',
];
if (in_array(trim($_REQUEST['action']), $authorizedActions)) {
$action = trim($_REQUEST['action']);

@ -8,7 +8,6 @@ use moodleexport\MoodleExport;
/**
* Create a Moodle export.
*
*/
require_once __DIR__.'/../inc/global.inc.php';
require_once api_get_path(SYS_PATH).'main/work/work.lib.php';
@ -72,7 +71,7 @@ if ($action === 'course_select_form' && Security::check_token('post')) {
// Perform export
$courseId = api_get_course_id();
$exportDir = 'moodle_export_' . $courseId;
$exportDir = 'moodle_export_'.$courseId;
try {
$moodleVersion = isset($_POST['moodle_version']) ? (int) $_POST['moodle_version'] : 3;
$mbzFile = $exporter->export($courseId, $exportDir, $moodleVersion);
@ -135,7 +134,7 @@ if ($action === 'course_select_form' && Security::check_token('post')) {
$exporter->setAdminUserData($adminId, $adminUsername, $adminEmail);
$courseId = api_get_course_id(); // Get course ID
$exportDir = 'moodle_export_' . $courseId;
$exportDir = 'moodle_export_'.$courseId;
try {
$moodleVersion = isset($values['moodle_version']) ? $values['moodle_version'] : '3';

@ -27,7 +27,7 @@ if (isset($_GET['action'])) {
$session = new ChamiloSession();
$endTime = 0;
$endTime = 0;
$isExpired = false;
$timeLeft = -1;
@ -44,9 +44,8 @@ if (isset($_GET['action'])) {
}
$timeLeft = $endTime - $currentTime;
}
else {
$endTime = 999999;
} else {
$endTime = 999999;
$isExpired = false;
$timeLeft = 999999;
}
@ -72,4 +71,4 @@ if (isset($_GET['action'])) {
// No action provided
http_response_code(400);
echo json_encode(['error' => 'No action parameter provided']);
}
}

@ -15,6 +15,11 @@ class Compilatio
{
/** Identification key for the Compilatio account*/
public $key;
/**
* @var Client
*/
public $client;
/**
* @var string
*/
@ -24,11 +29,6 @@ class Compilatio
private $proxyHost;
private $proxyPort;
/**
* @var Client
*/
public $client;
/**
* Compilatio constructor.
*
@ -62,36 +62,6 @@ class Compilatio
$this->client = new Client($clientConfig);
}
/**
* @throws Exception
*/
protected function getSettings(): array
{
if (empty(api_get_configuration_value('allow_compilatio_tool')) ||
empty(api_get_configuration_value('compilatio_tool'))
) {
throw new Exception('Compilatio not available');
}
$compilatioTool = api_get_configuration_value('compilatio_tool');
if (!isset($compilatioTool['settings'])) {
throw new Exception('Compilatio config available');
}
$settings = $compilatioTool['settings'];
if (empty($settings['key'])) {
throw new Exception('API key not available');
}
if (empty($settings['api_url'])) {
throw new Exception('Api URL not available');
}
return $settings;
}
/**
* @return string
*/
@ -153,20 +123,20 @@ class Compilatio
'filename' => basename($filename),
'indexed' => 'true',
'user_notes' => [
'description' => $description
'description' => $description,
],
'authors' => [
[
'firstname' => $user->getFirstname(),
'lastname' => $user->getlastname(),
'email_address' => $user->getEmail(),
]
],
],
'depositor' => [
'firstname' => $user->getFirstname(),
'lastname' => $user->getlastname(),
'email_address' => $user->getEmail(),
]
],
];
try {
@ -176,14 +146,14 @@ class Compilatio
[
'multipart' => [
[
'name' => 'postData',
'contents' => json_encode($postData)
'name' => 'postData',
'contents' => json_encode($postData),
],
[
'name' => 'file',
'name' => 'file',
'contents' => Utils::tryFopen($filepath, 'r'),
]
]
],
],
]
)
->getBody()
@ -238,7 +208,6 @@ class Compilatio
*/
public function deldoc(string $documentId)
{
}
/**
@ -255,7 +224,7 @@ class Compilatio
[
'json' => [
'doc_id' => $compilatioId,
'recipe_name' => 'anasim'
'recipe_name' => 'anasim',
],
]
)
@ -332,7 +301,7 @@ class Compilatio
$result = Database::query($sql);
$result = Database::fetch_object($result);
return $result ? (string)$result->compilatio_id : null;
return $result ? (string) $result->compilatio_id : null;
}
public function giveWorkIdState(int $workId): string
@ -372,7 +341,7 @@ class Compilatio
$actionCompilatio .= "<div style='font-size:80%;font-style:italic;margin-bottom:5px;'>"
.get_lang('CompilatioAnalysisPercentage')
."</div>";
$actionCompilatio .= $spinnerIcon.PHP_EOL .get_lang('CompilatioAnalysisEnding');
$actionCompilatio .= $spinnerIcon.PHP_EOL.get_lang('CompilatioAnalysisEnding');
break;
case 'waiting':
$actionCompilatio .= $spinnerIcon.PHP_EOL.get_lang('CompilatioWaitingAnalysis');
@ -388,4 +357,34 @@ class Compilatio
return $workId.'|'.$actionCompilatio.'|'.$status.'|';
}
/**
* @throws Exception
*/
protected function getSettings(): array
{
if (empty(api_get_configuration_value('allow_compilatio_tool')) ||
empty(api_get_configuration_value('compilatio_tool'))
) {
throw new Exception('Compilatio not available');
}
$compilatioTool = api_get_configuration_value('compilatio_tool');
if (!isset($compilatioTool['settings'])) {
throw new Exception('Compilatio config available');
}
$settings = $compilatioTool['settings'];
if (empty($settings['key'])) {
throw new Exception('API key not available');
}
if (empty($settings['api_url'])) {
throw new Exception('Api URL not available');
}
return $settings;
}
}

@ -387,19 +387,19 @@ class MoodleImport
$exercise->updateFeedbackType($feedbackType);
// Shuffle questions and answers
$exercise->setRandom((int)$moduleValues['shufflequestions'] === 1 ? -1 : 0);
$exercise->setRandom((int) $moduleValues['shufflequestions'] === 1 ? -1 : 0);
$exercise->updateRandomAnswers(!empty($moduleValues['shuffleanswers']));
// Set time limit and grading
$limeLimit = !empty($moduleValues['timelimit']) ? round($moduleValues['timelimit'] / 60) : 0;
$exercise->updateExpiredTime((int)$limeLimit);
$exercise->updateExpiredTime((int) $limeLimit);
$gradesXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/grades.xml');
$gradeQuizValues = $this->readQuizGradeModule($gradesXml, $moduleValues['quiz_id']);
$exercise->pass_percentage = !empty($gradeQuizValues['grademax']) ? round(($gradeQuizValues['gradepass'] * 100) / $gradeQuizValues['grademax']) : 0;
// Set type (single question per page or all in one)
$exercise->updateType((int)$moduleValues['questionsperpage'] === 1 ? 2 : 1);
$exercise->updateType((int) $moduleValues['questionsperpage'] === 1 ? 2 : 1);
// Set start and end times
$exercise->start_time = !empty($moduleValues['timeopen']) ? api_get_utc_datetime($moduleValues['timeopen']) : null;
@ -608,11 +608,12 @@ class MoodleImport
* Detects the Moodle version from the backup XML file.
*
* @param string $destinationDir The directory where the moodle_backup.xml is located.
*
* @return int Returns 4 if the Moodle version is 4 or higher, otherwise returns 3.
*/
public function detectMoodleVersion($destinationDir): int
{
$moodleBackupXmlPath = $destinationDir . '/moodle_backup.xml';
$moodleBackupXmlPath = $destinationDir.'/moodle_backup.xml';
$xml = file_get_contents($moodleBackupXmlPath);
$doc = new DOMDocument();
@ -620,7 +621,7 @@ class MoodleImport
$backupRelease = $doc->getElementsByTagName('backup_release');
$version = null;
foreach ($backupRelease as $release) {
$version = (float)$release->nodeValue;
$version = (float) $release->nodeValue;
}
return $version >= 4 ? 4 : 3;
@ -653,10 +654,10 @@ class MoodleImport
/**
* Adds an item to a learning path section and processes its relationships.
*
* @param int $lpId The ID of the learning path.
* @param string $itemType The type of the item (e.g., quiz, document).
* @param int $itemId The ID of the item to be added.
* @param string $itemTitle The title of the item.
* @param int $lpId The ID of the learning path.
* @param string $itemType The type of the item (e.g., quiz, document).
* @param int $itemId The ID of the item to be added.
* @param string $itemTitle The title of the item.
* @param int|null $previousItemId The ID of the previous item (optional).
*
* @return int The ID of the newly added learning path item.
@ -1888,6 +1889,7 @@ class MoodleImport
* Reads and parses the quiz module XML for Moodle version 4.
*
* @param string $moduleXml The XML content of the quiz module.
*
* @return array Returns an array with quiz data and question instances.
*/
public function readQuizModuleV4($moduleXml)
@ -1923,7 +1925,8 @@ class MoodleImport
* Reads and processes quiz questions for Moodle version 4.
*
* @param string $questionsXml The XML content containing question data.
* @param string $quizXml The XML content containing quiz data.
* @param string $quizXml The XML content containing quiz data.
*
* @return array Returns an array of processed questions, either by category or by question bank reference.
*/
public function readMainQuestionsXmlV4($questionsXml, $quizXml)
@ -1946,180 +1949,6 @@ class MoodleImport
return [];
}
/**
* Processes quiz questions organized by category.
*
* @param DOMDocument $questionsDoc The document containing the questions XML.
* @param DOMDocument $quizDoc The document containing the quiz XML.
* @return array Returns an array of processed questions filtered by category.
*/
protected function processByCategory($questionsDoc, $quizDoc)
{
$questionInstances = $quizDoc->getElementsByTagName('question_instance');
$questionSetReferences = [];
foreach ($questionInstances as $instance) {
$questionSetReference = $instance->getElementsByTagName('question_set_reference')->item(0);
if ($questionSetReference) {
$filterCondition = $questionSetReference->getElementsByTagName('filtercondition')->item(0)->nodeValue;
$filterCondition = json_decode($filterCondition, true);
if (isset($filterCondition['questioncategoryid'])) {
$categoryId = $filterCondition['questioncategoryid'];
$questionSetReferences[] = $categoryId;
}
}
}
if (empty($questionSetReferences)) {
return [];
}
$processedQuestions = [];
$questionsCount = 0;
foreach ($questionSetReferences as $categoryId) {
$xpath = new DOMXPath($questionsDoc);
$query = "//question_bank_entry[questioncategoryid='$categoryId']/question_version/question_versions/questions/question";
$entries = $xpath->query($query);
foreach ($entries as $question) {
if ($questionsCount >= count($questionInstances)) {
break;
}
$currentItem = $this->processQuestionV4($question);
if (!empty($currentItem)) {
$processedQuestions[] = $currentItem;
$questionsCount++;
}
}
}
return $processedQuestions;
}
/**
* Processes quiz questions based on question bank references.
*
* @param DOMDocument $questionsDoc The document containing the questions XML.
* @param DOMDocument $quizDoc The document containing the quiz XML.
* @return array Returns an array of processed questions from the question bank.
*/
protected function processByBankReference($questionsDoc, $quizDoc)
{
$questionInstances = $quizDoc->getElementsByTagName('question_instance');
$questionBankEntries = [];
foreach ($questionInstances as $instance) {
$questionReference = $instance->getElementsByTagName('question_reference')->item(0);
if ($questionReference) {
$questionBankEntryId = $questionReference->getElementsByTagName('questionbankentryid')->item(0)->nodeValue;
$questionBankEntries[] = $questionBankEntryId;
}
}
if (empty($questionBankEntries)) {
return [];
}
$processedQuestions = [];
$xpath = new DOMXPath($questionsDoc);
foreach ($questionBankEntries as $entryId) {
$query = "//question_bank_entry[@id='$entryId']/question_version/question_versions/questions/question";
$entries = $xpath->query($query);
foreach ($entries as $question) {
$processedQuestions[] = $this->processQuestionV4($question);
}
}
return $processedQuestions;
}
/**
* Processes individual quiz question data for Moodle version 4.
*
* @param DOMElement $question The DOM element representing a question in the XML.
* @return array Returns an associative array containing question data, including type, text, and answers.
*/
protected function processQuestionV4($question)
{
$currentItem = [
"questionid" => $question->getAttribute('id'),
"name" => '',
"questiontext" => '',
"generalfeedback" => '',
"defaultmark" => "1.0000000",
"penalty" => "0.3333333",
"qtype" => '',
"plugin_qtype_question" => [],
];
$questionType = '';
foreach ($question->childNodes as $item) {
switch ($item->nodeName) {
case 'name':
$currentItem['name'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'questiontext':
$currentItem['questiontext'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'generalfeedback':
$currentItem['generalfeedback'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'qtype':
$questionType = $item->nodeValue;
$currentItem['qtype'] = $questionType;
break;
case 'plugin_qtype_' . $questionType . '_question':
$currentItem['plugin_qtype_' . $questionType . '_question'] = $this->processAnswersV4($item);
break;
}
}
return !empty($currentItem['name']) ? $currentItem : [];
}
/**
* Processes the answers for a given quiz question in Moodle version 4.
*
* @param DOMElement $item The DOM element containing answer data.
* @return array Returns an array of processed answers, each containing details like answer text and fraction.
*/
protected function processAnswersV4($item)
{
$answersList = [];
$answers = $item->getElementsByTagName('answer');
foreach ($answers as $i => $answer) {
$answerData = [
'answerid' => $answer->getAttribute('id'),
'answertext' => '',
'fraction' => '0.0000000',
];
foreach ($answer->childNodes as $properties) {
switch ($properties->nodeName) {
case 'answertext':
$answerData['answertext'] = htmlspecialchars_decode($properties->nodeValue);
break;
case 'fraction':
$answerData['fraction'] = $properties->nodeValue;
break;
case 'feedback':
$answerData['feedback'] = htmlspecialchars_decode($properties->nodeValue);
break;
}
}
$answersList[$i] = $answerData;
}
return $answersList;
}
/**
* Search the files of a resource type folder in main Files XML.
*
@ -2748,7 +2577,7 @@ class MoodleImport
/**
* Updates the previous item ID for a given learning path item.
*
* @param int $currentItemId The ID of the current item.
* @param int $currentItemId The ID of the current item.
* @param int $previousItemId The ID of the previous item to be set.
*/
public function updateLpItemPreviousId($currentItemId, $previousItemId)
@ -2762,7 +2591,7 @@ class MoodleImport
* Updates the next item ID for a given learning path item.
*
* @param int $previousItemId The ID of the previous item.
* @param int $currentItemId The ID of the current item to be set as next.
* @param int $currentItemId The ID of the current item to be set as next.
*/
public function updateLpItemNextId($previousItemId, $currentItemId)
{
@ -2856,6 +2685,184 @@ class MoodleImport
}
}
/**
* Processes quiz questions organized by category.
*
* @param DOMDocument $questionsDoc The document containing the questions XML.
* @param DOMDocument $quizDoc The document containing the quiz XML.
*
* @return array Returns an array of processed questions filtered by category.
*/
protected function processByCategory($questionsDoc, $quizDoc)
{
$questionInstances = $quizDoc->getElementsByTagName('question_instance');
$questionSetReferences = [];
foreach ($questionInstances as $instance) {
$questionSetReference = $instance->getElementsByTagName('question_set_reference')->item(0);
if ($questionSetReference) {
$filterCondition = $questionSetReference->getElementsByTagName('filtercondition')->item(0)->nodeValue;
$filterCondition = json_decode($filterCondition, true);
if (isset($filterCondition['questioncategoryid'])) {
$categoryId = $filterCondition['questioncategoryid'];
$questionSetReferences[] = $categoryId;
}
}
}
if (empty($questionSetReferences)) {
return [];
}
$processedQuestions = [];
$questionsCount = 0;
foreach ($questionSetReferences as $categoryId) {
$xpath = new DOMXPath($questionsDoc);
$query = "//question_bank_entry[questioncategoryid='$categoryId']/question_version/question_versions/questions/question";
$entries = $xpath->query($query);
foreach ($entries as $question) {
if ($questionsCount >= count($questionInstances)) {
break;
}
$currentItem = $this->processQuestionV4($question);
if (!empty($currentItem)) {
$processedQuestions[] = $currentItem;
$questionsCount++;
}
}
}
return $processedQuestions;
}
/**
* Processes quiz questions based on question bank references.
*
* @param DOMDocument $questionsDoc The document containing the questions XML.
* @param DOMDocument $quizDoc The document containing the quiz XML.
*
* @return array Returns an array of processed questions from the question bank.
*/
protected function processByBankReference($questionsDoc, $quizDoc)
{
$questionInstances = $quizDoc->getElementsByTagName('question_instance');
$questionBankEntries = [];
foreach ($questionInstances as $instance) {
$questionReference = $instance->getElementsByTagName('question_reference')->item(0);
if ($questionReference) {
$questionBankEntryId = $questionReference->getElementsByTagName('questionbankentryid')->item(0)->nodeValue;
$questionBankEntries[] = $questionBankEntryId;
}
}
if (empty($questionBankEntries)) {
return [];
}
$processedQuestions = [];
$xpath = new DOMXPath($questionsDoc);
foreach ($questionBankEntries as $entryId) {
$query = "//question_bank_entry[@id='$entryId']/question_version/question_versions/questions/question";
$entries = $xpath->query($query);
foreach ($entries as $question) {
$processedQuestions[] = $this->processQuestionV4($question);
}
}
return $processedQuestions;
}
/**
* Processes individual quiz question data for Moodle version 4.
*
* @param DOMElement $question The DOM element representing a question in the XML.
*
* @return array Returns an associative array containing question data, including type, text, and answers.
*/
protected function processQuestionV4($question)
{
$currentItem = [
"questionid" => $question->getAttribute('id'),
"name" => '',
"questiontext" => '',
"generalfeedback" => '',
"defaultmark" => "1.0000000",
"penalty" => "0.3333333",
"qtype" => '',
"plugin_qtype_question" => [],
];
$questionType = '';
foreach ($question->childNodes as $item) {
switch ($item->nodeName) {
case 'name':
$currentItem['name'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'questiontext':
$currentItem['questiontext'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'generalfeedback':
$currentItem['generalfeedback'] = htmlspecialchars_decode($item->nodeValue);
break;
case 'qtype':
$questionType = $item->nodeValue;
$currentItem['qtype'] = $questionType;
break;
case 'plugin_qtype_'.$questionType.'_question':
$currentItem['plugin_qtype_'.$questionType.'_question'] = $this->processAnswersV4($item);
break;
}
}
return !empty($currentItem['name']) ? $currentItem : [];
}
/**
* Processes the answers for a given quiz question in Moodle version 4.
*
* @param DOMElement $item The DOM element containing answer data.
*
* @return array Returns an array of processed answers, each containing details like answer text and fraction.
*/
protected function processAnswersV4($item)
{
$answersList = [];
$answers = $item->getElementsByTagName('answer');
foreach ($answers as $i => $answer) {
$answerData = [
'answerid' => $answer->getAttribute('id'),
'answertext' => '',
'fraction' => '0.0000000',
];
foreach ($answer->childNodes as $properties) {
switch ($properties->nodeName) {
case 'answertext':
$answerData['answertext'] = htmlspecialchars_decode($properties->nodeValue);
break;
case 'fraction':
$answerData['fraction'] = $properties->nodeValue;
break;
case 'feedback':
$answerData['feedback'] = htmlspecialchars_decode($properties->nodeValue);
break;
}
}
$answersList[$i] = $answerData;
}
return $answersList;
}
/**
* Check if folder is empty or not.
*

@ -3087,11 +3087,10 @@ HTML;
/**
* Get the latest view (later than given date) in any LP in this course/session
* as datetime format, or null
* @param int $courseId
* @param int $userId
* @param int $sessionId
* as datetime format, or null.
*
* @param int $latestTimestamp The latest time for the tool in general, as obtained through track_e_access
*
* @return string|null The latest view if later than $latestTimestamp, or null otherwise
*/
public static function getLatestLpView(int $courseId, int $userId, int $sessionId, int $latestTimestamp): ?string

@ -7070,6 +7070,66 @@ class DocumentManager
return $canBeDownloadedIcon;
}
/**
* Retrieves all documents in a course by their parent folder ID.
*
* @param array $courseInfo Information about the course.
* @param int $parentId The ID of the parent folder.
* @param int $toGroupId (Optional) The ID of the group to filter by. Default is 0.
* @param int|null $toUserId (Optional) The ID of the user to filter by. Default is null.
* @param bool $canSeeInvisible (Optional) Whether to include invisible documents. Default is false.
* @param bool $search (Optional) Whether to perform a search or fetch all documents. Default is true.
* @param int $sessionId (Optional) The session ID to filter by. Default is 0.
*
* @return array List of documents that match the criteria.
*/
public static function getAllDocumentsByParentId(
$courseInfo,
$parentId,
$toGroupId = 0,
$toUserId = null,
$canSeeInvisible = false,
$search = true,
$sessionId = 0
) {
if (empty($courseInfo)) {
return [];
}
$tblDocument = Database::get_course_table(TABLE_DOCUMENT);
$parentId = (int) $parentId;
$sql = "SELECT path, filetype
FROM $tblDocument
WHERE id = $parentId
AND c_id = {$courseInfo['real_id']}";
$result = Database::query($sql);
if ($result === false || Database::num_rows($result) == 0) {
return [];
}
$parentRow = Database::fetch_array($result, 'ASSOC');
$parentPath = $parentRow['path'];
$filetype = $parentRow['filetype'];
if ($filetype !== 'folder') {
return [];
}
return self::getAllDocumentData(
$courseInfo,
$parentPath,
$toGroupId,
$toUserId,
$canSeeInvisible,
$search,
$sessionId
);
}
/**
* Parse file information into a link.
*
@ -7533,66 +7593,6 @@ class DocumentManager
return $btn;
}
/**
* Retrieves all documents in a course by their parent folder ID.
*
* @param array $courseInfo Information about the course.
* @param int $parentId The ID of the parent folder.
* @param int $toGroupId (Optional) The ID of the group to filter by. Default is 0.
* @param int|null $toUserId (Optional) The ID of the user to filter by. Default is null.
* @param bool $canSeeInvisible (Optional) Whether to include invisible documents. Default is false.
* @param bool $search (Optional) Whether to perform a search or fetch all documents. Default is true.
* @param int $sessionId (Optional) The session ID to filter by. Default is 0.
*
* @return array List of documents that match the criteria.
*/
public static function getAllDocumentsByParentId(
$courseInfo,
$parentId,
$toGroupId = 0,
$toUserId = null,
$canSeeInvisible = false,
$search = true,
$sessionId = 0
) {
if (empty($courseInfo)) {
return [];
}
$tblDocument = Database::get_course_table(TABLE_DOCUMENT);
$parentId = (int) $parentId;
$sql = "SELECT path, filetype
FROM $tblDocument
WHERE id = $parentId
AND c_id = {$courseInfo['real_id']}";
$result = Database::query($sql);
if ($result === false || Database::num_rows($result) == 0) {
return [];
}
$parentRow = Database::fetch_array($result, 'ASSOC');
$parentPath = $parentRow['path'];
$filetype = $parentRow['filetype'];
if ($filetype !== 'folder') {
return [];
}
return self::getAllDocumentData(
$courseInfo,
$parentPath,
$toGroupId,
$toUserId,
$canSeeInvisible,
$search,
$sessionId
);
}
/**
* Include MathJax script in document.
*

@ -2605,7 +2605,7 @@ HOTSPOT;
if (empty($courseInfo)) {
return [];
}
} elseif (false === api_is_platform_admin(true,false)) {
} elseif (false === api_is_platform_admin(true, false)) {
$courses = CourseManager::get_courses_list_by_user_id(api_get_user_id(), $showAttemptsInSessions, false, false);
if (empty($courses)) {

@ -2104,9 +2104,11 @@ function plain_url_filter($html, $mode = NO_HTML)
* Prevent execution of event handlers in HTML elements.
*
* @param string $html
*
* @return string
*/
function attr_on_filter($html) {
function attr_on_filter($html)
{
$prefix = uniqid('data-cke-').'-';
return preg_replace('/(\s)(on)/i', '$1'.$prefix.'$2', $html);

@ -3052,9 +3052,9 @@ class MessageManager
/**
* Retrieves a list of users with whom the specified user has exchanged messages within an optional date range.
*
* @param int $userId The user ID for whom to retrieve message exchange.
* @param string|null $startDate Start date to filter the messages (optional).
* @param string|null $endDate End date to filter the messages (optional).
* @param int $userId The user ID for whom to retrieve message exchange.
* @param string|null $startDate Start date to filter the messages (optional).
* @param string|null $endDate End date to filter the messages (optional).
*
* @return array Array of user information for each user with whom the specified user has exchanged messages.
*/
@ -3072,14 +3072,14 @@ class MessageManager
$sql = "SELECT DISTINCT user_sender_id AS user_id
FROM $messagesTable
WHERE user_receiver_id = $userId" .
($startDate ? " AND send_date >= '$startDate'" : "") .
($endDate ? " AND send_date <= '$endDate'" : "") .
WHERE user_receiver_id = $userId".
($startDate ? " AND send_date >= '$startDate'" : "").
($endDate ? " AND send_date <= '$endDate'" : "").
" UNION
SELECT DISTINCT user_receiver_id
FROM $messagesTable
WHERE user_sender_id = $userId" .
($startDate ? " AND send_date >= '$startDate'" : "") .
WHERE user_sender_id = $userId".
($startDate ? " AND send_date >= '$startDate'" : "").
($endDate ? " AND send_date <= '$endDate'" : "");
$result = Database::query($sql);

@ -26,18 +26,6 @@ abstract class ActivityExport
*/
abstract public function export($activityId, $exportDir, $moduleId, $sectionId);
/**
* Prepares the directory for the activity.
*/
protected function prepareActivityDirectory(string $exportDir, string $activityType, int $moduleId): string
{
$activityDir = "{$exportDir}/activities/{$activityType}_{$moduleId}";
if (!is_dir($activityDir)) {
mkdir($activityDir, 0777, true);
}
return $activityDir;
}
/**
* Get the section ID for a given activity ID.
*/
@ -54,12 +42,25 @@ abstract class ActivityExport
return 0;
}
/**
* Prepares the directory for the activity.
*/
protected function prepareActivityDirectory(string $exportDir, string $activityType, int $moduleId): string
{
$activityDir = "{$exportDir}/activities/{$activityType}_{$moduleId}";
if (!is_dir($activityDir)) {
mkdir($activityDir, 0777, true);
}
return $activityDir;
}
/**
* Creates a generic XML file.
*/
protected function createXmlFile(string $fileName, string $xmlContent, string $directory): void
{
$filePath = $directory . '/' . $fileName . '.xml';
$filePath = $directory.'/'.$fileName.'.xml';
if (file_put_contents($filePath, $xmlContent) === false) {
throw new Exception("Error creating {$fileName}.xml");
}
@ -70,28 +71,28 @@ abstract class ActivityExport
*/
protected function createModuleXml(array $data, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<module id="' . $data['moduleid'] . '" version="2021051700">' . PHP_EOL;
$xmlContent .= ' <modulename>' .$data['modulename']. '</modulename>' . PHP_EOL;
$xmlContent .= ' <sectionid>' . $data['sectionid'] . '</sectionid>' . PHP_EOL;
$xmlContent .= ' <sectionnumber>' . $data['sectionnumber'] . '</sectionnumber>' . PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>' . PHP_EOL;
$xmlContent .= ' <added>' . time() . '</added>' . PHP_EOL;
$xmlContent .= ' <score>0</score>' . PHP_EOL;
$xmlContent .= ' <indent>0</indent>' . PHP_EOL;
$xmlContent .= ' <visible>1</visible>' . PHP_EOL;
$xmlContent .= ' <visibleoncoursepage>1</visibleoncoursepage>' . PHP_EOL;
$xmlContent .= ' <visibleold>1</visibleold>' . PHP_EOL;
$xmlContent .= ' <groupmode>0</groupmode>' . PHP_EOL;
$xmlContent .= ' <groupingid>0</groupingid>' . PHP_EOL;
$xmlContent .= ' <completion>1</completion>' . PHP_EOL;
$xmlContent .= ' <completiongradeitemnumber>$@NULL@$</completiongradeitemnumber>' . PHP_EOL;
$xmlContent .= ' <completionview>0</completionview>' . PHP_EOL;
$xmlContent .= ' <completionexpected>0</completionexpected>' . PHP_EOL;
$xmlContent .= ' <availability>$@NULL@$</availability>' . PHP_EOL;
$xmlContent .= ' <showdescription>0</showdescription>' . PHP_EOL;
$xmlContent .= ' <tags></tags>' . PHP_EOL;
$xmlContent .= '</module>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<module id="'.$data['moduleid'].'" version="2021051700">'.PHP_EOL;
$xmlContent .= ' <modulename>'.$data['modulename'].'</modulename>'.PHP_EOL;
$xmlContent .= ' <sectionid>'.$data['sectionid'].'</sectionid>'.PHP_EOL;
$xmlContent .= ' <sectionnumber>'.$data['sectionnumber'].'</sectionnumber>'.PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>'.PHP_EOL;
$xmlContent .= ' <added>'.time().'</added>'.PHP_EOL;
$xmlContent .= ' <score>0</score>'.PHP_EOL;
$xmlContent .= ' <indent>0</indent>'.PHP_EOL;
$xmlContent .= ' <visible>1</visible>'.PHP_EOL;
$xmlContent .= ' <visibleoncoursepage>1</visibleoncoursepage>'.PHP_EOL;
$xmlContent .= ' <visibleold>1</visibleold>'.PHP_EOL;
$xmlContent .= ' <groupmode>0</groupmode>'.PHP_EOL;
$xmlContent .= ' <groupingid>0</groupingid>'.PHP_EOL;
$xmlContent .= ' <completion>1</completion>'.PHP_EOL;
$xmlContent .= ' <completiongradeitemnumber>$@NULL@$</completiongradeitemnumber>'.PHP_EOL;
$xmlContent .= ' <completionview>0</completionview>'.PHP_EOL;
$xmlContent .= ' <completionexpected>0</completionexpected>'.PHP_EOL;
$xmlContent .= ' <availability>$@NULL@$</availability>'.PHP_EOL;
$xmlContent .= ' <showdescription>0</showdescription>'.PHP_EOL;
$xmlContent .= ' <tags></tags>'.PHP_EOL;
$xmlContent .= '</module>'.PHP_EOL;
$this->createXmlFile('module', $xmlContent, $directory);
}
@ -101,10 +102,10 @@ abstract class ActivityExport
*/
protected function createGradesXml(array $data, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity_gradebook>' . PHP_EOL;
$xmlContent .= ' <grade_items></grade_items>' . PHP_EOL;
$xmlContent .= '</activity_gradebook>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity_gradebook>'.PHP_EOL;
$xmlContent .= ' <grade_items></grade_items>'.PHP_EOL;
$xmlContent .= '</activity_gradebook>'.PHP_EOL;
$this->createXmlFile('grades', $xmlContent, $directory);
}
@ -115,32 +116,32 @@ abstract class ActivityExport
protected function createInforefXml(array $references, string $directory): void
{
// Start the XML content
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<inforef>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<inforef>'.PHP_EOL;
// Add user references if provided
if (isset($references['users']) && is_array($references['users'])) {
$xmlContent .= ' <userref>' . PHP_EOL;
$xmlContent .= ' <userref>'.PHP_EOL;
foreach ($references['users'] as $userId) {
$xmlContent .= ' <user>' . PHP_EOL;
$xmlContent .= ' <id>' . htmlspecialchars($userId) . '</id>' . PHP_EOL;
$xmlContent .= ' </user>' . PHP_EOL;
$xmlContent .= ' <user>'.PHP_EOL;
$xmlContent .= ' <id>'.htmlspecialchars($userId).'</id>'.PHP_EOL;
$xmlContent .= ' </user>'.PHP_EOL;
}
$xmlContent .= ' </userref>' . PHP_EOL;
$xmlContent .= ' </userref>'.PHP_EOL;
}
// Add file references if provided
if (isset($references['files']) && is_array($references['files'])) {
$xmlContent .= ' <fileref>' . PHP_EOL;
$xmlContent .= ' <fileref>'.PHP_EOL;
foreach ($references['files'] as $file) {
$xmlContent .= ' <file>' . PHP_EOL;
$xmlContent .= ' <id>' . htmlspecialchars($file['id']) . '</id>' . PHP_EOL;
$xmlContent .= ' </file>' . PHP_EOL;
$xmlContent .= ' <file>'.PHP_EOL;
$xmlContent .= ' <id>'.htmlspecialchars($file['id']).'</id>'.PHP_EOL;
$xmlContent .= ' </file>'.PHP_EOL;
}
$xmlContent .= ' </fileref>' . PHP_EOL;
$xmlContent .= ' </fileref>'.PHP_EOL;
}
$xmlContent .= '</inforef>' . PHP_EOL;
$xmlContent .= '</inforef>'.PHP_EOL;
$this->createXmlFile('inforef', $xmlContent, $directory);
}
@ -150,8 +151,8 @@ abstract class ActivityExport
*/
protected function createRolesXml(array $activityData, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<roles></roles>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<roles></roles>'.PHP_EOL;
$this->createXmlFile('roles', $xmlContent, $directory);
}
@ -161,13 +162,13 @@ abstract class ActivityExport
*/
protected function createFiltersXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<filters>' . PHP_EOL;
$xmlContent .= ' <filter_actives>' . PHP_EOL;
$xmlContent .= ' </filter_actives>' . PHP_EOL;
$xmlContent .= ' <filter_configs>' . PHP_EOL;
$xmlContent .= ' </filter_configs>' . PHP_EOL;
$xmlContent .= '</filters>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<filters>'.PHP_EOL;
$xmlContent .= ' <filter_actives>'.PHP_EOL;
$xmlContent .= ' </filter_actives>'.PHP_EOL;
$xmlContent .= ' <filter_configs>'.PHP_EOL;
$xmlContent .= ' </filter_configs>'.PHP_EOL;
$xmlContent .= '</filters>'.PHP_EOL;
$this->createXmlFile('filters', $xmlContent, $destinationDir);
}
@ -177,11 +178,11 @@ abstract class ActivityExport
*/
protected function createGradeHistoryXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<grade_history>' . PHP_EOL;
$xmlContent .= ' <grade_grades>' . PHP_EOL;
$xmlContent .= ' </grade_grades>' . PHP_EOL;
$xmlContent .= '</grade_history>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<grade_history>'.PHP_EOL;
$xmlContent .= ' <grade_grades>'.PHP_EOL;
$xmlContent .= ' </grade_grades>'.PHP_EOL;
$xmlContent .= '</grade_history>'.PHP_EOL;
$this->createXmlFile('grade_history', $xmlContent, $destinationDir);
}
@ -191,15 +192,15 @@ abstract class ActivityExport
*/
protected function createCompletionXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<completion>' . PHP_EOL;
$xmlContent .= ' <completiondata>' . PHP_EOL;
$xmlContent .= ' <completion>' . PHP_EOL;
$xmlContent .= ' <timecompleted>0</timecompleted>' . PHP_EOL;
$xmlContent .= ' <completionstate>1</completionstate>' . PHP_EOL;
$xmlContent .= ' </completion>' . PHP_EOL;
$xmlContent .= ' </completiondata>' . PHP_EOL;
$xmlContent .= '</completion>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<completion>'.PHP_EOL;
$xmlContent .= ' <completiondata>'.PHP_EOL;
$xmlContent .= ' <completion>'.PHP_EOL;
$xmlContent .= ' <timecompleted>0</timecompleted>'.PHP_EOL;
$xmlContent .= ' <completionstate>1</completionstate>'.PHP_EOL;
$xmlContent .= ' </completion>'.PHP_EOL;
$xmlContent .= ' </completiondata>'.PHP_EOL;
$xmlContent .= '</completion>'.PHP_EOL;
$this->createXmlFile('completion', $xmlContent, $destinationDir);
}
@ -209,13 +210,13 @@ abstract class ActivityExport
*/
protected function createCommentsXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<comments>' . PHP_EOL;
$xmlContent .= ' <comment>' . PHP_EOL;
$xmlContent .= ' <content>This is a sample comment</content>' . PHP_EOL;
$xmlContent .= ' <author>Professor</author>' . PHP_EOL;
$xmlContent .= ' </comment>' . PHP_EOL;
$xmlContent .= '</comments>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<comments>'.PHP_EOL;
$xmlContent .= ' <comment>'.PHP_EOL;
$xmlContent .= ' <content>This is a sample comment</content>'.PHP_EOL;
$xmlContent .= ' <author>Professor</author>'.PHP_EOL;
$xmlContent .= ' </comment>'.PHP_EOL;
$xmlContent .= '</comments>'.PHP_EOL;
$this->createXmlFile('comments', $xmlContent, $destinationDir);
}
@ -225,12 +226,12 @@ abstract class ActivityExport
*/
protected function createCompetenciesXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<competencies>' . PHP_EOL;
$xmlContent .= ' <competency>' . PHP_EOL;
$xmlContent .= ' <name>Sample Competency</name>' . PHP_EOL;
$xmlContent .= ' </competency>' . PHP_EOL;
$xmlContent .= '</competencies>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<competencies>'.PHP_EOL;
$xmlContent .= ' <competency>'.PHP_EOL;
$xmlContent .= ' <name>Sample Competency</name>'.PHP_EOL;
$xmlContent .= ' </competency>'.PHP_EOL;
$xmlContent .= '</competencies>'.PHP_EOL;
$this->createXmlFile('competencies', $xmlContent, $destinationDir);
}
@ -240,13 +241,13 @@ abstract class ActivityExport
*/
protected function createCalendarXml(array $activityData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<calendar>' . PHP_EOL;
$xmlContent .= ' <event>' . PHP_EOL;
$xmlContent .= ' <name>Due Date</name>' . PHP_EOL;
$xmlContent .= ' <timestart>' . time() . '</timestart>' . PHP_EOL;
$xmlContent .= ' </event>' . PHP_EOL;
$xmlContent .= '</calendar>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<calendar>'.PHP_EOL;
$xmlContent .= ' <event>'.PHP_EOL;
$xmlContent .= ' <name>Due Date</name>'.PHP_EOL;
$xmlContent .= ' <timestart>'.time().'</timestart>'.PHP_EOL;
$xmlContent .= ' </event>'.PHP_EOL;
$xmlContent .= '</calendar>'.PHP_EOL;
$this->createXmlFile('calendar', $xmlContent, $destinationDir);
}

@ -16,10 +16,10 @@ class AssignExport extends ActivityExport
/**
* Export all assign data into a single Moodle assign activity.
*
* @param int $activityId The ID of the assign.
* @param string $exportDir The directory where the assign will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the assign.
* @param string $exportDir The directory where the assign will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -42,114 +42,6 @@ class AssignExport extends ActivityExport
$this->createFiltersXml($assignData, $assignDir);
}
/**
* Create the XML file for the assign activity.
*/
private function createAssignXml(array $assignData, string $assignDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $assignData['id'] . '" moduleid="' . $assignData['moduleid'] . '" modulename="assign" contextid="' . $assignData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <assign id="' . $assignData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($assignData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro><![CDATA[' . $assignData['intro'] . ']]></intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <alwaysshowdescription>1</alwaysshowdescription>' . PHP_EOL;
$xmlContent .= ' <submissiondrafts>0</submissiondrafts>' . PHP_EOL;
$xmlContent .= ' <sendnotifications>0</sendnotifications>' . PHP_EOL;
$xmlContent .= ' <sendlatenotifications>0</sendlatenotifications>' . PHP_EOL;
$xmlContent .= ' <sendstudentnotifications>1</sendstudentnotifications>' . PHP_EOL;
$xmlContent .= ' <duedate>' . $assignData['duedate'] . '</duedate>' . PHP_EOL;
$xmlContent .= ' <cutoffdate>0</cutoffdate>' . PHP_EOL;
$xmlContent .= ' <gradingduedate>' . $assignData['gradingduedate'] . '</gradingduedate>' . PHP_EOL;
$xmlContent .= ' <allowsubmissionsfromdate>' . $assignData['allowsubmissionsfromdate'] . '</allowsubmissionsfromdate>' . PHP_EOL;
$xmlContent .= ' <grade>100</grade>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $assignData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <completionsubmit>1</completionsubmit>' . PHP_EOL;
$xmlContent .= ' <requiresubmissionstatement>0</requiresubmissionstatement>' . PHP_EOL;
$xmlContent .= ' <teamsubmission>0</teamsubmission>' . PHP_EOL;
$xmlContent .= ' <requireallteammemberssubmit>0</requireallteammemberssubmit>' . PHP_EOL;
$xmlContent .= ' <teamsubmissiongroupingid>0</teamsubmissiongroupingid>' . PHP_EOL;
$xmlContent .= ' <blindmarking>0</blindmarking>' . PHP_EOL;
$xmlContent .= ' <hidegrader>0</hidegrader>' . PHP_EOL;
$xmlContent .= ' <revealidentities>0</revealidentities>' . PHP_EOL;
$xmlContent .= ' <attemptreopenmethod>none</attemptreopenmethod>' . PHP_EOL;
$xmlContent .= ' <maxattempts>1</maxattempts>' . PHP_EOL;
$xmlContent .= ' <markingworkflow>0</markingworkflow>' . PHP_EOL;
$xmlContent .= ' <markingallocation>0</markingallocation>' . PHP_EOL;
$xmlContent .= ' <preventsubmissionnotingroup>0</preventsubmissionnotingroup>' . PHP_EOL;
$xmlContent .= ' <userflags></userflags>' . PHP_EOL;
$xmlContent .= ' <submissions></submissions>' . PHP_EOL;
$xmlContent .= ' <grades></grades>' . PHP_EOL;
$xmlContent .= ' </assign>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('assign', $xmlContent, $assignDir);
}
/**
* Create the grades.xml file for the assign activity.
*/
protected function createGradesXml(array $data, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity_gradebook>' . PHP_EOL;
$xmlContent .= ' <grade_items>' . PHP_EOL;
$xmlContent .= ' <grade_item id="' . $data['grade_item_id'] . '">' . PHP_EOL;
$xmlContent .= ' <categoryid>1</categoryid>' . PHP_EOL;
$xmlContent .= ' <itemname>' . htmlspecialchars($data['name']) . '</itemname>' . PHP_EOL;
$xmlContent .= ' <itemtype>mod</itemtype>' . PHP_EOL;
$xmlContent .= ' <itemmodule>'.$data['modulename'].'</itemmodule>' . PHP_EOL;
$xmlContent .= ' <iteminstance>' . $data['id'] . '</iteminstance>' . PHP_EOL;
$xmlContent .= ' <itemnumber>0</itemnumber>' . PHP_EOL;
$xmlContent .= ' <iteminfo>$@NULL@$</iteminfo>' . PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>' . PHP_EOL;
$xmlContent .= ' <calculation>$@NULL@$</calculation>' . PHP_EOL;
$xmlContent .= ' <gradetype>1</gradetype>' . PHP_EOL;
$xmlContent .= ' <grademax>100.00000</grademax>' . PHP_EOL;
$xmlContent .= ' <grademin>0.00000</grademin>' . PHP_EOL;
$xmlContent .= ' <scaleid>$@NULL@$</scaleid>' . PHP_EOL;
$xmlContent .= ' <outcomeid>$@NULL@$</outcomeid>' . PHP_EOL;
$xmlContent .= ' <gradepass>0.00000</gradepass>' . PHP_EOL;
$xmlContent .= ' <multfactor>1.00000</multfactor>' . PHP_EOL;
$xmlContent .= ' <plusfactor>0.00000</plusfactor>' . PHP_EOL;
$xmlContent .= ' <aggregationcoef>0.00000</aggregationcoef>' . PHP_EOL;
$xmlContent .= ' <aggregationcoef2>0.23810</aggregationcoef2>' . PHP_EOL;
$xmlContent .= ' <weightoverride>0</weightoverride>' . PHP_EOL;
$xmlContent .= ' <sortorder>5</sortorder>' . PHP_EOL;
$xmlContent .= ' <display>0</display>' . PHP_EOL;
$xmlContent .= ' <decimals>$@NULL@$</decimals>' . PHP_EOL;
$xmlContent .= ' <hidden>0</hidden>' . PHP_EOL;
$xmlContent .= ' <locked>0</locked>' . PHP_EOL;
$xmlContent .= ' <locktime>0</locktime>' . PHP_EOL;
$xmlContent .= ' <needsupdate>0</needsupdate>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . $data['timemodified'] . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $data['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <grade_grades></grade_grades>' . PHP_EOL;
$xmlContent .= ' </grade_item>' . PHP_EOL;
$xmlContent .= ' </grade_items>' . PHP_EOL;
$xmlContent .= ' <grade_letters></grade_letters>' . PHP_EOL;
$xmlContent .= '</activity_gradebook>';
$this->createXmlFile('grades', $xmlContent, $directory);
}
/**
* Create the grading.xml file for the assign activity.
*/
private function createGradingXml(array $data, string $assignDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<areas>' . PHP_EOL;
$xmlContent .= ' <area id="'.$data['area_id'].'">' . PHP_EOL;
$xmlContent .= ' <areaname>submissions</areaname>' . PHP_EOL;
$xmlContent .= ' <activemethod>$@NULL@$</activemethod>' . PHP_EOL;
$xmlContent .= ' <definitions></definitions>' . PHP_EOL;
$xmlContent .= ' </area>' . PHP_EOL;
$xmlContent .= '</areas>';
$this->createXmlFile('grading', $xmlContent, $assignDir);
}
/**
* Get all the data related to the assign activity.
*/
@ -190,7 +82,115 @@ class AssignExport extends ActivityExport
'grade_item_id' => 0,
'files' => $files,
'users' => [$adminId],
'area_id' => 0
'area_id' => 0,
];
}
/**
* Create the grades.xml file for the assign activity.
*/
protected function createGradesXml(array $data, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity_gradebook>'.PHP_EOL;
$xmlContent .= ' <grade_items>'.PHP_EOL;
$xmlContent .= ' <grade_item id="'.$data['grade_item_id'].'">'.PHP_EOL;
$xmlContent .= ' <categoryid>1</categoryid>'.PHP_EOL;
$xmlContent .= ' <itemname>'.htmlspecialchars($data['name']).'</itemname>'.PHP_EOL;
$xmlContent .= ' <itemtype>mod</itemtype>'.PHP_EOL;
$xmlContent .= ' <itemmodule>'.$data['modulename'].'</itemmodule>'.PHP_EOL;
$xmlContent .= ' <iteminstance>'.$data['id'].'</iteminstance>'.PHP_EOL;
$xmlContent .= ' <itemnumber>0</itemnumber>'.PHP_EOL;
$xmlContent .= ' <iteminfo>$@NULL@$</iteminfo>'.PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>'.PHP_EOL;
$xmlContent .= ' <calculation>$@NULL@$</calculation>'.PHP_EOL;
$xmlContent .= ' <gradetype>1</gradetype>'.PHP_EOL;
$xmlContent .= ' <grademax>100.00000</grademax>'.PHP_EOL;
$xmlContent .= ' <grademin>0.00000</grademin>'.PHP_EOL;
$xmlContent .= ' <scaleid>$@NULL@$</scaleid>'.PHP_EOL;
$xmlContent .= ' <outcomeid>$@NULL@$</outcomeid>'.PHP_EOL;
$xmlContent .= ' <gradepass>0.00000</gradepass>'.PHP_EOL;
$xmlContent .= ' <multfactor>1.00000</multfactor>'.PHP_EOL;
$xmlContent .= ' <plusfactor>0.00000</plusfactor>'.PHP_EOL;
$xmlContent .= ' <aggregationcoef>0.00000</aggregationcoef>'.PHP_EOL;
$xmlContent .= ' <aggregationcoef2>0.23810</aggregationcoef2>'.PHP_EOL;
$xmlContent .= ' <weightoverride>0</weightoverride>'.PHP_EOL;
$xmlContent .= ' <sortorder>5</sortorder>'.PHP_EOL;
$xmlContent .= ' <display>0</display>'.PHP_EOL;
$xmlContent .= ' <decimals>$@NULL@$</decimals>'.PHP_EOL;
$xmlContent .= ' <hidden>0</hidden>'.PHP_EOL;
$xmlContent .= ' <locked>0</locked>'.PHP_EOL;
$xmlContent .= ' <locktime>0</locktime>'.PHP_EOL;
$xmlContent .= ' <needsupdate>0</needsupdate>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.$data['timemodified'].'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$data['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <grade_grades></grade_grades>'.PHP_EOL;
$xmlContent .= ' </grade_item>'.PHP_EOL;
$xmlContent .= ' </grade_items>'.PHP_EOL;
$xmlContent .= ' <grade_letters></grade_letters>'.PHP_EOL;
$xmlContent .= '</activity_gradebook>';
$this->createXmlFile('grades', $xmlContent, $directory);
}
/**
* Create the XML file for the assign activity.
*/
private function createAssignXml(array $assignData, string $assignDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$assignData['id'].'" moduleid="'.$assignData['moduleid'].'" modulename="assign" contextid="'.$assignData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <assign id="'.$assignData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($assignData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro><![CDATA['.$assignData['intro'].']]></intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <alwaysshowdescription>1</alwaysshowdescription>'.PHP_EOL;
$xmlContent .= ' <submissiondrafts>0</submissiondrafts>'.PHP_EOL;
$xmlContent .= ' <sendnotifications>0</sendnotifications>'.PHP_EOL;
$xmlContent .= ' <sendlatenotifications>0</sendlatenotifications>'.PHP_EOL;
$xmlContent .= ' <sendstudentnotifications>1</sendstudentnotifications>'.PHP_EOL;
$xmlContent .= ' <duedate>'.$assignData['duedate'].'</duedate>'.PHP_EOL;
$xmlContent .= ' <cutoffdate>0</cutoffdate>'.PHP_EOL;
$xmlContent .= ' <gradingduedate>'.$assignData['gradingduedate'].'</gradingduedate>'.PHP_EOL;
$xmlContent .= ' <allowsubmissionsfromdate>'.$assignData['allowsubmissionsfromdate'].'</allowsubmissionsfromdate>'.PHP_EOL;
$xmlContent .= ' <grade>100</grade>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$assignData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <completionsubmit>1</completionsubmit>'.PHP_EOL;
$xmlContent .= ' <requiresubmissionstatement>0</requiresubmissionstatement>'.PHP_EOL;
$xmlContent .= ' <teamsubmission>0</teamsubmission>'.PHP_EOL;
$xmlContent .= ' <requireallteammemberssubmit>0</requireallteammemberssubmit>'.PHP_EOL;
$xmlContent .= ' <teamsubmissiongroupingid>0</teamsubmissiongroupingid>'.PHP_EOL;
$xmlContent .= ' <blindmarking>0</blindmarking>'.PHP_EOL;
$xmlContent .= ' <hidegrader>0</hidegrader>'.PHP_EOL;
$xmlContent .= ' <revealidentities>0</revealidentities>'.PHP_EOL;
$xmlContent .= ' <attemptreopenmethod>none</attemptreopenmethod>'.PHP_EOL;
$xmlContent .= ' <maxattempts>1</maxattempts>'.PHP_EOL;
$xmlContent .= ' <markingworkflow>0</markingworkflow>'.PHP_EOL;
$xmlContent .= ' <markingallocation>0</markingallocation>'.PHP_EOL;
$xmlContent .= ' <preventsubmissionnotingroup>0</preventsubmissionnotingroup>'.PHP_EOL;
$xmlContent .= ' <userflags></userflags>'.PHP_EOL;
$xmlContent .= ' <submissions></submissions>'.PHP_EOL;
$xmlContent .= ' <grades></grades>'.PHP_EOL;
$xmlContent .= ' </assign>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('assign', $xmlContent, $assignDir);
}
/**
* Create the grading.xml file for the assign activity.
*/
private function createGradingXml(array $data, string $assignDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<areas>'.PHP_EOL;
$xmlContent .= ' <area id="'.$data['area_id'].'">'.PHP_EOL;
$xmlContent .= ' <areaname>submissions</areaname>'.PHP_EOL;
$xmlContent .= ' <activemethod>$@NULL@$</activemethod>'.PHP_EOL;
$xmlContent .= ' <definitions></definitions>'.PHP_EOL;
$xmlContent .= ' </area>'.PHP_EOL;
$xmlContent .= '</areas>';
$this->createXmlFile('grading', $xmlContent, $assignDir);
}
}

@ -33,7 +33,7 @@ class CourseExport
*/
public function exportCourse(string $exportDir): void
{
$courseDir = $exportDir . '/course';
$courseDir = $exportDir.'/course';
if (!is_dir($courseDir)) {
mkdir($courseDir, api_get_permissions_for_new_directories(), true);
}
@ -65,60 +65,60 @@ class CourseExport
$visible = $this->courseInfo['visible'] ?? 1;
$enablecompletion = $this->courseInfo['enablecompletion'] ?? 0;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<course id="' . $courseId . '" contextid="' . $contextId . '">' . PHP_EOL;
$xmlContent .= ' <shortname>' . htmlspecialchars($shortname) . '</shortname>' . PHP_EOL;
$xmlContent .= ' <fullname>' . htmlspecialchars($fullname) . '</fullname>' . PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>' . PHP_EOL;
$xmlContent .= ' <summary></summary>' . PHP_EOL;
$xmlContent .= ' <summaryformat>1</summaryformat>' . PHP_EOL;
$xmlContent .= ' <format>topics</format>' . PHP_EOL;
$xmlContent .= ' <showgrades>' . $showgrades . '</showgrades>' . PHP_EOL;
$xmlContent .= ' <newsitems>5</newsitems>' . PHP_EOL;
$xmlContent .= ' <startdate>' . $startdate . '</startdate>' . PHP_EOL;
$xmlContent .= ' <enddate>' . $enddate . '</enddate>' . PHP_EOL;
$xmlContent .= ' <marker>0</marker>' . PHP_EOL;
$xmlContent .= ' <maxbytes>0</maxbytes>' . PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>' . PHP_EOL;
$xmlContent .= ' <showreports>0</showreports>' . PHP_EOL;
$xmlContent .= ' <visible>' . $visible . '</visible>' . PHP_EOL;
$xmlContent .= ' <groupmode>0</groupmode>' . PHP_EOL;
$xmlContent .= ' <groupmodeforce>0</groupmodeforce>' . PHP_EOL;
$xmlContent .= ' <defaultgroupingid>0</defaultgroupingid>' . PHP_EOL;
$xmlContent .= ' <lang></lang>' . PHP_EOL;
$xmlContent .= ' <theme></theme>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . time() . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . time() . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <requested>0</requested>' . PHP_EOL;
$xmlContent .= ' <showactivitydates>1</showactivitydates>' . PHP_EOL;
$xmlContent .= ' <showcompletionconditions>1</showcompletionconditions>' . PHP_EOL;
$xmlContent .= ' <enablecompletion>' . $enablecompletion . '</enablecompletion>' . PHP_EOL;
$xmlContent .= ' <completionnotify>0</completionnotify>' . PHP_EOL;
$xmlContent .= ' <category id="1">' . PHP_EOL;
$xmlContent .= ' <name>Miscellaneous</name>' . PHP_EOL;
$xmlContent .= ' <description>$@NULL@$</description>' . PHP_EOL;
$xmlContent .= ' </category>' . PHP_EOL;
$xmlContent .= ' <tags>' . PHP_EOL;
$xmlContent .= ' </tags>' . PHP_EOL;
$xmlContent .= ' <customfields>' . PHP_EOL;
$xmlContent .= ' </customfields>' . PHP_EOL;
$xmlContent .= ' <courseformatoptions>' . PHP_EOL;
$xmlContent .= ' <courseformatoption>' . PHP_EOL;
$xmlContent .= ' <format>topics</format>' . PHP_EOL;
$xmlContent .= ' <sectionid>0</sectionid>' . PHP_EOL;
$xmlContent .= ' <name>hiddensections</name>' . PHP_EOL;
$xmlContent .= ' <value>0</value>' . PHP_EOL;
$xmlContent .= ' </courseformatoption>' . PHP_EOL;
$xmlContent .= ' <courseformatoption>' . PHP_EOL;
$xmlContent .= ' <format>topics</format>' . PHP_EOL;
$xmlContent .= ' <sectionid>0</sectionid>' . PHP_EOL;
$xmlContent .= ' <name>coursedisplay</name>' . PHP_EOL;
$xmlContent .= ' <value>0</value>' . PHP_EOL;
$xmlContent .= ' </courseformatoption>' . PHP_EOL;
$xmlContent .= ' </courseformatoptions>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<course id="'.$courseId.'" contextid="'.$contextId.'">'.PHP_EOL;
$xmlContent .= ' <shortname>'.htmlspecialchars($shortname).'</shortname>'.PHP_EOL;
$xmlContent .= ' <fullname>'.htmlspecialchars($fullname).'</fullname>'.PHP_EOL;
$xmlContent .= ' <idnumber></idnumber>'.PHP_EOL;
$xmlContent .= ' <summary></summary>'.PHP_EOL;
$xmlContent .= ' <summaryformat>1</summaryformat>'.PHP_EOL;
$xmlContent .= ' <format>topics</format>'.PHP_EOL;
$xmlContent .= ' <showgrades>'.$showgrades.'</showgrades>'.PHP_EOL;
$xmlContent .= ' <newsitems>5</newsitems>'.PHP_EOL;
$xmlContent .= ' <startdate>'.$startdate.'</startdate>'.PHP_EOL;
$xmlContent .= ' <enddate>'.$enddate.'</enddate>'.PHP_EOL;
$xmlContent .= ' <marker>0</marker>'.PHP_EOL;
$xmlContent .= ' <maxbytes>0</maxbytes>'.PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>'.PHP_EOL;
$xmlContent .= ' <showreports>0</showreports>'.PHP_EOL;
$xmlContent .= ' <visible>'.$visible.'</visible>'.PHP_EOL;
$xmlContent .= ' <groupmode>0</groupmode>'.PHP_EOL;
$xmlContent .= ' <groupmodeforce>0</groupmodeforce>'.PHP_EOL;
$xmlContent .= ' <defaultgroupingid>0</defaultgroupingid>'.PHP_EOL;
$xmlContent .= ' <lang></lang>'.PHP_EOL;
$xmlContent .= ' <theme></theme>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.time().'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.time().'</timemodified>'.PHP_EOL;
$xmlContent .= ' <requested>0</requested>'.PHP_EOL;
$xmlContent .= ' <showactivitydates>1</showactivitydates>'.PHP_EOL;
$xmlContent .= ' <showcompletionconditions>1</showcompletionconditions>'.PHP_EOL;
$xmlContent .= ' <enablecompletion>'.$enablecompletion.'</enablecompletion>'.PHP_EOL;
$xmlContent .= ' <completionnotify>0</completionnotify>'.PHP_EOL;
$xmlContent .= ' <category id="1">'.PHP_EOL;
$xmlContent .= ' <name>Miscellaneous</name>'.PHP_EOL;
$xmlContent .= ' <description>$@NULL@$</description>'.PHP_EOL;
$xmlContent .= ' </category>'.PHP_EOL;
$xmlContent .= ' <tags>'.PHP_EOL;
$xmlContent .= ' </tags>'.PHP_EOL;
$xmlContent .= ' <customfields>'.PHP_EOL;
$xmlContent .= ' </customfields>'.PHP_EOL;
$xmlContent .= ' <courseformatoptions>'.PHP_EOL;
$xmlContent .= ' <courseformatoption>'.PHP_EOL;
$xmlContent .= ' <format>topics</format>'.PHP_EOL;
$xmlContent .= ' <sectionid>0</sectionid>'.PHP_EOL;
$xmlContent .= ' <name>hiddensections</name>'.PHP_EOL;
$xmlContent .= ' <value>0</value>'.PHP_EOL;
$xmlContent .= ' </courseformatoption>'.PHP_EOL;
$xmlContent .= ' <courseformatoption>'.PHP_EOL;
$xmlContent .= ' <format>topics</format>'.PHP_EOL;
$xmlContent .= ' <sectionid>0</sectionid>'.PHP_EOL;
$xmlContent .= ' <name>coursedisplay</name>'.PHP_EOL;
$xmlContent .= ' <value>0</value>'.PHP_EOL;
$xmlContent .= ' </courseformatoption>'.PHP_EOL;
$xmlContent .= ' </courseformatoptions>'.PHP_EOL;
$xmlContent .= '</course>';
file_put_contents($destinationDir . '/course.xml', $xmlContent);
file_put_contents($destinationDir.'/course.xml', $xmlContent);
}
/**
@ -126,21 +126,21 @@ class CourseExport
*/
private function createEnrolmentsXml(array $enrolmentsData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<enrolments>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<enrolments>'.PHP_EOL;
foreach ($enrolmentsData as $enrol) {
$id = $enrol['id'] ?? 0;
$type = $enrol['type'] ?? 'manual';
$status = $enrol['status'] ?? 1;
$xmlContent .= ' <enrol id="' . $id . '">' . PHP_EOL;
$xmlContent .= ' <enrol>' . htmlspecialchars($type) . '</enrol>' . PHP_EOL;
$xmlContent .= ' <status>' . $status . '</status>' . PHP_EOL;
$xmlContent .= ' </enrol>' . PHP_EOL;
$xmlContent .= ' <enrol id="'.$id.'">'.PHP_EOL;
$xmlContent .= ' <enrol>'.htmlspecialchars($type).'</enrol>'.PHP_EOL;
$xmlContent .= ' <status>'.$status.'</status>'.PHP_EOL;
$xmlContent .= ' </enrol>'.PHP_EOL;
}
$xmlContent .= '</enrolments>';
file_put_contents($destinationDir . '/enrolments.xml', $xmlContent);
file_put_contents($destinationDir.'/enrolments.xml', $xmlContent);
}
/**
@ -148,8 +148,8 @@ class CourseExport
*/
private function createInforefXml(string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<inforef>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<inforef>'.PHP_EOL;
$questionCategories = [];
foreach ($this->activities as $activity) {
@ -166,25 +166,25 @@ class CourseExport
}
if (!empty($questionCategories)) {
$xmlContent .= ' <question_categoryref>' . PHP_EOL;
$xmlContent .= ' <question_categoryref>'.PHP_EOL;
foreach ($questionCategories as $categoryId) {
$xmlContent .= ' <question_category>' . PHP_EOL;
$xmlContent .= ' <id>' . $categoryId . '</id>' . PHP_EOL;
$xmlContent .= ' </question_category>' . PHP_EOL;
$xmlContent .= ' <question_category>'.PHP_EOL;
$xmlContent .= ' <id>'.$categoryId.'</id>'.PHP_EOL;
$xmlContent .= ' </question_category>'.PHP_EOL;
}
$xmlContent .= ' </question_categoryref>' . PHP_EOL;
$xmlContent .= ' </question_categoryref>'.PHP_EOL;
}
// Add role references
$xmlContent .= ' <roleref>' . PHP_EOL;
$xmlContent .= ' <role>' . PHP_EOL;
$xmlContent .= ' <id>5</id>' . PHP_EOL;
$xmlContent .= ' </role>' . PHP_EOL;
$xmlContent .= ' </roleref>' . PHP_EOL;
$xmlContent .= ' <roleref>'.PHP_EOL;
$xmlContent .= ' <role>'.PHP_EOL;
$xmlContent .= ' <id>5</id>'.PHP_EOL;
$xmlContent .= ' </role>'.PHP_EOL;
$xmlContent .= ' </roleref>'.PHP_EOL;
$xmlContent .= '</inforef>' . PHP_EOL;
$xmlContent .= '</inforef>'.PHP_EOL;
file_put_contents($destinationDir . '/inforef.xml', $xmlContent);
file_put_contents($destinationDir.'/inforef.xml', $xmlContent);
}
/**
@ -192,17 +192,17 @@ class CourseExport
*/
private function createRolesXml(array $rolesData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<roles>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<roles>'.PHP_EOL;
foreach ($rolesData as $role) {
$roleName = $role['name'] ?? 'Student';
$xmlContent .= ' <role>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($roleName) . '</name>' . PHP_EOL;
$xmlContent .= ' </role>' . PHP_EOL;
$xmlContent .= ' <role>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($roleName).'</name>'.PHP_EOL;
$xmlContent .= ' </role>'.PHP_EOL;
}
$xmlContent .= '</roles>';
file_put_contents($destinationDir . '/roles.xml', $xmlContent);
file_put_contents($destinationDir.'/roles.xml', $xmlContent);
}
/**
@ -210,22 +210,22 @@ class CourseExport
*/
private function createCalendarXml(array $calendarData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<calendar>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<calendar>'.PHP_EOL;
foreach ($calendarData as $event) {
$eventName = $event['name'] ?? 'Event';
$timestart = $event['timestart'] ?? time();
$duration = $event['duration'] ?? 3600;
$xmlContent .= ' <event>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($eventName) . '</name>' . PHP_EOL;
$xmlContent .= ' <timestart>' . $timestart . '</timestart>' . PHP_EOL;
$xmlContent .= ' <duration>' . $duration . '</duration>' . PHP_EOL;
$xmlContent .= ' </event>' . PHP_EOL;
$xmlContent .= ' <event>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($eventName).'</name>'.PHP_EOL;
$xmlContent .= ' <timestart>'.$timestart.'</timestart>'.PHP_EOL;
$xmlContent .= ' <duration>'.$duration.'</duration>'.PHP_EOL;
$xmlContent .= ' </event>'.PHP_EOL;
}
$xmlContent .= '</calendar>';
file_put_contents($destinationDir . '/calendar.xml', $xmlContent);
file_put_contents($destinationDir.'/calendar.xml', $xmlContent);
}
/**
@ -233,20 +233,20 @@ class CourseExport
*/
private function createCommentsXml(array $commentsData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<comments>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<comments>'.PHP_EOL;
foreach ($commentsData as $comment) {
$content = $comment['content'] ?? 'No comment';
$author = $comment['author'] ?? 'Anonymous';
$xmlContent .= ' <comment>' . PHP_EOL;
$xmlContent .= ' <content>' . htmlspecialchars($content) . '</content>' . PHP_EOL;
$xmlContent .= ' <author>' . htmlspecialchars($author) . '</author>' . PHP_EOL;
$xmlContent .= ' </comment>' . PHP_EOL;
$xmlContent .= ' <comment>'.PHP_EOL;
$xmlContent .= ' <content>'.htmlspecialchars($content).'</content>'.PHP_EOL;
$xmlContent .= ' <author>'.htmlspecialchars($author).'</author>'.PHP_EOL;
$xmlContent .= ' </comment>'.PHP_EOL;
}
$xmlContent .= '</comments>';
file_put_contents($destinationDir . '/comments.xml', $xmlContent);
file_put_contents($destinationDir.'/comments.xml', $xmlContent);
}
/**
@ -254,17 +254,17 @@ class CourseExport
*/
private function createCompetenciesXml(array $competenciesData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<competencies>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<competencies>'.PHP_EOL;
foreach ($competenciesData as $competency) {
$name = $competency['name'] ?? 'Competency';
$xmlContent .= ' <competency>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($name) . '</name>' . PHP_EOL;
$xmlContent .= ' </competency>' . PHP_EOL;
$xmlContent .= ' <competency>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($name).'</name>'.PHP_EOL;
$xmlContent .= ' </competency>'.PHP_EOL;
}
$xmlContent .= '</competencies>';
file_put_contents($destinationDir . '/competencies.xml', $xmlContent);
file_put_contents($destinationDir.'/competencies.xml', $xmlContent);
}
/**
@ -272,17 +272,17 @@ class CourseExport
*/
private function createCompletionDefaultsXml(array $completionData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<completiondefaults>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<completiondefaults>'.PHP_EOL;
foreach ($completionData as $completion) {
$completionState = $completion['state'] ?? 0;
$xmlContent .= ' <completion>' . PHP_EOL;
$xmlContent .= ' <completionstate>' . $completionState . '</completionstate>' . PHP_EOL;
$xmlContent .= ' </completion>' . PHP_EOL;
$xmlContent .= ' <completion>'.PHP_EOL;
$xmlContent .= ' <completionstate>'.$completionState.'</completionstate>'.PHP_EOL;
$xmlContent .= ' </completion>'.PHP_EOL;
}
$xmlContent .= '</completiondefaults>';
file_put_contents($destinationDir . '/completiondefaults.xml', $xmlContent);
file_put_contents($destinationDir.'/completiondefaults.xml', $xmlContent);
}
/**
@ -290,16 +290,16 @@ class CourseExport
*/
private function createContentBankXml(array $contentBankData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<contentbank>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<contentbank>'.PHP_EOL;
foreach ($contentBankData as $content) {
$id = $content['id'] ?? 0;
$name = $content['name'] ?? 'Content';
$xmlContent .= ' <content id="' . $id . '">' . htmlspecialchars($name) . '</content>' . PHP_EOL;
$xmlContent .= ' <content id="'.$id.'">'.htmlspecialchars($name).'</content>'.PHP_EOL;
}
$xmlContent .= '</contentbank>';
file_put_contents($destinationDir . '/contentbank.xml', $xmlContent);
file_put_contents($destinationDir.'/contentbank.xml', $xmlContent);
}
/**
@ -307,19 +307,19 @@ class CourseExport
*/
private function createFiltersXml(array $filtersData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<filters>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<filters>'.PHP_EOL;
foreach ($filtersData as $filter) {
$filterName = $filter['name'] ?? 'filter_example';
$active = $filter['active'] ?? 1;
$xmlContent .= ' <filter>' . PHP_EOL;
$xmlContent .= ' <filtername>' . htmlspecialchars($filterName) . '</filtername>' . PHP_EOL;
$xmlContent .= ' <active>' . $active . '</active>' . PHP_EOL;
$xmlContent .= ' </filter>' . PHP_EOL;
$xmlContent .= ' <filter>'.PHP_EOL;
$xmlContent .= ' <filtername>'.htmlspecialchars($filterName).'</filtername>'.PHP_EOL;
$xmlContent .= ' <active>'.$active.'</active>'.PHP_EOL;
$xmlContent .= ' </filter>'.PHP_EOL;
}
$xmlContent .= '</filters>';
file_put_contents($destinationDir . '/filters.xml', $xmlContent);
file_put_contents($destinationDir.'/filters.xml', $xmlContent);
}
}

@ -14,10 +14,10 @@ class FeedbackExport extends ActivityExport
/**
* Export a survey to Moodle Feedback format.
*
* @param int $activityId The ID of the survey.
* @param string $exportDir The directory where the feedback will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the survey.
* @param string $exportDir The directory where the feedback will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -41,38 +41,80 @@ class FeedbackExport extends ActivityExport
$this->createRolesXml($surveyData, $feedbackDir);
}
/**
* Get survey data including questions and answers from Chamilo.
*/
public function getData(int $surveyId, int $sectionId): array
{
$adminData = MoodleExport::getAdminUserData();
$adminId = $adminData['id'];
$survey = $this->course->resources['survey'][$surveyId];
$questions = [];
foreach ($this->course->resources['survey_question'] as $question) {
if ((int) $question->survey_id === $surveyId) {
// Debugging
$questions[] = [
'id' => $question->id,
'text' => $question->survey_question,
'type' => $question->survey_question_type,
'options' => array_map(function ($answer) {
return $answer['option_text'];
}, $question->answers),
'position' => $question->sort,
'label' => '', // Default empty label
];
}
}
return [
'id' => $surveyId,
'moduleid' => $surveyId,
'modulename' => 'feedback',
'contextid' => $this->course->info['real_id'],
'sectionid' => $sectionId,
'sectionnumber' => 0,
'name' => $survey->title,
'intro' => $survey->intro,
'timemodified' => time(),
'questions' => $questions,
'users' => [$adminId],
'files' => [],
];
}
/**
* Create the feedback.xml file for the Moodle feedback activity.
*/
private function createFeedbackXml(array $surveyData, string $feedbackDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $surveyData['id'] . '" moduleid="' . $surveyData['moduleid'] . '" modulename="feedback" contextid="' . $surveyData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <feedback id="' . $surveyData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($surveyData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro>' . htmlspecialchars($surveyData['intro']) . '</intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <anonymous>1</anonymous>' . PHP_EOL;
$xmlContent .= ' <email_notification>0</email_notification>' . PHP_EOL;
$xmlContent .= ' <multiple_submit>0</multiple_submit>' . PHP_EOL;
$xmlContent .= ' <autonumbering>1</autonumbering>' . PHP_EOL;
$xmlContent .= ' <site_after_submit></site_after_submit>' . PHP_EOL;
$xmlContent .= ' <page_after_submit></page_after_submit>' . PHP_EOL;
$xmlContent .= ' <page_after_submitformat>1</page_after_submitformat>' . PHP_EOL;
$xmlContent .= ' <publish_stats>0</publish_stats>' . PHP_EOL;
$xmlContent .= ' <timeopen>0</timeopen>' . PHP_EOL;
$xmlContent .= ' <timeclose>0</timeclose>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $surveyData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <completionsubmit>0</completionsubmit>' . PHP_EOL;
$xmlContent .= ' <items>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$surveyData['id'].'" moduleid="'.$surveyData['moduleid'].'" modulename="feedback" contextid="'.$surveyData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <feedback id="'.$surveyData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($surveyData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro>'.htmlspecialchars($surveyData['intro']).'</intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <anonymous>1</anonymous>'.PHP_EOL;
$xmlContent .= ' <email_notification>0</email_notification>'.PHP_EOL;
$xmlContent .= ' <multiple_submit>0</multiple_submit>'.PHP_EOL;
$xmlContent .= ' <autonumbering>1</autonumbering>'.PHP_EOL;
$xmlContent .= ' <site_after_submit></site_after_submit>'.PHP_EOL;
$xmlContent .= ' <page_after_submit></page_after_submit>'.PHP_EOL;
$xmlContent .= ' <page_after_submitformat>1</page_after_submitformat>'.PHP_EOL;
$xmlContent .= ' <publish_stats>0</publish_stats>'.PHP_EOL;
$xmlContent .= ' <timeopen>0</timeopen>'.PHP_EOL;
$xmlContent .= ' <timeclose>0</timeclose>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$surveyData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <completionsubmit>0</completionsubmit>'.PHP_EOL;
$xmlContent .= ' <items>'.PHP_EOL;
// Map Chamilo questions to Moodle Feedback format
foreach ($surveyData['questions'] as $question) {
$xmlContent .= $this->createQuestionXml($question);
}
$xmlContent .= ' </items>' . PHP_EOL;
$xmlContent .= ' </feedback>' . PHP_EOL;
$xmlContent .= ' </items>'.PHP_EOL;
$xmlContent .= ' </feedback>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('feedback', $xmlContent, $feedbackDir);
@ -88,19 +130,19 @@ class FeedbackExport extends ActivityExport
$presentation = $this->getPresentation($question);
$hasValue = ($question['type'] === 'pagebreak') ? '0' : '1';
$xmlContent = '<item id="' . $question['id'] . '">' . PHP_EOL;
$xmlContent .= ' <template>0</template>' . PHP_EOL;
$xmlContent .= ' <name>' . $name . '</name>' . PHP_EOL;
$xmlContent .= ' <label>' . $label . '</label>' . PHP_EOL;
$xmlContent .= ' <presentation>' . $presentation . '</presentation>' . PHP_EOL;
$xmlContent .= ' <typ>' . $this->mapQuestionType($question['type']) . '</typ>' . PHP_EOL;
$xmlContent .= ' <hasvalue>' . $hasValue . '</hasvalue>' . PHP_EOL;
$xmlContent .= ' <position>' . $question['position'] . '</position>' . PHP_EOL;
$xmlContent .= ' <required>0</required>' . PHP_EOL;
$xmlContent .= ' <dependitem>0</dependitem>' . PHP_EOL;
$xmlContent .= ' <dependvalue></dependvalue>' . PHP_EOL;
$xmlContent .= ' <options>h</options>' . PHP_EOL;
$xmlContent .= '</item>' . PHP_EOL;
$xmlContent = '<item id="'.$question['id'].'">'.PHP_EOL;
$xmlContent .= ' <template>0</template>'.PHP_EOL;
$xmlContent .= ' <name>'.$name.'</name>'.PHP_EOL;
$xmlContent .= ' <label>'.$label.'</label>'.PHP_EOL;
$xmlContent .= ' <presentation>'.$presentation.'</presentation>'.PHP_EOL;
$xmlContent .= ' <typ>'.$this->mapQuestionType($question['type']).'</typ>'.PHP_EOL;
$xmlContent .= ' <hasvalue>'.$hasValue.'</hasvalue>'.PHP_EOL;
$xmlContent .= ' <position>'.$question['position'].'</position>'.PHP_EOL;
$xmlContent .= ' <required>0</required>'.PHP_EOL;
$xmlContent .= ' <dependitem>0</dependitem>'.PHP_EOL;
$xmlContent .= ' <dependvalue></dependvalue>'.PHP_EOL;
$xmlContent .= ' <options>h</options>'.PHP_EOL;
$xmlContent .= '</item>'.PHP_EOL;
return $xmlContent;
}
@ -119,11 +161,11 @@ class FeedbackExport extends ActivityExport
case 'yesno':
case 'multiplechoice':
case 'multiplechoiceother':
return 'r&gt;&gt;&gt;&gt;&gt;' . implode(PHP_EOL . '|', $sanitizedOptions);
return 'r&gt;&gt;&gt;&gt;&gt;'.implode(PHP_EOL.'|', $sanitizedOptions);
case 'multipleresponse':
return 'c&gt;&gt;&gt;&gt;&gt;' . implode(PHP_EOL . '|', $sanitizedOptions);
return 'c&gt;&gt;&gt;&gt;&gt;'.implode(PHP_EOL.'|', $sanitizedOptions);
case 'dropdown':
return 'd&gt;&gt;&gt;&gt;&gt;' . implode(PHP_EOL . '|', $sanitizedOptions);
return 'd&gt;&gt;&gt;&gt;&gt;'.implode(PHP_EOL.'|', $sanitizedOptions);
case 'open':
return '30|5'; // Textarea with rows and cols
default:
@ -148,46 +190,4 @@ class FeedbackExport extends ActivityExport
return $typeMap[$chamiloType] ?? 'unknown';
}
/**
* Get survey data including questions and answers from Chamilo.
*/
public function getData(int $surveyId, int $sectionId): array
{
$adminData = MoodleExport::getAdminUserData();
$adminId = $adminData['id'];
$survey = $this->course->resources['survey'][$surveyId];
$questions = [];
foreach ($this->course->resources['survey_question'] as $question) {
if ((int) $question->survey_id === $surveyId) {
// Debugging
$questions[] = [
'id' => $question->id,
'text' => $question->survey_question,
'type' => $question->survey_question_type,
'options' => array_map(function ($answer) {
return $answer['option_text'];
}, $question->answers),
'position' => $question->sort,
'label' => '', // Default empty label
];
}
}
return [
'id' => $surveyId,
'moduleid' => $surveyId,
'modulename' => 'feedback',
'contextid' => $this->course->info['real_id'],
'sectionid' => $sectionId,
'sectionnumber' => 0,
'name' => $survey->title,
'intro' => $survey->intro,
'timemodified' => time(),
'questions' => $questions,
'users' => [$adminId],
'files' => [],
];
}
}

@ -32,7 +32,7 @@ class FileExport
*/
public function exportFiles(array $filesData, string $exportDir): void
{
$filesDir = $exportDir . '/files';
$filesDir = $exportDir.'/files';
if (!is_dir($filesDir)) {
mkdir($filesDir, api_get_permissions_for_new_directories(), true);
@ -50,12 +50,61 @@ class FileExport
$this->createFilesXml($filesData, $exportDir);
}
/**
* Get file data from course resources. This is for testing purposes.
*/
public function getFilesData(): array
{
$adminData = MoodleExport::getAdminUserData();
$adminId = $adminData['id'];
$filesData = ['files' => []];
foreach ($this->course->resources[RESOURCE_DOCUMENT] as $document) {
$filesData = $this->processDocument($filesData, $document);
}
foreach ($this->course->resources[RESOURCE_WORK] as $work) {
$workFiles = getAllDocumentToWork($work->params['id'], $this->course->info['real_id']);
if (!empty($workFiles)) {
foreach ($workFiles as $file) {
$docData = DocumentManager::get_document_data_by_id($file['document_id'], $this->course->info['code']);
if (!empty($docData)) {
$filesData['files'][] = [
'id' => $file['document_id'],
'contenthash' => hash('sha1', basename($docData['path'])),
'contextid' => $this->course->info['real_id'],
'component' => 'mod_assign',
'filearea' => 'introattachment',
'itemid' => (int) $work->params['id'],
'filepath' => '/',
'documentpath' => 'document/'.$docData['path'],
'filename' => basename($docData['path']),
'userid' => $adminId,
'filesize' => $docData['size'],
'mimetype' => $this->getMimeType($docData['path']),
'status' => 0,
'timecreated' => time() - 3600,
'timemodified' => time(),
'source' => $docData['title'],
'author' => 'Unknown',
'license' => 'allrightsreserved',
];
}
}
}
}
return $filesData;
}
/**
* Create a placeholder index.html file to prevent an empty directory.
*/
private function createPlaceholderFile(string $filesDir): void
{
$placeholderFile = $filesDir . '/index.html';
$placeholderFile = $filesDir.'/index.html';
file_put_contents($placeholderFile, "<!-- Placeholder file to ensure the directory is not empty -->");
}
@ -70,8 +119,8 @@ class FileExport
$contenthash = $file['contenthash'];
$subDir = substr($contenthash, 0, 2);
$filePath = $this->course->path . $file['documentpath'];
$exportSubDir = $filesDir . '/' . $subDir;
$filePath = $this->course->path.$file['documentpath'];
$exportSubDir = $filesDir.'/'.$subDir;
// Ensure the subdirectory exists
if (!is_dir($exportSubDir)) {
@ -79,7 +128,7 @@ class FileExport
}
// Copy the file to the export directory
$destinationFile = $exportSubDir . '/' . $contenthash;
$destinationFile = $exportSubDir.'/'.$contenthash;
if (file_exists($filePath)) {
copy($filePath, $destinationFile);
} else {
@ -92,15 +141,15 @@ class FileExport
*/
private function createFilesXml(array $filesData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<files>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<files>'.PHP_EOL;
foreach ($filesData['files'] as $file) {
$xmlContent .= $this->createFileXmlEntry($file);
}
$xmlContent .= '</files>' . PHP_EOL;
file_put_contents($destinationDir . '/files.xml', $xmlContent);
$xmlContent .= '</files>'.PHP_EOL;
file_put_contents($destinationDir.'/files.xml', $xmlContent);
}
/**
@ -108,77 +157,28 @@ class FileExport
*/
private function createFileXmlEntry(array $file): string
{
return ' <file id="' . $file['id'] . '">' . PHP_EOL .
' <contenthash>' . htmlspecialchars($file['contenthash']) . '</contenthash>' . PHP_EOL .
' <contextid>' . $file['contextid'] . '</contextid>' . PHP_EOL .
' <component>' . htmlspecialchars($file['component']) . '</component>' . PHP_EOL .
' <filearea>' . htmlspecialchars($file['filearea']) . '</filearea>' . PHP_EOL .
' <itemid>0</itemid>' . PHP_EOL .
' <filepath>' . htmlspecialchars($file['filepath']) . '</filepath>' . PHP_EOL .
' <filename>' . htmlspecialchars($file['filename']) . '</filename>' . PHP_EOL .
' <userid>' . $file['userid'] . '</userid>' . PHP_EOL .
' <filesize>' . $file['filesize'] . '</filesize>' . PHP_EOL .
' <mimetype>' . htmlspecialchars($file['mimetype']) . '</mimetype>' . PHP_EOL .
' <status>' . $file['status'] . '</status>' . PHP_EOL .
' <timecreated>' . $file['timecreated'] . '</timecreated>' . PHP_EOL .
' <timemodified>' . $file['timemodified'] . '</timemodified>' . PHP_EOL .
' <source>' . htmlspecialchars($file['source']) . '</source>' . PHP_EOL .
' <author>' . htmlspecialchars($file['author']) . '</author>' . PHP_EOL .
' <license>' . htmlspecialchars($file['license']) . '</license>' . PHP_EOL .
' <sortorder>0</sortorder>' . PHP_EOL .
' <repositorytype>$@NULL@$</repositorytype>' . PHP_EOL .
' <repositoryid>$@NULL@$</repositoryid>' . PHP_EOL .
' <reference>$@NULL@$</reference>' . PHP_EOL .
' </file>' . PHP_EOL;
}
/**
* Get file data from course resources. This is for testing purposes.
*/
public function getFilesData(): array
{
$adminData = MoodleExport::getAdminUserData();
$adminId = $adminData['id'];
$filesData = ['files' => []];
foreach ($this->course->resources[RESOURCE_DOCUMENT] as $document) {
$filesData = $this->processDocument($filesData, $document);
}
foreach ($this->course->resources[RESOURCE_WORK] as $work) {
$workFiles = getAllDocumentToWork($work->params['id'], $this->course->info['real_id']);
if (!empty($workFiles)) {
foreach ($workFiles as $file) {
$docData = DocumentManager::get_document_data_by_id($file['document_id'], $this->course->info['code']);
if (!empty($docData)) {
$filesData['files'][] = [
'id' => $file['document_id'],
'contenthash' => hash('sha1', basename($docData['path'])),
'contextid' => $this->course->info['real_id'],
'component' => 'mod_assign',
'filearea' => 'introattachment',
'itemid' => (int) $work->params['id'],
'filepath' => '/',
'documentpath' => 'document/'.$docData['path'],
'filename' => basename($docData['path']),
'userid' => $adminId,
'filesize' => $docData['size'],
'mimetype' => $this->getMimeType($docData['path']),
'status' => 0,
'timecreated' => time() - 3600,
'timemodified' => time(),
'source' => $docData['title'],
'author' => 'Unknown',
'license' => 'allrightsreserved',
];
}
}
}
}
return $filesData;
return ' <file id="'.$file['id'].'">'.PHP_EOL.
' <contenthash>'.htmlspecialchars($file['contenthash']).'</contenthash>'.PHP_EOL.
' <contextid>'.$file['contextid'].'</contextid>'.PHP_EOL.
' <component>'.htmlspecialchars($file['component']).'</component>'.PHP_EOL.
' <filearea>'.htmlspecialchars($file['filearea']).'</filearea>'.PHP_EOL.
' <itemid>0</itemid>'.PHP_EOL.
' <filepath>'.htmlspecialchars($file['filepath']).'</filepath>'.PHP_EOL.
' <filename>'.htmlspecialchars($file['filename']).'</filename>'.PHP_EOL.
' <userid>'.$file['userid'].'</userid>'.PHP_EOL.
' <filesize>'.$file['filesize'].'</filesize>'.PHP_EOL.
' <mimetype>'.htmlspecialchars($file['mimetype']).'</mimetype>'.PHP_EOL.
' <status>'.$file['status'].'</status>'.PHP_EOL.
' <timecreated>'.$file['timecreated'].'</timecreated>'.PHP_EOL.
' <timemodified>'.$file['timemodified'].'</timemodified>'.PHP_EOL.
' <source>'.htmlspecialchars($file['source']).'</source>'.PHP_EOL.
' <author>'.htmlspecialchars($file['author']).'</author>'.PHP_EOL.
' <license>'.htmlspecialchars($file['license']).'</license>'.PHP_EOL.
' <sortorder>0</sortorder>'.PHP_EOL.
' <repositorytype>$@NULL@$</repositorytype>'.PHP_EOL.
' <repositoryid>$@NULL@$</repositoryid>'.PHP_EOL.
' <reference>$@NULL@$</reference>'.PHP_EOL.
' </file>'.PHP_EOL;
}
/**
@ -194,6 +194,7 @@ class FileExport
$filesData['files'][] = $this->getFolderFileData($file, (int) $document->source_id);
}
}
return $filesData;
}
@ -268,7 +269,7 @@ class FileExport
*/
private function ensureTrailingSlash($path): string
{
return empty($path) || $path === '.' || $path === '/' ? '/' : rtrim($path, '/') . '/';
return empty($path) || $path === '.' || $path === '/' ? '/' : rtrim($path, '/').'/';
}
/**

@ -14,10 +14,10 @@ class FolderExport extends ActivityExport
/**
* Export a folder to the specified directory.
*
* @param int $activityId The ID of the folder.
* @param string $exportDir The directory where the folder will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the folder.
* @param string $exportDir The directory where the folder will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -39,29 +39,6 @@ class FolderExport extends ActivityExport
$this->createCalendarXml($folderData, $folderDir);
}
/**
* Create the XML file for the folder.
*/
private function createFolderXml(array $folderData, string $folderDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $folderData['id'] . '" moduleid="' . $folderData['moduleid'] . '" modulename="folder" contextid="' . $folderData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <folder id="' . $folderData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($folderData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro></intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <revision>1</revision>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $folderData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <display>0</display>' . PHP_EOL;
$xmlContent .= ' <showexpanded>1</showexpanded>' . PHP_EOL;
$xmlContent .= ' <showdownloadfolder>1</showdownloadfolder>' . PHP_EOL;
$xmlContent .= ' <forcedownload>1</forcedownload>' . PHP_EOL;
$xmlContent .= ' </folder>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('folder', $xmlContent, $folderDir);
}
/**
* Get folder data dynamically from the course.
*/
@ -80,6 +57,29 @@ class FolderExport extends ActivityExport
];
}
/**
* Create the XML file for the folder.
*/
private function createFolderXml(array $folderData, string $folderDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$folderData['id'].'" moduleid="'.$folderData['moduleid'].'" modulename="folder" contextid="'.$folderData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <folder id="'.$folderData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($folderData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro></intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <revision>1</revision>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$folderData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <display>0</display>'.PHP_EOL;
$xmlContent .= ' <showexpanded>1</showexpanded>'.PHP_EOL;
$xmlContent .= ' <showdownloadfolder>1</showdownloadfolder>'.PHP_EOL;
$xmlContent .= ' <forcedownload>1</forcedownload>'.PHP_EOL;
$xmlContent .= ' </folder>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('folder', $xmlContent, $folderDir);
}
/**
* Get the list of files for a folder.
*/
@ -92,7 +92,7 @@ class FolderExport extends ActivityExport
if ($doc['filetype'] === 'file') {
$files[] = [
'id' => (int) $doc['id'],
'contenthash' => 'hash' . $doc['id'],
'contenthash' => 'hash'.$doc['id'],
'filename' => $doc['basename'],
'filepath' => $doc['path'],
'filesize' => (int) $doc['size'],

@ -14,10 +14,10 @@ class ForumExport extends ActivityExport
/**
* Export all forum data into a single Moodle forum activity.
*
* @param int $activityId The ID of the forum.
* @param string $exportDir The directory where the forum will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the forum.
* @param string $exportDir The directory where the forum will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -40,94 +40,6 @@ class ForumExport extends ActivityExport
$this->createFiltersXml($forumData, $forumDir);
}
/**
* Create the forum.xml file with all forum data.
*/
private function createForumXml(array $forumData, string $forumDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $forumData['id'] . '" moduleid="' . $forumData['moduleid'] . '" modulename="'.$forumData['modulename'].'" contextid="' . $forumData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <forum id="' . $forumData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <type>general</type>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($forumData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro>' . htmlspecialchars($forumData['description']) . '</intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <duedate>0</duedate>' . PHP_EOL;
$xmlContent .= ' <cutoffdate>0</cutoffdate>' . PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>' . PHP_EOL;
$xmlContent .= ' <assesstimestart>0</assesstimestart>' . PHP_EOL;
$xmlContent .= ' <assesstimefinish>0</assesstimefinish>' . PHP_EOL;
$xmlContent .= ' <scale>100</scale>' . PHP_EOL;
$xmlContent .= ' <maxbytes>512000</maxbytes>' . PHP_EOL;
$xmlContent .= ' <maxattachments>9</maxattachments>' . PHP_EOL;
$xmlContent .= ' <forcesubscribe>0</forcesubscribe>' . PHP_EOL;
$xmlContent .= ' <trackingtype>1</trackingtype>' . PHP_EOL;
$xmlContent .= ' <rsstype>0</rsstype>' . PHP_EOL;
$xmlContent .= ' <rssarticles>0</rssarticles>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $forumData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <warnafter>0</warnafter>' . PHP_EOL;
$xmlContent .= ' <blockafter>0</blockafter>' . PHP_EOL;
$xmlContent .= ' <blockperiod>0</blockperiod>' . PHP_EOL;
$xmlContent .= ' <completiondiscussions>0</completiondiscussions>' . PHP_EOL;
$xmlContent .= ' <completionreplies>0</completionreplies>' . PHP_EOL;
$xmlContent .= ' <completionposts>0</completionposts>' . PHP_EOL;
$xmlContent .= ' <displaywordcount>0</displaywordcount>' . PHP_EOL;
$xmlContent .= ' <lockdiscussionafter>0</lockdiscussionafter>' . PHP_EOL;
$xmlContent .= ' <grade_forum>0</grade_forum>' . PHP_EOL;
// Add forum threads
$xmlContent .= ' <discussions>' . PHP_EOL;
foreach ($forumData['threads'] as $thread) {
$xmlContent .= ' <discussion id="' . $thread['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($thread['title']) . '</name>' . PHP_EOL;
$xmlContent .= ' <firstpost>' . $thread['firstpost'] . '</firstpost>' . PHP_EOL;
$xmlContent .= ' <userid>' . $thread['userid'] . '</userid>' . PHP_EOL;
$xmlContent .= ' <groupid>-1</groupid>' . PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $thread['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <usermodified>' . $thread['usermodified'] . '</usermodified>' . PHP_EOL;
$xmlContent .= ' <timestart>0</timestart>' . PHP_EOL;
$xmlContent .= ' <timeend>0</timeend>' . PHP_EOL;
$xmlContent .= ' <pinned>0</pinned>' . PHP_EOL;
$xmlContent .= ' <timelocked>0</timelocked>' . PHP_EOL;
// Add forum posts to the thread
$xmlContent .= ' <posts>' . PHP_EOL;
foreach ($thread['posts'] as $post) {
$xmlContent .= ' <post id="' . $post['id'] . '">' . PHP_EOL;
$xmlContent .= ' <parent>' . $post['parent'] . '</parent>' . PHP_EOL;
$xmlContent .= ' <userid>' . $post['userid'] . '</userid>' . PHP_EOL;
$xmlContent .= ' <created>' . $post['created'] . '</created>' . PHP_EOL;
$xmlContent .= ' <modified>' . $post['modified'] . '</modified>' . PHP_EOL;
$xmlContent .= ' <mailed>' . $post['mailed'] . '</mailed>' . PHP_EOL;
$xmlContent .= ' <subject>' . htmlspecialchars($post['subject']) . '</subject>' . PHP_EOL;
$xmlContent .= ' <message>' . htmlspecialchars($post['message']) . '</message>' . PHP_EOL;
$xmlContent .= ' <messageformat>1</messageformat>' . PHP_EOL;
$xmlContent .= ' <messagetrust>0</messagetrust>' . PHP_EOL;
$xmlContent .= ' <attachment></attachment>' . PHP_EOL;
$xmlContent .= ' <totalscore>0</totalscore>' . PHP_EOL;
$xmlContent .= ' <mailnow>0</mailnow>' . PHP_EOL;
$xmlContent .= ' <privatereplyto>0</privatereplyto>' . PHP_EOL;
$xmlContent .= ' <ratings>' . PHP_EOL;
$xmlContent .= ' </ratings>' . PHP_EOL;
$xmlContent .= ' </post>' . PHP_EOL;
}
$xmlContent .= ' </posts>' . PHP_EOL;
$xmlContent .= ' <discussion_subs>' . PHP_EOL;
$xmlContent .= ' <discussion_sub id="'.$thread['id'].'">' . PHP_EOL;
$xmlContent .= ' <userid>' . $thread['userid'] . '</userid>' . PHP_EOL;
$xmlContent .= ' <preference>' . $thread['timemodified'] . '</preference>' . PHP_EOL;
$xmlContent .= ' </discussion_sub>' . PHP_EOL;
$xmlContent .= ' </discussion_subs>' . PHP_EOL;
$xmlContent .= ' </discussion>' . PHP_EOL;
}
$xmlContent .= ' </discussions>' . PHP_EOL;
$xmlContent .= ' </forum>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('forum', $xmlContent, $forumDir);
}
/**
* Get all forum data from the course.
*/
@ -185,4 +97,92 @@ class ForumExport extends ActivityExport
'files' => $fileIds,
];
}
/**
* Create the forum.xml file with all forum data.
*/
private function createForumXml(array $forumData, string $forumDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$forumData['id'].'" moduleid="'.$forumData['moduleid'].'" modulename="'.$forumData['modulename'].'" contextid="'.$forumData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <forum id="'.$forumData['id'].'">'.PHP_EOL;
$xmlContent .= ' <type>general</type>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($forumData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro>'.htmlspecialchars($forumData['description']).'</intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <duedate>0</duedate>'.PHP_EOL;
$xmlContent .= ' <cutoffdate>0</cutoffdate>'.PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>'.PHP_EOL;
$xmlContent .= ' <assesstimestart>0</assesstimestart>'.PHP_EOL;
$xmlContent .= ' <assesstimefinish>0</assesstimefinish>'.PHP_EOL;
$xmlContent .= ' <scale>100</scale>'.PHP_EOL;
$xmlContent .= ' <maxbytes>512000</maxbytes>'.PHP_EOL;
$xmlContent .= ' <maxattachments>9</maxattachments>'.PHP_EOL;
$xmlContent .= ' <forcesubscribe>0</forcesubscribe>'.PHP_EOL;
$xmlContent .= ' <trackingtype>1</trackingtype>'.PHP_EOL;
$xmlContent .= ' <rsstype>0</rsstype>'.PHP_EOL;
$xmlContent .= ' <rssarticles>0</rssarticles>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$forumData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <warnafter>0</warnafter>'.PHP_EOL;
$xmlContent .= ' <blockafter>0</blockafter>'.PHP_EOL;
$xmlContent .= ' <blockperiod>0</blockperiod>'.PHP_EOL;
$xmlContent .= ' <completiondiscussions>0</completiondiscussions>'.PHP_EOL;
$xmlContent .= ' <completionreplies>0</completionreplies>'.PHP_EOL;
$xmlContent .= ' <completionposts>0</completionposts>'.PHP_EOL;
$xmlContent .= ' <displaywordcount>0</displaywordcount>'.PHP_EOL;
$xmlContent .= ' <lockdiscussionafter>0</lockdiscussionafter>'.PHP_EOL;
$xmlContent .= ' <grade_forum>0</grade_forum>'.PHP_EOL;
// Add forum threads
$xmlContent .= ' <discussions>'.PHP_EOL;
foreach ($forumData['threads'] as $thread) {
$xmlContent .= ' <discussion id="'.$thread['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($thread['title']).'</name>'.PHP_EOL;
$xmlContent .= ' <firstpost>'.$thread['firstpost'].'</firstpost>'.PHP_EOL;
$xmlContent .= ' <userid>'.$thread['userid'].'</userid>'.PHP_EOL;
$xmlContent .= ' <groupid>-1</groupid>'.PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$thread['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <usermodified>'.$thread['usermodified'].'</usermodified>'.PHP_EOL;
$xmlContent .= ' <timestart>0</timestart>'.PHP_EOL;
$xmlContent .= ' <timeend>0</timeend>'.PHP_EOL;
$xmlContent .= ' <pinned>0</pinned>'.PHP_EOL;
$xmlContent .= ' <timelocked>0</timelocked>'.PHP_EOL;
// Add forum posts to the thread
$xmlContent .= ' <posts>'.PHP_EOL;
foreach ($thread['posts'] as $post) {
$xmlContent .= ' <post id="'.$post['id'].'">'.PHP_EOL;
$xmlContent .= ' <parent>'.$post['parent'].'</parent>'.PHP_EOL;
$xmlContent .= ' <userid>'.$post['userid'].'</userid>'.PHP_EOL;
$xmlContent .= ' <created>'.$post['created'].'</created>'.PHP_EOL;
$xmlContent .= ' <modified>'.$post['modified'].'</modified>'.PHP_EOL;
$xmlContent .= ' <mailed>'.$post['mailed'].'</mailed>'.PHP_EOL;
$xmlContent .= ' <subject>'.htmlspecialchars($post['subject']).'</subject>'.PHP_EOL;
$xmlContent .= ' <message>'.htmlspecialchars($post['message']).'</message>'.PHP_EOL;
$xmlContent .= ' <messageformat>1</messageformat>'.PHP_EOL;
$xmlContent .= ' <messagetrust>0</messagetrust>'.PHP_EOL;
$xmlContent .= ' <attachment></attachment>'.PHP_EOL;
$xmlContent .= ' <totalscore>0</totalscore>'.PHP_EOL;
$xmlContent .= ' <mailnow>0</mailnow>'.PHP_EOL;
$xmlContent .= ' <privatereplyto>0</privatereplyto>'.PHP_EOL;
$xmlContent .= ' <ratings>'.PHP_EOL;
$xmlContent .= ' </ratings>'.PHP_EOL;
$xmlContent .= ' </post>'.PHP_EOL;
}
$xmlContent .= ' </posts>'.PHP_EOL;
$xmlContent .= ' <discussion_subs>'.PHP_EOL;
$xmlContent .= ' <discussion_sub id="'.$thread['id'].'">'.PHP_EOL;
$xmlContent .= ' <userid>'.$thread['userid'].'</userid>'.PHP_EOL;
$xmlContent .= ' <preference>'.$thread['timemodified'].'</preference>'.PHP_EOL;
$xmlContent .= ' </discussion_sub>'.PHP_EOL;
$xmlContent .= ' </discussion_subs>'.PHP_EOL;
$xmlContent .= ' </discussion>'.PHP_EOL;
}
$xmlContent .= ' </discussions>'.PHP_EOL;
$xmlContent .= ' </forum>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('forum', $xmlContent, $forumDir);
}
}

@ -14,10 +14,10 @@ class GlossaryExport extends ActivityExport
/**
* Export all glossary terms into a single Moodle glossary.
*
* @param int $activityId The ID of the glossary.
* @param string $exportDir The directory where the glossary will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the glossary.
* @param string $exportDir The directory where the glossary will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -40,71 +40,6 @@ class GlossaryExport extends ActivityExport
$this->createFiltersXml($glossaryData, $glossaryDir);
}
/**
* Create the XML file for the glossary with all terms combined.
*/
private function createGlossaryXml(array $glossaryData, string $glossaryDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $glossaryData['id'] . '" moduleid="' . $glossaryData['moduleid'] . '" modulename="'.$glossaryData['modulename'].'" contextid="' . $glossaryData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <glossary id="' . $glossaryData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($glossaryData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro></intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <allowduplicatedentries>0</allowduplicatedentries>' . PHP_EOL;
$xmlContent .= ' <displayformat>dictionary</displayformat>' . PHP_EOL;
$xmlContent .= ' <mainglossary>0</mainglossary>' . PHP_EOL;
$xmlContent .= ' <showspecial>1</showspecial>' . PHP_EOL;
$xmlContent .= ' <showalphabet>1</showalphabet>' . PHP_EOL;
$xmlContent .= ' <showall>1</showall>' . PHP_EOL;
$xmlContent .= ' <allowcomments>0</allowcomments>' . PHP_EOL;
$xmlContent .= ' <allowprintview>1</allowprintview>' . PHP_EOL;
$xmlContent .= ' <usedynalink>1</usedynalink>' . PHP_EOL;
$xmlContent .= ' <defaultapproval>1</defaultapproval>' . PHP_EOL;
$xmlContent .= ' <globalglossary>0</globalglossary>' . PHP_EOL;
$xmlContent .= ' <entbypage>10</entbypage>' . PHP_EOL;
$xmlContent .= ' <editalways>0</editalways>' . PHP_EOL;
$xmlContent .= ' <rsstype>0</rsstype>' . PHP_EOL;
$xmlContent .= ' <rssarticles>0</rssarticles>' . PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>' . PHP_EOL;
$xmlContent .= ' <assesstimestart>0</assesstimestart>' . PHP_EOL;
$xmlContent .= ' <assesstimefinish>0</assesstimefinish>' . PHP_EOL;
$xmlContent .= ' <scale>100</scale>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . $glossaryData['timecreated'] . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $glossaryData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <completionentries>0</completionentries>' . PHP_EOL;
$xmlContent .= ' <entries>' . PHP_EOL;
// Add glossary terms (entries)
foreach ($glossaryData['entries'] as $entry) {
$xmlContent .= ' <entry id="' . $entry['id'] . '">' . PHP_EOL;
$xmlContent .= ' <userid>' . $entry['userid'] . '</userid>' . PHP_EOL;
$xmlContent .= ' <concept>' . htmlspecialchars($entry['concept']) . '</concept>' . PHP_EOL;
$xmlContent .= ' <definition><![CDATA[' . $entry['definition'] . ']]></definition>' . PHP_EOL;
$xmlContent .= ' <definitionformat>1</definitionformat>' . PHP_EOL;
$xmlContent .= ' <definitiontrust>0</definitiontrust>' . PHP_EOL;
$xmlContent .= ' <attachment></attachment>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . $entry['timecreated'] . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $entry['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <teacherentry>1</teacherentry>' . PHP_EOL;
$xmlContent .= ' <sourceglossaryid>0</sourceglossaryid>' . PHP_EOL;
$xmlContent .= ' <usedynalink>0</usedynalink>' . PHP_EOL;
$xmlContent .= ' <casesensitive>0</casesensitive>' . PHP_EOL;
$xmlContent .= ' <fullmatch>0</fullmatch>' . PHP_EOL;
$xmlContent .= ' <approved>1</approved>' . PHP_EOL;
$xmlContent .= ' <ratings>' . PHP_EOL;
$xmlContent .= ' </ratings>' . PHP_EOL;
$xmlContent .= ' </entry>' . PHP_EOL;
}
$xmlContent .= ' </entries>' . PHP_EOL;
$xmlContent .= ' <entriestags></entriestags>' . PHP_EOL;
$xmlContent .= ' <categories></categories>' . PHP_EOL;
$xmlContent .= ' </glossary>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('glossary', $xmlContent, $glossaryDir);
}
/**
* Get all terms from the course and group them into a single glossary.
*/
@ -143,4 +78,69 @@ class GlossaryExport extends ActivityExport
'files' => [],
];
}
/**
* Create the XML file for the glossary with all terms combined.
*/
private function createGlossaryXml(array $glossaryData, string $glossaryDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$glossaryData['id'].'" moduleid="'.$glossaryData['moduleid'].'" modulename="'.$glossaryData['modulename'].'" contextid="'.$glossaryData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <glossary id="'.$glossaryData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($glossaryData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro></intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <allowduplicatedentries>0</allowduplicatedentries>'.PHP_EOL;
$xmlContent .= ' <displayformat>dictionary</displayformat>'.PHP_EOL;
$xmlContent .= ' <mainglossary>0</mainglossary>'.PHP_EOL;
$xmlContent .= ' <showspecial>1</showspecial>'.PHP_EOL;
$xmlContent .= ' <showalphabet>1</showalphabet>'.PHP_EOL;
$xmlContent .= ' <showall>1</showall>'.PHP_EOL;
$xmlContent .= ' <allowcomments>0</allowcomments>'.PHP_EOL;
$xmlContent .= ' <allowprintview>1</allowprintview>'.PHP_EOL;
$xmlContent .= ' <usedynalink>1</usedynalink>'.PHP_EOL;
$xmlContent .= ' <defaultapproval>1</defaultapproval>'.PHP_EOL;
$xmlContent .= ' <globalglossary>0</globalglossary>'.PHP_EOL;
$xmlContent .= ' <entbypage>10</entbypage>'.PHP_EOL;
$xmlContent .= ' <editalways>0</editalways>'.PHP_EOL;
$xmlContent .= ' <rsstype>0</rsstype>'.PHP_EOL;
$xmlContent .= ' <rssarticles>0</rssarticles>'.PHP_EOL;
$xmlContent .= ' <assessed>0</assessed>'.PHP_EOL;
$xmlContent .= ' <assesstimestart>0</assesstimestart>'.PHP_EOL;
$xmlContent .= ' <assesstimefinish>0</assesstimefinish>'.PHP_EOL;
$xmlContent .= ' <scale>100</scale>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.$glossaryData['timecreated'].'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$glossaryData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <completionentries>0</completionentries>'.PHP_EOL;
$xmlContent .= ' <entries>'.PHP_EOL;
// Add glossary terms (entries)
foreach ($glossaryData['entries'] as $entry) {
$xmlContent .= ' <entry id="'.$entry['id'].'">'.PHP_EOL;
$xmlContent .= ' <userid>'.$entry['userid'].'</userid>'.PHP_EOL;
$xmlContent .= ' <concept>'.htmlspecialchars($entry['concept']).'</concept>'.PHP_EOL;
$xmlContent .= ' <definition><![CDATA['.$entry['definition'].']]></definition>'.PHP_EOL;
$xmlContent .= ' <definitionformat>1</definitionformat>'.PHP_EOL;
$xmlContent .= ' <definitiontrust>0</definitiontrust>'.PHP_EOL;
$xmlContent .= ' <attachment></attachment>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.$entry['timecreated'].'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$entry['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <teacherentry>1</teacherentry>'.PHP_EOL;
$xmlContent .= ' <sourceglossaryid>0</sourceglossaryid>'.PHP_EOL;
$xmlContent .= ' <usedynalink>0</usedynalink>'.PHP_EOL;
$xmlContent .= ' <casesensitive>0</casesensitive>'.PHP_EOL;
$xmlContent .= ' <fullmatch>0</fullmatch>'.PHP_EOL;
$xmlContent .= ' <approved>1</approved>'.PHP_EOL;
$xmlContent .= ' <ratings>'.PHP_EOL;
$xmlContent .= ' </ratings>'.PHP_EOL;
$xmlContent .= ' </entry>'.PHP_EOL;
}
$xmlContent .= ' </entries>'.PHP_EOL;
$xmlContent .= ' <entriestags></entriestags>'.PHP_EOL;
$xmlContent .= ' <categories></categories>'.PHP_EOL;
$xmlContent .= ' </glossary>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('glossary', $xmlContent, $glossaryDir);
}
}

@ -5,10 +5,9 @@
namespace moodleexport;
use Exception;
use FillBlanks;
use ZipArchive;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ZipArchive;
/**
* Class MoodleExport.
@ -34,7 +33,7 @@ class MoodleExport
*/
public function export(string $courseId, string $exportDir, int $version)
{
$tempDir = api_get_path(SYS_ARCHIVE_PATH) . $exportDir;
$tempDir = api_get_path(SYS_ARCHIVE_PATH).$exportDir;
if (!is_dir($tempDir)) {
if (!mkdir($tempDir, api_get_permissions_for_new_directories(), true)) {
@ -77,6 +76,107 @@ class MoodleExport
return $exportedFile;
}
/**
* Export questions data to XML file.
*/
public function exportQuestionsXml(array $questionsData, string $exportDir): void
{
$quizExport = new QuizExport($this->course);
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<question_categories>'.PHP_EOL;
foreach ($questionsData as $quiz) {
$categoryId = $quiz['questions'][0]['questioncategoryid'] ?? '0';
$xmlContent .= ' <question_category id="'.$categoryId.'">'.PHP_EOL;
$xmlContent .= ' <name>Default for '.htmlspecialchars($quiz['name'] ?? 'Unknown').'</name>'.PHP_EOL;
$xmlContent .= ' <contextid>'.($quiz['contextid'] ?? '0').'</contextid>'.PHP_EOL;
$xmlContent .= ' <contextlevel>70</contextlevel>'.PHP_EOL;
$xmlContent .= ' <contextinstanceid>'.($quiz['moduleid'] ?? '0').'</contextinstanceid>'.PHP_EOL;
$xmlContent .= ' <info>The default category for questions shared in context "'.htmlspecialchars($quiz['name'] ?? 'Unknown').'".</info>'.PHP_EOL;
$xmlContent .= ' <infoformat>0</infoformat>'.PHP_EOL;
$xmlContent .= ' <stamp>moodle+'.time().'+CATEGORYSTAMP</stamp>'.PHP_EOL;
$xmlContent .= ' <parent>0</parent>'.PHP_EOL;
$xmlContent .= ' <sortorder>999</sortorder>'.PHP_EOL;
$xmlContent .= ' <idnumber>$@NULL@$</idnumber>'.PHP_EOL;
$xmlContent .= ' <questions>'.PHP_EOL;
foreach ($quiz['questions'] as $question) {
$xmlContent .= $quizExport->exportQuestion($question);
}
$xmlContent .= ' </questions>'.PHP_EOL;
$xmlContent .= ' </question_category>'.PHP_EOL;
}
$xmlContent .= '</question_categories>';
file_put_contents($exportDir.'/questions.xml', $xmlContent);
}
/**
* Sets the admin user data.
*/
public function setAdminUserData(int $id, string $username, string $email): void
{
self::$adminUserData = [
'id' => $id,
'contextid' => $id,
'username' => $username,
'idnumber' => '',
'email' => $email,
'phone1' => '',
'phone2' => '',
'institution' => '',
'department' => '',
'address' => '',
'city' => 'London',
'country' => 'GB',
'lastip' => '127.0.0.1',
'picture' => '0',
'description' => '',
'descriptionformat' => 1,
'imagealt' => '$@NULL@$',
'auth' => 'manual',
'firstname' => 'Admin',
'lastname' => 'User',
'confirmed' => 1,
'policyagreed' => 0,
'deleted' => 0,
'lang' => 'en',
'theme' => '',
'timezone' => 99,
'firstaccess' => time(),
'lastaccess' => time() - (60 * 60 * 24 * 7),
'lastlogin' => time() - (60 * 60 * 24 * 2),
'currentlogin' => time(),
'mailformat' => 1,
'maildigest' => 0,
'maildisplay' => 1,
'autosubscribe' => 1,
'trackforums' => 0,
'timecreated' => time(),
'timemodified' => time(),
'trustbitmask' => 0,
'preferences' => [
['name' => 'core_message_migrate_data', 'value' => 1],
['name' => 'auth_manual_passwordupdatetime', 'value' => time()],
['name' => 'email_bounce_count', 'value' => 1],
['name' => 'email_send_count', 'value' => 1],
['name' => 'login_failed_count_since_success', 'value' => 0],
['name' => 'filepicker_recentrepository', 'value' => 5],
['name' => 'filepicker_recentlicense', 'value' => 'unknown'],
],
];
}
/**
* Returns hardcoded data for the admin user.
*/
public static function getAdminUserData(): array
{
return self::$adminUserData;
}
/**
* Export root XML files such as badges, completion, gradebook, etc.
*/
@ -121,104 +221,104 @@ class MoodleExport
$courseEndDate = $courseStartDate + (365 * 24 * 60 * 60);
// Build the XML content for the backup
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<moodle_backup>' . PHP_EOL;
$xmlContent .= ' <information>' . PHP_EOL;
$xmlContent .= ' <name>backup-' . htmlspecialchars($courseInfo['code']) . '.mbz</name>' . PHP_EOL;
$xmlContent .= ' <moodle_version>' . ($version === 3 ? '2021051718' : '2022041900') . '</moodle_version>' . PHP_EOL;
$xmlContent .= ' <moodle_release>' . ($version === 3 ? '3.11.18 (Build: 20231211)' : '4.x version here') . '</moodle_release>' . PHP_EOL;
$xmlContent .= ' <backup_version>' . ($version === 3 ? '2021051700' : '2022041900') . '</backup_version>' . PHP_EOL;
$xmlContent .= ' <backup_release>' . ($version === 3 ? '3.11' : '4.x') . '</backup_release>' . PHP_EOL;
$xmlContent .= ' <backup_date>' . time() . '</backup_date>' . PHP_EOL;
$xmlContent .= ' <mnet_remoteusers>0</mnet_remoteusers>' . PHP_EOL;
$xmlContent .= ' <include_files>1</include_files>' . PHP_EOL;
$xmlContent .= ' <include_file_references_to_external_content>0</include_file_references_to_external_content>' . PHP_EOL;
$xmlContent .= ' <original_wwwroot>' . $wwwRoot . '</original_wwwroot>' . PHP_EOL;
$xmlContent .= ' <original_site_identifier_hash>' . $siteHash . '</original_site_identifier_hash>' . PHP_EOL;
$xmlContent .= ' <original_course_id>' . htmlspecialchars($courseInfo['real_id']) . '</original_course_id>' . PHP_EOL;
$xmlContent .= ' <original_course_format>' . get_lang('Topics') . '</original_course_format>' . PHP_EOL;
$xmlContent .= ' <original_course_fullname>' . htmlspecialchars($courseInfo['title']) . '</original_course_fullname>' . PHP_EOL;
$xmlContent .= ' <original_course_shortname>' . htmlspecialchars($courseInfo['code']) . '</original_course_shortname>' . PHP_EOL;
$xmlContent .= ' <original_course_startdate>' . $courseStartDate . '</original_course_startdate>' . PHP_EOL;
$xmlContent .= ' <original_course_enddate>' . $courseEndDate . '</original_course_enddate>' . PHP_EOL;
$xmlContent .= ' <original_course_contextid>' . $courseInfo['real_id'] . '</original_course_contextid>' . PHP_EOL;
$xmlContent .= ' <original_system_contextid>' . api_get_current_access_url_id() . '</original_system_contextid>' . PHP_EOL;
$xmlContent .= ' <details>' . PHP_EOL;
$xmlContent .= ' <detail backup_id="' . $backupId . '">' . PHP_EOL;
$xmlContent .= ' <type>course</type>' . PHP_EOL;
$xmlContent .= ' <format>moodle2</format>' . PHP_EOL;
$xmlContent .= ' <interactive>1</interactive>' . PHP_EOL;
$xmlContent .= ' <mode>10</mode>' . PHP_EOL;
$xmlContent .= ' <execution>1</execution>' . PHP_EOL;
$xmlContent .= ' <executiontime>0</executiontime>' . PHP_EOL;
$xmlContent .= ' </detail>' . PHP_EOL;
$xmlContent .= ' </details>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<moodle_backup>'.PHP_EOL;
$xmlContent .= ' <information>'.PHP_EOL;
$xmlContent .= ' <name>backup-'.htmlspecialchars($courseInfo['code']).'.mbz</name>'.PHP_EOL;
$xmlContent .= ' <moodle_version>'.($version === 3 ? '2021051718' : '2022041900').'</moodle_version>'.PHP_EOL;
$xmlContent .= ' <moodle_release>'.($version === 3 ? '3.11.18 (Build: 20231211)' : '4.x version here').'</moodle_release>'.PHP_EOL;
$xmlContent .= ' <backup_version>'.($version === 3 ? '2021051700' : '2022041900').'</backup_version>'.PHP_EOL;
$xmlContent .= ' <backup_release>'.($version === 3 ? '3.11' : '4.x').'</backup_release>'.PHP_EOL;
$xmlContent .= ' <backup_date>'.time().'</backup_date>'.PHP_EOL;
$xmlContent .= ' <mnet_remoteusers>0</mnet_remoteusers>'.PHP_EOL;
$xmlContent .= ' <include_files>1</include_files>'.PHP_EOL;
$xmlContent .= ' <include_file_references_to_external_content>0</include_file_references_to_external_content>'.PHP_EOL;
$xmlContent .= ' <original_wwwroot>'.$wwwRoot.'</original_wwwroot>'.PHP_EOL;
$xmlContent .= ' <original_site_identifier_hash>'.$siteHash.'</original_site_identifier_hash>'.PHP_EOL;
$xmlContent .= ' <original_course_id>'.htmlspecialchars($courseInfo['real_id']).'</original_course_id>'.PHP_EOL;
$xmlContent .= ' <original_course_format>'.get_lang('Topics').'</original_course_format>'.PHP_EOL;
$xmlContent .= ' <original_course_fullname>'.htmlspecialchars($courseInfo['title']).'</original_course_fullname>'.PHP_EOL;
$xmlContent .= ' <original_course_shortname>'.htmlspecialchars($courseInfo['code']).'</original_course_shortname>'.PHP_EOL;
$xmlContent .= ' <original_course_startdate>'.$courseStartDate.'</original_course_startdate>'.PHP_EOL;
$xmlContent .= ' <original_course_enddate>'.$courseEndDate.'</original_course_enddate>'.PHP_EOL;
$xmlContent .= ' <original_course_contextid>'.$courseInfo['real_id'].'</original_course_contextid>'.PHP_EOL;
$xmlContent .= ' <original_system_contextid>'.api_get_current_access_url_id().'</original_system_contextid>'.PHP_EOL;
$xmlContent .= ' <details>'.PHP_EOL;
$xmlContent .= ' <detail backup_id="'.$backupId.'">'.PHP_EOL;
$xmlContent .= ' <type>course</type>'.PHP_EOL;
$xmlContent .= ' <format>moodle2</format>'.PHP_EOL;
$xmlContent .= ' <interactive>1</interactive>'.PHP_EOL;
$xmlContent .= ' <mode>10</mode>'.PHP_EOL;
$xmlContent .= ' <execution>1</execution>'.PHP_EOL;
$xmlContent .= ' <executiontime>0</executiontime>'.PHP_EOL;
$xmlContent .= ' </detail>'.PHP_EOL;
$xmlContent .= ' </details>'.PHP_EOL;
// Contents with activities and sections
$xmlContent .= ' <contents>' . PHP_EOL;
$xmlContent .= ' <contents>'.PHP_EOL;
// Export sections dynamically and add them to the XML
$sections = $this->getSections();
if (!empty($sections)) {
$xmlContent .= ' <sections>' . PHP_EOL;
$xmlContent .= ' <sections>'.PHP_EOL;
foreach ($sections as $section) {
$xmlContent .= ' <section>' . PHP_EOL;
$xmlContent .= ' <sectionid>' . $section['id'] . '</sectionid>' . PHP_EOL;
$xmlContent .= ' <title>' . htmlspecialchars($section['name']) . '</title>' . PHP_EOL;
$xmlContent .= ' <directory>sections/section_' . $section['id'] . '</directory>' . PHP_EOL;
$xmlContent .= ' </section>' . PHP_EOL;
$xmlContent .= ' <section>'.PHP_EOL;
$xmlContent .= ' <sectionid>'.$section['id'].'</sectionid>'.PHP_EOL;
$xmlContent .= ' <title>'.htmlspecialchars($section['name']).'</title>'.PHP_EOL;
$xmlContent .= ' <directory>sections/section_'.$section['id'].'</directory>'.PHP_EOL;
$xmlContent .= ' </section>'.PHP_EOL;
}
$xmlContent .= ' </sections>' . PHP_EOL;
$xmlContent .= ' </sections>'.PHP_EOL;
}
$activities = $this->getActivities();
if (!empty($activities)) {
$xmlContent .= ' <activities>' . PHP_EOL;
$xmlContent .= ' <activities>'.PHP_EOL;
foreach ($activities as $activity) {
$xmlContent .= ' <activity>' . PHP_EOL;
$xmlContent .= ' <moduleid>' . $activity['moduleid'] . '</moduleid>' . PHP_EOL;
$xmlContent .= ' <sectionid>' . $activity['sectionid'] . '</sectionid>' . PHP_EOL;
$xmlContent .= ' <modulename>' . htmlspecialchars($activity['modulename']) . '</modulename>' . PHP_EOL;
$xmlContent .= ' <title>' . htmlspecialchars($activity['title']) . '</title>' . PHP_EOL;
$xmlContent .= ' <directory>activities/' . $activity['modulename'] . '_' . $activity['moduleid'] . '</directory>' . PHP_EOL;
$xmlContent .= ' </activity>' . PHP_EOL;
$xmlContent .= ' <activity>'.PHP_EOL;
$xmlContent .= ' <moduleid>'.$activity['moduleid'].'</moduleid>'.PHP_EOL;
$xmlContent .= ' <sectionid>'.$activity['sectionid'].'</sectionid>'.PHP_EOL;
$xmlContent .= ' <modulename>'.htmlspecialchars($activity['modulename']).'</modulename>'.PHP_EOL;
$xmlContent .= ' <title>'.htmlspecialchars($activity['title']).'</title>'.PHP_EOL;
$xmlContent .= ' <directory>activities/'.$activity['modulename'].'_'.$activity['moduleid'].'</directory>'.PHP_EOL;
$xmlContent .= ' </activity>'.PHP_EOL;
}
$xmlContent .= ' </activities>' . PHP_EOL;
$xmlContent .= ' </activities>'.PHP_EOL;
}
// Course directory
$xmlContent .= ' <course>' . PHP_EOL;
$xmlContent .= ' <courseid>' . $courseInfo['real_id'] . '</courseid>' . PHP_EOL;
$xmlContent .= ' <title>' . htmlspecialchars($courseInfo['title']) . '</title>' . PHP_EOL;
$xmlContent .= ' <directory>course</directory>' . PHP_EOL;
$xmlContent .= ' </course>' . PHP_EOL;
$xmlContent .= ' <course>'.PHP_EOL;
$xmlContent .= ' <courseid>'.$courseInfo['real_id'].'</courseid>'.PHP_EOL;
$xmlContent .= ' <title>'.htmlspecialchars($courseInfo['title']).'</title>'.PHP_EOL;
$xmlContent .= ' <directory>course</directory>'.PHP_EOL;
$xmlContent .= ' </course>'.PHP_EOL;
$xmlContent .= ' </contents>' . PHP_EOL;
$xmlContent .= ' </contents>'.PHP_EOL;
// Backup settings
$xmlContent .= ' <settings>' . PHP_EOL;
$xmlContent .= ' <settings>'.PHP_EOL;
$settings = $this->exportBackupSettings($sections, $activities);
foreach ($settings as $setting) {
$xmlContent .= ' <setting>' . PHP_EOL;
$xmlContent .= ' <level>' . htmlspecialchars($setting['level']) . '</level>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($setting['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <value>' . $setting['value'] . '</value>' . PHP_EOL;
$xmlContent .= ' <setting>'.PHP_EOL;
$xmlContent .= ' <level>'.htmlspecialchars($setting['level']).'</level>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($setting['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <value>'.$setting['value'].'</value>'.PHP_EOL;
if (isset($setting['section'])) {
$xmlContent .= ' <section>' . htmlspecialchars($setting['section']) . '</section>' . PHP_EOL;
$xmlContent .= ' <section>'.htmlspecialchars($setting['section']).'</section>'.PHP_EOL;
}
if (isset($setting['activity'])) {
$xmlContent .= ' <activity>' . htmlspecialchars($setting['activity']) . '</activity>' . PHP_EOL;
$xmlContent .= ' <activity>'.htmlspecialchars($setting['activity']).'</activity>'.PHP_EOL;
}
$xmlContent .= ' </setting>' . PHP_EOL;
$xmlContent .= ' </setting>'.PHP_EOL;
}
$xmlContent .= ' </settings>' . PHP_EOL;
$xmlContent .= ' </settings>'.PHP_EOL;
$xmlContent .= ' </information>' . PHP_EOL;
$xmlContent .= ' </information>'.PHP_EOL;
$xmlContent .= '</moodle_backup>';
$xmlFile = $destinationDir . '/moodle_backup.xml';
$xmlFile = $destinationDir.'/moodle_backup.xml';
file_put_contents($xmlFile, $xmlContent);
}
@ -366,7 +466,7 @@ class MoodleExport
private function createMbzFile(string $sourceDir): string
{
$zip = new ZipArchive();
$zipFile = $sourceDir . '.mbz';
$zipFile = $sourceDir.'.mbz';
if ($zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
throw new Exception(get_lang('ErrorCreatingZip'));
@ -383,7 +483,7 @@ class MoodleExport
$relativePath = substr($filePath, strlen($sourceDir) + 1);
if (!$zip->addFile($filePath, $relativePath)) {
throw new Exception(get_lang('ErrorAddingFileToZip') . ": $relativePath");
throw new Exception(get_lang('ErrorAddingFileToZip').": $relativePath");
}
}
}
@ -421,10 +521,10 @@ class MoodleExport
*/
private function exportBadgesXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<badges>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<badges>'.PHP_EOL;
$xmlContent .= '</badges>';
file_put_contents($exportDir . '/badges.xml', $xmlContent);
file_put_contents($exportDir.'/badges.xml', $xmlContent);
}
/**
@ -432,10 +532,10 @@ class MoodleExport
*/
private function exportCompletionXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<completions>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<completions>'.PHP_EOL;
$xmlContent .= '</completions>';
file_put_contents($exportDir . '/completion.xml', $xmlContent);
file_put_contents($exportDir.'/completion.xml', $xmlContent);
}
/**
@ -443,10 +543,10 @@ class MoodleExport
*/
private function exportGradebookXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<gradebook>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<gradebook>'.PHP_EOL;
$xmlContent .= '</gradebook>';
file_put_contents($exportDir . '/gradebook.xml', $xmlContent);
file_put_contents($exportDir.'/gradebook.xml', $xmlContent);
}
/**
@ -454,10 +554,10 @@ class MoodleExport
*/
private function exportGradeHistoryXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<grade_history>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<grade_history>'.PHP_EOL;
$xmlContent .= '</grade_history>';
file_put_contents($exportDir . '/grade_history.xml', $xmlContent);
file_put_contents($exportDir.'/grade_history.xml', $xmlContent);
}
/**
@ -465,10 +565,10 @@ class MoodleExport
*/
private function exportGroupsXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<groups>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<groups>'.PHP_EOL;
$xmlContent .= '</groups>';
file_put_contents($exportDir . '/groups.xml', $xmlContent);
file_put_contents($exportDir.'/groups.xml', $xmlContent);
}
/**
@ -476,47 +576,10 @@ class MoodleExport
*/
private function exportOutcomesXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<outcomes>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<outcomes>'.PHP_EOL;
$xmlContent .= '</outcomes>';
file_put_contents($exportDir . '/outcomes.xml', $xmlContent);
}
/**
* Export questions data to XML file.
*/
public function exportQuestionsXml(array $questionsData, string $exportDir): void
{
$quizExport = new QuizExport($this->course);
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<question_categories>' . PHP_EOL;
foreach ($questionsData as $quiz) {
$categoryId = $quiz['questions'][0]['questioncategoryid'] ?? '0';
$xmlContent .= ' <question_category id="' . $categoryId . '">' . PHP_EOL;
$xmlContent .= ' <name>Default for ' . htmlspecialchars($quiz['name'] ?? 'Unknown') . '</name>' . PHP_EOL;
$xmlContent .= ' <contextid>' . ($quiz['contextid'] ?? '0') . '</contextid>' . PHP_EOL;
$xmlContent .= ' <contextlevel>70</contextlevel>' . PHP_EOL;
$xmlContent .= ' <contextinstanceid>' . ($quiz['moduleid'] ?? '0') . '</contextinstanceid>' . PHP_EOL;
$xmlContent .= ' <info>The default category for questions shared in context "' . htmlspecialchars($quiz['name'] ?? 'Unknown') . '".</info>' . PHP_EOL;
$xmlContent .= ' <infoformat>0</infoformat>' . PHP_EOL;
$xmlContent .= ' <stamp>moodle+' . time() . '+CATEGORYSTAMP</stamp>' . PHP_EOL;
$xmlContent .= ' <parent>0</parent>' . PHP_EOL;
$xmlContent .= ' <sortorder>999</sortorder>' . PHP_EOL;
$xmlContent .= ' <idnumber>$@NULL@$</idnumber>' . PHP_EOL;
$xmlContent .= ' <questions>' . PHP_EOL;
foreach ($quiz['questions'] as $question) {
$xmlContent .= $quizExport->exportQuestion($question);
}
$xmlContent .= ' </questions>' . PHP_EOL;
$xmlContent .= ' </question_category>' . PHP_EOL;
}
$xmlContent .= '</question_categories>';
file_put_contents($exportDir . '/questions.xml', $xmlContent);
file_put_contents($exportDir.'/outcomes.xml', $xmlContent);
}
/**
@ -524,19 +587,19 @@ class MoodleExport
*/
private function exportRolesXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<roles_definition>' . PHP_EOL;
$xmlContent .= ' <role id="5">' . PHP_EOL;
$xmlContent .= ' <name></name>' . PHP_EOL;
$xmlContent .= ' <shortname>student</shortname>' . PHP_EOL;
$xmlContent .= ' <nameincourse>$@NULL@$</nameincourse>' . PHP_EOL;
$xmlContent .= ' <description></description>' . PHP_EOL;
$xmlContent .= ' <sortorder>5</sortorder>' . PHP_EOL;
$xmlContent .= ' <archetype>student</archetype>' . PHP_EOL;
$xmlContent .= ' </role>' . PHP_EOL;
$xmlContent .= '</roles_definition>' . PHP_EOL;
file_put_contents($exportDir . '/roles.xml', $xmlContent);
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<roles_definition>'.PHP_EOL;
$xmlContent .= ' <role id="5">'.PHP_EOL;
$xmlContent .= ' <name></name>'.PHP_EOL;
$xmlContent .= ' <shortname>student</shortname>'.PHP_EOL;
$xmlContent .= ' <nameincourse>$@NULL@$</nameincourse>'.PHP_EOL;
$xmlContent .= ' <description></description>'.PHP_EOL;
$xmlContent .= ' <sortorder>5</sortorder>'.PHP_EOL;
$xmlContent .= ' <archetype>student</archetype>'.PHP_EOL;
$xmlContent .= ' </role>'.PHP_EOL;
$xmlContent .= '</roles_definition>'.PHP_EOL;
file_put_contents($exportDir.'/roles.xml', $xmlContent);
}
/**
@ -544,76 +607,10 @@ class MoodleExport
*/
private function exportScalesXml(string $exportDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<scales>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<scales>'.PHP_EOL;
$xmlContent .= '</scales>';
file_put_contents($exportDir . '/scales.xml', $xmlContent);
}
/**
* Sets the admin user data.
*/
public function setAdminUserData(int $id, string $username, string $email): void
{
self::$adminUserData = [
'id' => $id,
'contextid' => $id,
'username' => $username,
'idnumber' => '',
'email' => $email,
'phone1' => '',
'phone2' => '',
'institution' => '',
'department' => '',
'address' => '',
'city' => 'London',
'country' => 'GB',
'lastip' => '127.0.0.1',
'picture' => '0',
'description' => '',
'descriptionformat' => 1,
'imagealt' => '$@NULL@$',
'auth' => 'manual',
'firstname' => 'Admin',
'lastname' => 'User',
'confirmed' => 1,
'policyagreed' => 0,
'deleted' => 0,
'lang' => 'en',
'theme' => '',
'timezone' => 99,
'firstaccess' => time(),
'lastaccess' => time() - (60 * 60 * 24 * 7),
'lastlogin' => time() - (60 * 60 * 24 * 2),
'currentlogin' => time(),
'mailformat' => 1,
'maildigest' => 0,
'maildisplay' => 1,
'autosubscribe' => 1,
'trackforums' => 0,
'timecreated' => time(),
'timemodified' => time(),
'trustbitmask' => 0,
'preferences' => [
['name' => 'core_message_migrate_data', 'value' => 1],
['name' => 'auth_manual_passwordupdatetime', 'value' => time()],
['name' => 'email_bounce_count', 'value' => 1],
['name' => 'email_send_count', 'value' => 1],
['name' => 'login_failed_count_since_success', 'value' => 0],
['name' => 'filepicker_recentrepository', 'value' => 5],
['name' => 'filepicker_recentlicense', 'value' => 'unknown'],
],
];
}
/**
* Returns hardcoded data for the admin user.
*
* @return array
*/
public static function getAdminUserData(): array
{
return self::$adminUserData;
file_put_contents($exportDir.'/scales.xml', $xmlContent);
}
/**
@ -623,71 +620,71 @@ class MoodleExport
{
$adminData = self::getAdminUserData();
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<users>' . PHP_EOL;
$xmlContent .= ' <user id="' . $adminData['id'] . '" contextid="' . $adminData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <username>' . $adminData['username'] . '</username>' . PHP_EOL;
$xmlContent .= ' <idnumber>' . $adminData['idnumber'] . '</idnumber>' . PHP_EOL;
$xmlContent .= ' <email>' . $adminData['email'] . '</email>' . PHP_EOL;
$xmlContent .= ' <phone1>' . $adminData['phone1'] . '</phone1>' . PHP_EOL;
$xmlContent .= ' <phone2>' . $adminData['phone2'] . '</phone2>' . PHP_EOL;
$xmlContent .= ' <institution>' . $adminData['institution'] . '</institution>' . PHP_EOL;
$xmlContent .= ' <department>' . $adminData['department'] . '</department>' . PHP_EOL;
$xmlContent .= ' <address>' . $adminData['address'] . '</address>' . PHP_EOL;
$xmlContent .= ' <city>' . $adminData['city'] . '</city>' . PHP_EOL;
$xmlContent .= ' <country>' . $adminData['country'] . '</country>' . PHP_EOL;
$xmlContent .= ' <lastip>' . $adminData['lastip'] . '</lastip>' . PHP_EOL;
$xmlContent .= ' <picture>' . $adminData['picture'] . '</picture>' . PHP_EOL;
$xmlContent .= ' <description>' . $adminData['description'] . '</description>' . PHP_EOL;
$xmlContent .= ' <descriptionformat>' . $adminData['descriptionformat'] . '</descriptionformat>' . PHP_EOL;
$xmlContent .= ' <imagealt>' . $adminData['imagealt'] . '</imagealt>' . PHP_EOL;
$xmlContent .= ' <auth>' . $adminData['auth'] . '</auth>' . PHP_EOL;
$xmlContent .= ' <firstname>' . $adminData['firstname'] . '</firstname>' . PHP_EOL;
$xmlContent .= ' <lastname>' . $adminData['lastname'] . '</lastname>' . PHP_EOL;
$xmlContent .= ' <confirmed>' . $adminData['confirmed'] . '</confirmed>' . PHP_EOL;
$xmlContent .= ' <policyagreed>' . $adminData['policyagreed'] . '</policyagreed>' . PHP_EOL;
$xmlContent .= ' <deleted>' . $adminData['deleted'] . '</deleted>' . PHP_EOL;
$xmlContent .= ' <lang>' . $adminData['lang'] . '</lang>' . PHP_EOL;
$xmlContent .= ' <theme>' . $adminData['theme'] . '</theme>' . PHP_EOL;
$xmlContent .= ' <timezone>' . $adminData['timezone'] . '</timezone>' . PHP_EOL;
$xmlContent .= ' <firstaccess>' . $adminData['firstaccess'] . '</firstaccess>' . PHP_EOL;
$xmlContent .= ' <lastaccess>' . $adminData['lastaccess'] . '</lastaccess>' . PHP_EOL;
$xmlContent .= ' <lastlogin>' . $adminData['lastlogin'] . '</lastlogin>' . PHP_EOL;
$xmlContent .= ' <currentlogin>' . $adminData['currentlogin'] . '</currentlogin>' . PHP_EOL;
$xmlContent .= ' <mailformat>' . $adminData['mailformat'] . '</mailformat>' . PHP_EOL;
$xmlContent .= ' <maildigest>' . $adminData['maildigest'] . '</maildigest>' . PHP_EOL;
$xmlContent .= ' <maildisplay>' . $adminData['maildisplay'] . '</maildisplay>' . PHP_EOL;
$xmlContent .= ' <autosubscribe>' . $adminData['autosubscribe'] . '</autosubscribe>' . PHP_EOL;
$xmlContent .= ' <trackforums>' . $adminData['trackforums'] . '</trackforums>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . $adminData['timecreated'] . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $adminData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <trustbitmask>' . $adminData['trustbitmask'] . '</trustbitmask>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<users>'.PHP_EOL;
$xmlContent .= ' <user id="'.$adminData['id'].'" contextid="'.$adminData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <username>'.$adminData['username'].'</username>'.PHP_EOL;
$xmlContent .= ' <idnumber>'.$adminData['idnumber'].'</idnumber>'.PHP_EOL;
$xmlContent .= ' <email>'.$adminData['email'].'</email>'.PHP_EOL;
$xmlContent .= ' <phone1>'.$adminData['phone1'].'</phone1>'.PHP_EOL;
$xmlContent .= ' <phone2>'.$adminData['phone2'].'</phone2>'.PHP_EOL;
$xmlContent .= ' <institution>'.$adminData['institution'].'</institution>'.PHP_EOL;
$xmlContent .= ' <department>'.$adminData['department'].'</department>'.PHP_EOL;
$xmlContent .= ' <address>'.$adminData['address'].'</address>'.PHP_EOL;
$xmlContent .= ' <city>'.$adminData['city'].'</city>'.PHP_EOL;
$xmlContent .= ' <country>'.$adminData['country'].'</country>'.PHP_EOL;
$xmlContent .= ' <lastip>'.$adminData['lastip'].'</lastip>'.PHP_EOL;
$xmlContent .= ' <picture>'.$adminData['picture'].'</picture>'.PHP_EOL;
$xmlContent .= ' <description>'.$adminData['description'].'</description>'.PHP_EOL;
$xmlContent .= ' <descriptionformat>'.$adminData['descriptionformat'].'</descriptionformat>'.PHP_EOL;
$xmlContent .= ' <imagealt>'.$adminData['imagealt'].'</imagealt>'.PHP_EOL;
$xmlContent .= ' <auth>'.$adminData['auth'].'</auth>'.PHP_EOL;
$xmlContent .= ' <firstname>'.$adminData['firstname'].'</firstname>'.PHP_EOL;
$xmlContent .= ' <lastname>'.$adminData['lastname'].'</lastname>'.PHP_EOL;
$xmlContent .= ' <confirmed>'.$adminData['confirmed'].'</confirmed>'.PHP_EOL;
$xmlContent .= ' <policyagreed>'.$adminData['policyagreed'].'</policyagreed>'.PHP_EOL;
$xmlContent .= ' <deleted>'.$adminData['deleted'].'</deleted>'.PHP_EOL;
$xmlContent .= ' <lang>'.$adminData['lang'].'</lang>'.PHP_EOL;
$xmlContent .= ' <theme>'.$adminData['theme'].'</theme>'.PHP_EOL;
$xmlContent .= ' <timezone>'.$adminData['timezone'].'</timezone>'.PHP_EOL;
$xmlContent .= ' <firstaccess>'.$adminData['firstaccess'].'</firstaccess>'.PHP_EOL;
$xmlContent .= ' <lastaccess>'.$adminData['lastaccess'].'</lastaccess>'.PHP_EOL;
$xmlContent .= ' <lastlogin>'.$adminData['lastlogin'].'</lastlogin>'.PHP_EOL;
$xmlContent .= ' <currentlogin>'.$adminData['currentlogin'].'</currentlogin>'.PHP_EOL;
$xmlContent .= ' <mailformat>'.$adminData['mailformat'].'</mailformat>'.PHP_EOL;
$xmlContent .= ' <maildigest>'.$adminData['maildigest'].'</maildigest>'.PHP_EOL;
$xmlContent .= ' <maildisplay>'.$adminData['maildisplay'].'</maildisplay>'.PHP_EOL;
$xmlContent .= ' <autosubscribe>'.$adminData['autosubscribe'].'</autosubscribe>'.PHP_EOL;
$xmlContent .= ' <trackforums>'.$adminData['trackforums'].'</trackforums>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.$adminData['timecreated'].'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$adminData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' <trustbitmask>'.$adminData['trustbitmask'].'</trustbitmask>'.PHP_EOL;
// Preferences
if (isset($adminData['preferences']) && is_array($adminData['preferences'])) {
$xmlContent .= ' <preferences>' . PHP_EOL;
$xmlContent .= ' <preferences>'.PHP_EOL;
foreach ($adminData['preferences'] as $preference) {
$xmlContent .= ' <preference>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($preference['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <value>' . htmlspecialchars($preference['value']) . '</value>' . PHP_EOL;
$xmlContent .= ' </preference>' . PHP_EOL;
$xmlContent .= ' <preference>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($preference['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <value>'.htmlspecialchars($preference['value']).'</value>'.PHP_EOL;
$xmlContent .= ' </preference>'.PHP_EOL;
}
$xmlContent .= ' </preferences>' . PHP_EOL;
$xmlContent .= ' </preferences>'.PHP_EOL;
} else {
$xmlContent .= ' <preferences></preferences>' . PHP_EOL;
$xmlContent .= ' <preferences></preferences>'.PHP_EOL;
}
// Roles (empty for now)
$xmlContent .= ' <roles>' . PHP_EOL;
$xmlContent .= ' <role_overrides></role_overrides>' . PHP_EOL;
$xmlContent .= ' <role_assignments></role_assignments>' . PHP_EOL;
$xmlContent .= ' </roles>' . PHP_EOL;
$xmlContent .= ' <roles>'.PHP_EOL;
$xmlContent .= ' <role_overrides></role_overrides>'.PHP_EOL;
$xmlContent .= ' <role_assignments></role_assignments>'.PHP_EOL;
$xmlContent .= ' </roles>'.PHP_EOL;
$xmlContent .= ' </user>' . PHP_EOL;
$xmlContent .= ' </user>'.PHP_EOL;
$xmlContent .= '</users>';
// Save the content to the users.xml file
file_put_contents($exportDir . '/users.xml', $xmlContent);
file_put_contents($exportDir.'/users.xml', $xmlContent);
}
/**
@ -697,7 +694,7 @@ class MoodleExport
{
// root-level settings
$settings = [
['level' => 'root', 'name' => 'filename', 'value' => 'backup-moodle-course-' . time() . '.mbz'],
['level' => 'root', 'name' => 'filename', 'value' => 'backup-moodle-course-'.time().'.mbz'],
['level' => 'root', 'name' => 'imscc11', 'value' => '0'],
['level' => 'root', 'name' => 'users', 'value' => '1'],
['level' => 'root', 'name' => 'anonymize', 'value' => '0'],
@ -724,14 +721,14 @@ class MoodleExport
foreach ($sections as $section) {
$settings[] = [
'level' => 'section',
'section' => 'section_' . $section['id'],
'name' => 'section_' . $section['id'] . '_included',
'section' => 'section_'.$section['id'],
'name' => 'section_'.$section['id'].'_included',
'value' => '1',
];
$settings[] = [
'level' => 'section',
'section' => 'section_' . $section['id'],
'name' => 'section_' . $section['id'] . '_userinfo',
'section' => 'section_'.$section['id'],
'name' => 'section_'.$section['id'].'_userinfo',
'value' => '1',
];
}
@ -740,14 +737,14 @@ class MoodleExport
foreach ($activities as $activity) {
$settings[] = [
'level' => 'activity',
'activity' => $activity['modulename'] . '_' . $activity['moduleid'],
'name' => $activity['modulename'] . '_' . $activity['moduleid'] . '_included',
'activity' => $activity['modulename'].'_'.$activity['moduleid'],
'name' => $activity['modulename'].'_'.$activity['moduleid'].'_included',
'value' => '1',
];
$settings[] = [
'level' => 'activity',
'activity' => $activity['modulename'] . '_' . $activity['moduleid'],
'name' => $activity['modulename'] . '_' . $activity['moduleid'] . '_userinfo',
'activity' => $activity['modulename'].'_'.$activity['moduleid'],
'name' => $activity['modulename'].'_'.$activity['moduleid'].'_userinfo',
'value' => '1',
];
}

@ -14,10 +14,10 @@ class PageExport extends ActivityExport
/**
* Export a page to the specified directory.
*
* @param int $activityId The ID of the page.
* @param string $exportDir The directory where the page will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the page.
* @param string $exportDir The directory where the page will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -39,30 +39,6 @@ class PageExport extends ActivityExport
$this->createCalendarXml($pageData, $pageDir);
}
/**
* Create the XML file for the page.
*/
private function createPageXml(array $pageData, string $pageDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $pageData['id'] . '" moduleid="' . $pageData['moduleid'] . '" modulename="page" contextid="' . $pageData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <page id="' . $pageData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($pageData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro>' . htmlspecialchars($pageData['intro']) . '</intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <content>' . htmlspecialchars($pageData['content']) . '</content>' . PHP_EOL;
$xmlContent .= ' <contentformat>1</contentformat>' . PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>' . PHP_EOL;
$xmlContent .= ' <display>5</display>' . PHP_EOL;
$xmlContent .= ' <displayoptions>a:3:{s:12:"printheading";s:1:"1";s:10:"printintro";s:1:"0";s:17:"printlastmodified";s:1:"1";}</displayoptions>' . PHP_EOL;
$xmlContent .= ' <revision>1</revision>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $pageData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' </page>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('page', $xmlContent, $pageDir);
}
/**
* Get page data dynamically from the course.
*/
@ -95,13 +71,37 @@ class PageExport extends ActivityExport
return null;
}
/**
* Create the XML file for the page.
*/
private function createPageXml(array $pageData, string $pageDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$pageData['id'].'" moduleid="'.$pageData['moduleid'].'" modulename="page" contextid="'.$pageData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <page id="'.$pageData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($pageData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro>'.htmlspecialchars($pageData['intro']).'</intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <content>'.htmlspecialchars($pageData['content']).'</content>'.PHP_EOL;
$xmlContent .= ' <contentformat>1</contentformat>'.PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>'.PHP_EOL;
$xmlContent .= ' <display>5</display>'.PHP_EOL;
$xmlContent .= ' <displayoptions>a:3:{s:12:"printheading";s:1:"1";s:10:"printintro";s:1:"0";s:17:"printlastmodified";s:1:"1";}</displayoptions>'.PHP_EOL;
$xmlContent .= ' <revision>1</revision>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$pageData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' </page>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('page', $xmlContent, $pageDir);
}
/**
* Retrieves the content of the page.
*/
private function getPageContent(object $page): string
{
if ($page->file_type === 'file') {
return file_get_contents($this->course->path . $page->path);
return file_get_contents($this->course->path.$page->path);
}
return '';

@ -17,10 +17,10 @@ class QuizExport extends ActivityExport
/**
* Export a quiz to the specified directory.
*
* @param int $activityId The ID of the quiz.
* @param string $exportDir The directory where the quiz will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the quiz.
* @param string $exportDir The directory where the quiz will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -114,6 +114,54 @@ class QuizExport extends ActivityExport
return [];
}
/**
* Exports a question in XML format.
*/
public function exportQuestion(array $question): string
{
$xmlContent = ' <question id="'.($question['id'] ?? '0').'">'.PHP_EOL;
$xmlContent .= ' <parent>0</parent>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($question['questiontext'] ?? 'No question text').'</name>'.PHP_EOL;
$xmlContent .= ' <questiontext>'.htmlspecialchars($question['questiontext'] ?? 'No question text').'</questiontext>'.PHP_EOL;
$xmlContent .= ' <questiontextformat>1</questiontextformat>'.PHP_EOL;
$xmlContent .= ' <generalfeedback></generalfeedback>'.PHP_EOL;
$xmlContent .= ' <generalfeedbackformat>1</generalfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <defaultmark>'.($question['maxmark'] ?? '0').'</defaultmark>'.PHP_EOL;
$xmlContent .= ' <penalty>0.3333333</penalty>'.PHP_EOL;
$xmlContent .= ' <qtype>'.htmlspecialchars(str_replace('_nosingle', '', $question['qtype']) ?? 'unknown').'</qtype>'.PHP_EOL;
$xmlContent .= ' <length>1</length>'.PHP_EOL;
$xmlContent .= ' <stamp>moodle+'.time().'+QUESTIONSTAMP</stamp>'.PHP_EOL;
$xmlContent .= ' <version>moodle+'.time().'+VERSIONSTAMP</version>'.PHP_EOL;
$xmlContent .= ' <hidden>0</hidden>'.PHP_EOL;
$xmlContent .= ' <timecreated>'.time().'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.time().'</timemodified>'.PHP_EOL;
$xmlContent .= ' <createdby>2</createdby>'.PHP_EOL;
$xmlContent .= ' <modifiedby>2</modifiedby>'.PHP_EOL;
// Add question type-specific content
switch ($question['qtype']) {
case 'multichoice':
$xmlContent .= $this->exportMultichoiceQuestion($question);
break;
case 'multichoice_nosingle':
$xmlContent .= $this->exportMultichoiceNosingleQuestion($question);
break;
case 'truefalse':
$xmlContent .= $this->exportTrueFalseQuestion($question);
break;
case 'shortanswer':
$xmlContent .= $this->exportShortAnswerQuestion($question);
break;
case 'match':
$xmlContent .= $this->exportMatchQuestion($question);
break;
}
$xmlContent .= ' </question>'.PHP_EOL;
return $xmlContent;
}
/**
* Retrieves the questions for a specific quiz.
*/
@ -173,6 +221,7 @@ class QuizExport extends ActivityExport
}
}
}
return $answers;
}
@ -202,186 +251,138 @@ class QuizExport extends ActivityExport
*/
private function createQuizXml(array $quizData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $quizData['id'] . '" moduleid="' . $quizData['moduleid'] . '" modulename="quiz" contextid="' . $quizData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <quiz id="' . $quizData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($quizData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro>' . htmlspecialchars($quizData['intro']) . '</intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <timeopen>' . ($quizData['timeopen'] ?? 0) . '</timeopen>' . PHP_EOL;
$xmlContent .= ' <timeclose>' . ($quizData['timeclose'] ?? 0) . '</timeclose>' . PHP_EOL;
$xmlContent .= ' <timelimit>' . ($quizData['timelimit'] ?? 0) . '</timelimit>' . PHP_EOL;
$xmlContent .= ' <overduehandling>' . ($quizData['overduehandling'] ?? 'autosubmit') . '</overduehandling>' . PHP_EOL;
$xmlContent .= ' <graceperiod>' . ($quizData['graceperiod'] ?? 0) . '</graceperiod>' . PHP_EOL;
$xmlContent .= ' <preferredbehaviour>' . htmlspecialchars($quizData['preferredbehaviour']) . '</preferredbehaviour>' . PHP_EOL;
$xmlContent .= ' <canredoquestions>' . ($quizData['canredoquestions'] ?? 0) . '</canredoquestions>' . PHP_EOL;
$xmlContent .= ' <attempts_number>' . ($quizData['attempts_number'] ?? 0) . '</attempts_number>' . PHP_EOL;
$xmlContent .= ' <attemptonlast>' . ($quizData['attemptonlast'] ?? 0) . '</attemptonlast>' . PHP_EOL;
$xmlContent .= ' <grademethod>' . $quizData['grademethod'] . '</grademethod>' . PHP_EOL;
$xmlContent .= ' <decimalpoints>' . $quizData['decimalpoints'] . '</decimalpoints>' . PHP_EOL;
$xmlContent .= ' <questiondecimalpoints>' . ($quizData['questiondecimalpoints'] ?? -1) . '</questiondecimalpoints>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$quizData['id'].'" moduleid="'.$quizData['moduleid'].'" modulename="quiz" contextid="'.$quizData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <quiz id="'.$quizData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($quizData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro>'.htmlspecialchars($quizData['intro']).'</intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <timeopen>'.($quizData['timeopen'] ?? 0).'</timeopen>'.PHP_EOL;
$xmlContent .= ' <timeclose>'.($quizData['timeclose'] ?? 0).'</timeclose>'.PHP_EOL;
$xmlContent .= ' <timelimit>'.($quizData['timelimit'] ?? 0).'</timelimit>'.PHP_EOL;
$xmlContent .= ' <overduehandling>'.($quizData['overduehandling'] ?? 'autosubmit').'</overduehandling>'.PHP_EOL;
$xmlContent .= ' <graceperiod>'.($quizData['graceperiod'] ?? 0).'</graceperiod>'.PHP_EOL;
$xmlContent .= ' <preferredbehaviour>'.htmlspecialchars($quizData['preferredbehaviour']).'</preferredbehaviour>'.PHP_EOL;
$xmlContent .= ' <canredoquestions>'.($quizData['canredoquestions'] ?? 0).'</canredoquestions>'.PHP_EOL;
$xmlContent .= ' <attempts_number>'.($quizData['attempts_number'] ?? 0).'</attempts_number>'.PHP_EOL;
$xmlContent .= ' <attemptonlast>'.($quizData['attemptonlast'] ?? 0).'</attemptonlast>'.PHP_EOL;
$xmlContent .= ' <grademethod>'.$quizData['grademethod'].'</grademethod>'.PHP_EOL;
$xmlContent .= ' <decimalpoints>'.$quizData['decimalpoints'].'</decimalpoints>'.PHP_EOL;
$xmlContent .= ' <questiondecimalpoints>'.($quizData['questiondecimalpoints'] ?? -1).'</questiondecimalpoints>'.PHP_EOL;
// Review options
$xmlContent .= ' <reviewattempt>' . ($quizData['reviewattempt'] ?? 69888) . '</reviewattempt>' . PHP_EOL;
$xmlContent .= ' <reviewcorrectness>' . ($quizData['reviewcorrectness'] ?? 4352) . '</reviewcorrectness>' . PHP_EOL;
$xmlContent .= ' <reviewmarks>' . ($quizData['reviewmarks'] ?? 4352) . '</reviewmarks>' . PHP_EOL;
$xmlContent .= ' <reviewspecificfeedback>' . ($quizData['reviewspecificfeedback'] ?? 4352) . '</reviewspecificfeedback>' . PHP_EOL;
$xmlContent .= ' <reviewgeneralfeedback>' . ($quizData['reviewgeneralfeedback'] ?? 4352) . '</reviewgeneralfeedback>' . PHP_EOL;
$xmlContent .= ' <reviewrightanswer>' . ($quizData['reviewrightanswer'] ?? 4352) . '</reviewrightanswer>' . PHP_EOL;
$xmlContent .= ' <reviewoverallfeedback>' . ($quizData['reviewoverallfeedback'] ?? 4352) . '</reviewoverallfeedback>' . PHP_EOL;
$xmlContent .= ' <reviewattempt>'.($quizData['reviewattempt'] ?? 69888).'</reviewattempt>'.PHP_EOL;
$xmlContent .= ' <reviewcorrectness>'.($quizData['reviewcorrectness'] ?? 4352).'</reviewcorrectness>'.PHP_EOL;
$xmlContent .= ' <reviewmarks>'.($quizData['reviewmarks'] ?? 4352).'</reviewmarks>'.PHP_EOL;
$xmlContent .= ' <reviewspecificfeedback>'.($quizData['reviewspecificfeedback'] ?? 4352).'</reviewspecificfeedback>'.PHP_EOL;
$xmlContent .= ' <reviewgeneralfeedback>'.($quizData['reviewgeneralfeedback'] ?? 4352).'</reviewgeneralfeedback>'.PHP_EOL;
$xmlContent .= ' <reviewrightanswer>'.($quizData['reviewrightanswer'] ?? 4352).'</reviewrightanswer>'.PHP_EOL;
$xmlContent .= ' <reviewoverallfeedback>'.($quizData['reviewoverallfeedback'] ?? 4352).'</reviewoverallfeedback>'.PHP_EOL;
// Navigation and presentation settings
$xmlContent .= ' <questionsperpage>' . $quizData['questionsperpage'] . '</questionsperpage>' . PHP_EOL;
$xmlContent .= ' <navmethod>' . htmlspecialchars($quizData['navmethod']) . '</navmethod>' . PHP_EOL;
$xmlContent .= ' <shuffleanswers>' . $quizData['shuffleanswers'] . '</shuffleanswers>' . PHP_EOL;
$xmlContent .= ' <sumgrades>' . $quizData['sumgrades'] . '</sumgrades>' . PHP_EOL;
$xmlContent .= ' <grade>' . $quizData['grade'] . '</grade>' . PHP_EOL;
$xmlContent .= ' <questionsperpage>'.$quizData['questionsperpage'].'</questionsperpage>'.PHP_EOL;
$xmlContent .= ' <navmethod>'.htmlspecialchars($quizData['navmethod']).'</navmethod>'.PHP_EOL;
$xmlContent .= ' <shuffleanswers>'.$quizData['shuffleanswers'].'</shuffleanswers>'.PHP_EOL;
$xmlContent .= ' <sumgrades>'.$quizData['sumgrades'].'</sumgrades>'.PHP_EOL;
$xmlContent .= ' <grade>'.$quizData['grade'].'</grade>'.PHP_EOL;
// Timing and security
$xmlContent .= ' <timecreated>' . ($quizData['timecreated'] ?? time()) . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . ($quizData['timemodified'] ?? time()) . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <password>' . (isset($quizData['password']) ? htmlspecialchars($quizData['password']) : '') . '</password>' . PHP_EOL;
$xmlContent .= ' <subnet>' . (isset($quizData['subnet']) ? htmlspecialchars($quizData['subnet']) : '') . '</subnet>' . PHP_EOL;
$xmlContent .= ' <browsersecurity>' . (isset($quizData['browsersecurity']) ? htmlspecialchars($quizData['browsersecurity']) : '-') . '</browsersecurity>' . PHP_EOL;
$xmlContent .= ' <delay1>' . ($quizData['delay1'] ?? 0) . '</delay1>' . PHP_EOL;
$xmlContent .= ' <delay2>' . ($quizData['delay2'] ?? 0) . '</delay2>' . PHP_EOL;
$xmlContent .= ' <timecreated>'.($quizData['timecreated'] ?? time()).'</timecreated>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.($quizData['timemodified'] ?? time()).'</timemodified>'.PHP_EOL;
$xmlContent .= ' <password>'.(isset($quizData['password']) ? htmlspecialchars($quizData['password']) : '').'</password>'.PHP_EOL;
$xmlContent .= ' <subnet>'.(isset($quizData['subnet']) ? htmlspecialchars($quizData['subnet']) : '').'</subnet>'.PHP_EOL;
$xmlContent .= ' <browsersecurity>'.(isset($quizData['browsersecurity']) ? htmlspecialchars($quizData['browsersecurity']) : '-').'</browsersecurity>'.PHP_EOL;
$xmlContent .= ' <delay1>'.($quizData['delay1'] ?? 0).'</delay1>'.PHP_EOL;
$xmlContent .= ' <delay2>'.($quizData['delay2'] ?? 0).'</delay2>'.PHP_EOL;
// Additional options
$xmlContent .= ' <showuserpicture>' . ($quizData['showuserpicture'] ?? 0) . '</showuserpicture>' . PHP_EOL;
$xmlContent .= ' <showblocks>' . ($quizData['showblocks'] ?? 0) . '</showblocks>' . PHP_EOL;
$xmlContent .= ' <completionattemptsexhausted>' . ($quizData['completionattemptsexhausted'] ?? 0) . '</completionattemptsexhausted>' . PHP_EOL;
$xmlContent .= ' <completionpass>' . ($quizData['completionpass'] ?? 0) . '</completionpass>' . PHP_EOL;
$xmlContent .= ' <completionminattempts>' . ($quizData['completionminattempts'] ?? 0) . '</completionminattempts>' . PHP_EOL;
$xmlContent .= ' <allowofflineattempts>' . ($quizData['allowofflineattempts'] ?? 0) . '</allowofflineattempts>' . PHP_EOL;
$xmlContent .= ' <showuserpicture>'.($quizData['showuserpicture'] ?? 0).'</showuserpicture>'.PHP_EOL;
$xmlContent .= ' <showblocks>'.($quizData['showblocks'] ?? 0).'</showblocks>'.PHP_EOL;
$xmlContent .= ' <completionattemptsexhausted>'.($quizData['completionattemptsexhausted'] ?? 0).'</completionattemptsexhausted>'.PHP_EOL;
$xmlContent .= ' <completionpass>'.($quizData['completionpass'] ?? 0).'</completionpass>'.PHP_EOL;
$xmlContent .= ' <completionminattempts>'.($quizData['completionminattempts'] ?? 0).'</completionminattempts>'.PHP_EOL;
$xmlContent .= ' <allowofflineattempts>'.($quizData['allowofflineattempts'] ?? 0).'</allowofflineattempts>'.PHP_EOL;
// Subplugin, if applicable
$xmlContent .= ' <subplugin_quizaccess_seb_quiz>' . PHP_EOL;
$xmlContent .= ' </subplugin_quizaccess_seb_quiz>' . PHP_EOL;
$xmlContent .= ' <subplugin_quizaccess_seb_quiz>'.PHP_EOL;
$xmlContent .= ' </subplugin_quizaccess_seb_quiz>'.PHP_EOL;
// Add question instances
$xmlContent .= ' <question_instances>' . PHP_EOL;
$xmlContent .= ' <question_instances>'.PHP_EOL;
foreach ($quizData['questions'] as $question) {
$xmlContent .= ' <question_instance id="' . $question['id'] . '">' . PHP_EOL;
$xmlContent .= ' <slot>' . $question['id'] . '</slot>' . PHP_EOL;
$xmlContent .= ' <page>1</page>' . PHP_EOL;
$xmlContent .= ' <requireprevious>0</requireprevious>' . PHP_EOL;
$xmlContent .= ' <questionid>' . $question['id'] . '</questionid>' . PHP_EOL;
$xmlContent .= ' <questioncategoryid>' . $question['questioncategoryid'] . '</questioncategoryid>' . PHP_EOL;
$xmlContent .= ' <includingsubcategories>$@NULL@$</includingsubcategories>' . PHP_EOL;
$xmlContent .= ' <maxmark>' . $question['maxmark'] . '</maxmark>' . PHP_EOL;
$xmlContent .= ' </question_instance>' . PHP_EOL;
$xmlContent .= ' <question_instance id="'.$question['id'].'">'.PHP_EOL;
$xmlContent .= ' <slot>'.$question['id'].'</slot>'.PHP_EOL;
$xmlContent .= ' <page>1</page>'.PHP_EOL;
$xmlContent .= ' <requireprevious>0</requireprevious>'.PHP_EOL;
$xmlContent .= ' <questionid>'.$question['id'].'</questionid>'.PHP_EOL;
$xmlContent .= ' <questioncategoryid>'.$question['questioncategoryid'].'</questioncategoryid>'.PHP_EOL;
$xmlContent .= ' <includingsubcategories>$@NULL@$</includingsubcategories>'.PHP_EOL;
$xmlContent .= ' <maxmark>'.$question['maxmark'].'</maxmark>'.PHP_EOL;
$xmlContent .= ' </question_instance>'.PHP_EOL;
}
$xmlContent .= ' </question_instances>' . PHP_EOL;
$xmlContent .= ' </question_instances>'.PHP_EOL;
// Quiz sections
$xmlContent .= ' <sections>' . PHP_EOL;
$xmlContent .= ' <section id="'.$quizData['id'].'">' . PHP_EOL;
$xmlContent .= ' <firstslot>1</firstslot>' . PHP_EOL;
$xmlContent .= ' <shufflequestions>0</shufflequestions>' . PHP_EOL;
$xmlContent .= ' </section>' . PHP_EOL;
$xmlContent .= ' </sections>' . PHP_EOL;
$xmlContent .= ' <sections>'.PHP_EOL;
$xmlContent .= ' <section id="'.$quizData['id'].'">'.PHP_EOL;
$xmlContent .= ' <firstslot>1</firstslot>'.PHP_EOL;
$xmlContent .= ' <shufflequestions>0</shufflequestions>'.PHP_EOL;
$xmlContent .= ' </section>'.PHP_EOL;
$xmlContent .= ' </sections>'.PHP_EOL;
// Add feedbacks
$xmlContent .= ' <feedbacks>' . PHP_EOL;
$xmlContent .= ' <feedbacks>'.PHP_EOL;
foreach ($quizData['feedbacks'] as $feedback) {
$xmlContent .= ' <feedback id="'.$quizData['id'].'">' . PHP_EOL;
$xmlContent .= ' <feedbacktext>' . htmlspecialchars($feedback['feedbacktext']) . '</feedbacktext>' . PHP_EOL;
$xmlContent .= ' <feedbacktextformat>1</feedbacktextformat>' . PHP_EOL;
$xmlContent .= ' <mingrade>' . $feedback['mingrade'] . '</mingrade>' . PHP_EOL;
$xmlContent .= ' <maxgrade>' . $feedback['maxgrade'] . '</maxgrade>' . PHP_EOL;
$xmlContent .= ' </feedback>' . PHP_EOL;
$xmlContent .= ' <feedback id="'.$quizData['id'].'">'.PHP_EOL;
$xmlContent .= ' <feedbacktext>'.htmlspecialchars($feedback['feedbacktext']).'</feedbacktext>'.PHP_EOL;
$xmlContent .= ' <feedbacktextformat>1</feedbacktextformat>'.PHP_EOL;
$xmlContent .= ' <mingrade>'.$feedback['mingrade'].'</mingrade>'.PHP_EOL;
$xmlContent .= ' <maxgrade>'.$feedback['maxgrade'].'</maxgrade>'.PHP_EOL;
$xmlContent .= ' </feedback>'.PHP_EOL;
}
$xmlContent .= ' </feedbacks>' . PHP_EOL;
$xmlContent .= ' </feedbacks>'.PHP_EOL;
// Complete with placeholders for attempts and grades
$xmlContent .= ' <overrides>' . PHP_EOL . ' </overrides>' . PHP_EOL;
$xmlContent .= ' <grades>' . PHP_EOL . ' </grades>' . PHP_EOL;
$xmlContent .= ' <attempts>' . PHP_EOL . ' </attempts>' . PHP_EOL;
$xmlContent .= ' <overrides>'.PHP_EOL.' </overrides>'.PHP_EOL;
$xmlContent .= ' <grades>'.PHP_EOL.' </grades>'.PHP_EOL;
$xmlContent .= ' <attempts>'.PHP_EOL.' </attempts>'.PHP_EOL;
// Close the activity tag
$xmlContent .= ' </quiz>' . PHP_EOL;
$xmlContent .= '</activity>' . PHP_EOL;
$xmlContent .= ' </quiz>'.PHP_EOL;
$xmlContent .= '</activity>'.PHP_EOL;
// Save the XML file
$xmlFile = $destinationDir . '/quiz.xml';
$xmlFile = $destinationDir.'/quiz.xml';
if (file_put_contents($xmlFile, $xmlContent) === false) {
throw new Exception(get_lang('ErrorCreatingQuizXml'));
}
}
/**
* Exports a question in XML format.
*/
public function exportQuestion(array $question): string
{
$xmlContent = ' <question id="' . ($question['id'] ?? '0') . '">' . PHP_EOL;
$xmlContent .= ' <parent>0</parent>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($question['questiontext'] ?? 'No question text') . '</name>' . PHP_EOL;
$xmlContent .= ' <questiontext>' . htmlspecialchars($question['questiontext'] ?? 'No question text') . '</questiontext>' . PHP_EOL;
$xmlContent .= ' <questiontextformat>1</questiontextformat>' . PHP_EOL;
$xmlContent .= ' <generalfeedback></generalfeedback>' . PHP_EOL;
$xmlContent .= ' <generalfeedbackformat>1</generalfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <defaultmark>' . ($question['maxmark'] ?? '0') . '</defaultmark>' . PHP_EOL;
$xmlContent .= ' <penalty>0.3333333</penalty>' . PHP_EOL;
$xmlContent .= ' <qtype>' . htmlspecialchars(str_replace('_nosingle', '', $question['qtype']) ?? 'unknown') . '</qtype>' . PHP_EOL;
$xmlContent .= ' <length>1</length>' . PHP_EOL;
$xmlContent .= ' <stamp>moodle+' . time() . '+QUESTIONSTAMP</stamp>' . PHP_EOL;
$xmlContent .= ' <version>moodle+' . time() . '+VERSIONSTAMP</version>' . PHP_EOL;
$xmlContent .= ' <hidden>0</hidden>' . PHP_EOL;
$xmlContent .= ' <timecreated>' . time() . '</timecreated>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . time() . '</timemodified>' . PHP_EOL;
$xmlContent .= ' <createdby>2</createdby>' . PHP_EOL;
$xmlContent .= ' <modifiedby>2</modifiedby>' . PHP_EOL;
// Add question type-specific content
switch ($question['qtype']) {
case 'multichoice':
$xmlContent .= $this->exportMultichoiceQuestion($question);
break;
case 'multichoice_nosingle':
$xmlContent .= $this->exportMultichoiceNosingleQuestion($question);
break;
case 'truefalse':
$xmlContent .= $this->exportTrueFalseQuestion($question);
break;
case 'shortanswer':
$xmlContent .= $this->exportShortAnswerQuestion($question);
break;
case 'match':
$xmlContent .= $this->exportMatchQuestion($question);
break;
}
$xmlContent .= ' </question>' . PHP_EOL;
return $xmlContent;
}
/**
* Exports a multiple-choice question in XML format.
*/
private function exportMultichoiceQuestion(array $question): string
{
$xmlContent = ' <plugin_qtype_multichoice_question>' . PHP_EOL;
$xmlContent .= ' <answers>' . PHP_EOL;
$xmlContent = ' <plugin_qtype_multichoice_question>'.PHP_EOL;
$xmlContent .= ' <answers>'.PHP_EOL;
foreach ($question['answers'] as $answer) {
$xmlContent .= $this->exportAnswer($answer);
}
$xmlContent .= ' </answers>' . PHP_EOL;
$xmlContent .= ' <multichoice id="' . ($question['id'] ?? '0') . '">' . PHP_EOL;
$xmlContent .= ' <layout>0</layout>' . PHP_EOL;
$xmlContent .= ' <single>1</single>' . PHP_EOL;
$xmlContent .= ' <shuffleanswers>1</shuffleanswers>' . PHP_EOL;
$xmlContent .= ' <correctfeedback>Your answer is correct.</correctfeedback>' . PHP_EOL;
$xmlContent .= ' <correctfeedbackformat>1</correctfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedback>Your answer is partially correct.</partiallycorrectfeedback>' . PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedbackformat>1</partiallycorrectfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <incorrectfeedback>Your answer is incorrect.</incorrectfeedback>' . PHP_EOL;
$xmlContent .= ' <incorrectfeedbackformat>1</incorrectfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <answernumbering>abc</answernumbering>' . PHP_EOL;
$xmlContent .= ' <shownumcorrect>1</shownumcorrect>' . PHP_EOL;
$xmlContent .= ' </multichoice>' . PHP_EOL;
$xmlContent .= ' </plugin_qtype_multichoice_question>' . PHP_EOL;
$xmlContent .= ' </answers>'.PHP_EOL;
$xmlContent .= ' <multichoice id="'.($question['id'] ?? '0').'">'.PHP_EOL;
$xmlContent .= ' <layout>0</layout>'.PHP_EOL;
$xmlContent .= ' <single>1</single>'.PHP_EOL;
$xmlContent .= ' <shuffleanswers>1</shuffleanswers>'.PHP_EOL;
$xmlContent .= ' <correctfeedback>Your answer is correct.</correctfeedback>'.PHP_EOL;
$xmlContent .= ' <correctfeedbackformat>1</correctfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedback>Your answer is partially correct.</partiallycorrectfeedback>'.PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedbackformat>1</partiallycorrectfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <incorrectfeedback>Your answer is incorrect.</incorrectfeedback>'.PHP_EOL;
$xmlContent .= ' <incorrectfeedbackformat>1</incorrectfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <answernumbering>abc</answernumbering>'.PHP_EOL;
$xmlContent .= ' <shownumcorrect>1</shownumcorrect>'.PHP_EOL;
$xmlContent .= ' </multichoice>'.PHP_EOL;
$xmlContent .= ' </plugin_qtype_multichoice_question>'.PHP_EOL;
return $xmlContent;
}
@ -393,6 +394,7 @@ class QuizExport extends ActivityExport
{
// Similar structure to exportMultichoiceQuestion, but with single=0
$xmlContent = str_replace('<single>1</single>', '<single>0</single>', $this->exportMultichoiceQuestion($question));
return $xmlContent;
}
@ -401,17 +403,17 @@ class QuizExport extends ActivityExport
*/
private function exportTrueFalseQuestion(array $question): string
{
$xmlContent = ' <plugin_qtype_truefalse_question>' . PHP_EOL;
$xmlContent .= ' <answers>' . PHP_EOL;
$xmlContent = ' <plugin_qtype_truefalse_question>'.PHP_EOL;
$xmlContent .= ' <answers>'.PHP_EOL;
foreach ($question['answers'] as $answer) {
$xmlContent .= $this->exportAnswer($answer);
}
$xmlContent .= ' </answers>' . PHP_EOL;
$xmlContent .= ' <truefalse id="' . ($question['id'] ?? '0') . '">' . PHP_EOL;
$xmlContent .= ' <trueanswer>' . ($question['answers'][0]['id'] ?? '0') . '</trueanswer>' . PHP_EOL;
$xmlContent .= ' <falseanswer>' . ($question['answers'][1]['id'] ?? '0') . '</falseanswer>' . PHP_EOL;
$xmlContent .= ' </truefalse>' . PHP_EOL;
$xmlContent .= ' </plugin_qtype_truefalse_question>' . PHP_EOL;
$xmlContent .= ' </answers>'.PHP_EOL;
$xmlContent .= ' <truefalse id="'.($question['id'] ?? '0').'">'.PHP_EOL;
$xmlContent .= ' <trueanswer>'.($question['answers'][0]['id'] ?? '0').'</trueanswer>'.PHP_EOL;
$xmlContent .= ' <falseanswer>'.($question['answers'][1]['id'] ?? '0').'</falseanswer>'.PHP_EOL;
$xmlContent .= ' </truefalse>'.PHP_EOL;
$xmlContent .= ' </plugin_qtype_truefalse_question>'.PHP_EOL;
return $xmlContent;
}
@ -421,16 +423,16 @@ class QuizExport extends ActivityExport
*/
private function exportShortAnswerQuestion(array $question): string
{
$xmlContent = ' <plugin_qtype_shortanswer_question>' . PHP_EOL;
$xmlContent .= ' <answers>' . PHP_EOL;
$xmlContent = ' <plugin_qtype_shortanswer_question>'.PHP_EOL;
$xmlContent .= ' <answers>'.PHP_EOL;
foreach ($question['answers'] as $answer) {
$xmlContent .= $this->exportAnswer($answer);
}
$xmlContent .= ' </answers>' . PHP_EOL;
$xmlContent .= ' <shortanswer id="' . ($question['id'] ?? '0') . '">' . PHP_EOL;
$xmlContent .= ' <usecase>0</usecase>' . PHP_EOL;
$xmlContent .= ' </shortanswer>' . PHP_EOL;
$xmlContent .= ' </plugin_qtype_shortanswer_question>' . PHP_EOL;
$xmlContent .= ' </answers>'.PHP_EOL;
$xmlContent .= ' <shortanswer id="'.($question['id'] ?? '0').'">'.PHP_EOL;
$xmlContent .= ' <usecase>0</usecase>'.PHP_EOL;
$xmlContent .= ' </shortanswer>'.PHP_EOL;
$xmlContent .= ' </plugin_qtype_shortanswer_question>'.PHP_EOL;
return $xmlContent;
}
@ -440,18 +442,18 @@ class QuizExport extends ActivityExport
*/
private function exportMatchQuestion(array $question): string
{
$xmlContent = ' <plugin_qtype_match_question>' . PHP_EOL;
$xmlContent .= ' <matchoptions id="' . htmlspecialchars($question['id'] ?? '0') . '">' . PHP_EOL;
$xmlContent .= ' <shuffleanswers>1</shuffleanswers>' . PHP_EOL;
$xmlContent .= ' <correctfeedback>' . htmlspecialchars($question['correctfeedback'] ?? '') . '</correctfeedback>' . PHP_EOL;
$xmlContent .= ' <correctfeedbackformat>0</correctfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedback>' . htmlspecialchars($question['partiallycorrectfeedback'] ?? '') . '</partiallycorrectfeedback>' . PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedbackformat>0</partiallycorrectfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <incorrectfeedback>' . htmlspecialchars($question['incorrectfeedback'] ?? '') . '</incorrectfeedback>' . PHP_EOL;
$xmlContent .= ' <incorrectfeedbackformat>0</incorrectfeedbackformat>' . PHP_EOL;
$xmlContent .= ' <shownumcorrect>0</shownumcorrect>' . PHP_EOL;
$xmlContent .= ' </matchoptions>' . PHP_EOL;
$xmlContent .= ' <matches>' . PHP_EOL;
$xmlContent = ' <plugin_qtype_match_question>'.PHP_EOL;
$xmlContent .= ' <matchoptions id="'.htmlspecialchars($question['id'] ?? '0').'">'.PHP_EOL;
$xmlContent .= ' <shuffleanswers>1</shuffleanswers>'.PHP_EOL;
$xmlContent .= ' <correctfeedback>'.htmlspecialchars($question['correctfeedback'] ?? '').'</correctfeedback>'.PHP_EOL;
$xmlContent .= ' <correctfeedbackformat>0</correctfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedback>'.htmlspecialchars($question['partiallycorrectfeedback'] ?? '').'</partiallycorrectfeedback>'.PHP_EOL;
$xmlContent .= ' <partiallycorrectfeedbackformat>0</partiallycorrectfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <incorrectfeedback>'.htmlspecialchars($question['incorrectfeedback'] ?? '').'</incorrectfeedback>'.PHP_EOL;
$xmlContent .= ' <incorrectfeedbackformat>0</incorrectfeedbackformat>'.PHP_EOL;
$xmlContent .= ' <shownumcorrect>0</shownumcorrect>'.PHP_EOL;
$xmlContent .= ' </matchoptions>'.PHP_EOL;
$xmlContent .= ' <matches>'.PHP_EOL;
$res = FillBlanks::getAnswerInfo($question['answers'][0]['text']);
$words = $res['words'];
@ -460,16 +462,16 @@ class QuizExport extends ActivityExport
for ($i = 0; $i < count($common_words); $i++) {
$answer = htmlspecialchars(trim(strip_tags($common_words[$i])));
if (!empty(trim($answer))) {
$xmlContent .= ' <match id="' . ($i + 1) . '">' . PHP_EOL;
$xmlContent .= ' <questiontext>' . $answer . '</questiontext>' . PHP_EOL;
$xmlContent .= ' <questiontextformat>0</questiontextformat>' . PHP_EOL;
$xmlContent .= ' <answertext>' . htmlspecialchars(explode('|', $words[$i])[0]) . '</answertext>' . PHP_EOL;
$xmlContent .= ' </match>' . PHP_EOL;
$xmlContent .= ' <match id="'.($i + 1).'">'.PHP_EOL;
$xmlContent .= ' <questiontext>'.$answer.'</questiontext>'.PHP_EOL;
$xmlContent .= ' <questiontextformat>0</questiontextformat>'.PHP_EOL;
$xmlContent .= ' <answertext>'.htmlspecialchars(explode('|', $words[$i])[0]).'</answertext>'.PHP_EOL;
$xmlContent .= ' </match>'.PHP_EOL;
}
}
$xmlContent .= ' </matches>' . PHP_EOL;
$xmlContent .= ' </plugin_qtype_match_question>' . PHP_EOL;
$xmlContent .= ' </matches>'.PHP_EOL;
$xmlContent .= ' </plugin_qtype_match_question>'.PHP_EOL;
return $xmlContent;
}
@ -479,13 +481,12 @@ class QuizExport extends ActivityExport
*/
private function exportAnswer(array $answer): string
{
return ' <answer id="' . ($answer['id'] ?? '0') . '">' . PHP_EOL .
' <answertext>' . htmlspecialchars($answer['text'] ?? 'No answer text') . '</answertext>' . PHP_EOL .
' <answerformat>1</answerformat>' . PHP_EOL .
' <fraction>' . ($answer['fraction'] ?? '0') . '</fraction>' . PHP_EOL .
' <feedback>' . htmlspecialchars($answer['feedback'] ?? '') . '</feedback>' . PHP_EOL .
' <feedbackformat>1</feedbackformat>' . PHP_EOL .
' </answer>' . PHP_EOL;
return ' <answer id="'.($answer['id'] ?? '0').'">'.PHP_EOL.
' <answertext>'.htmlspecialchars($answer['text'] ?? 'No answer text').'</answertext>'.PHP_EOL.
' <answerformat>1</answerformat>'.PHP_EOL.
' <fraction>'.($answer['fraction'] ?? '0').'</fraction>'.PHP_EOL.
' <feedback>'.htmlspecialchars($answer['feedback'] ?? '').'</feedback>'.PHP_EOL.
' <feedbackformat>1</feedbackformat>'.PHP_EOL.
' </answer>'.PHP_EOL;
}
}

@ -14,10 +14,10 @@ class ResourceExport extends ActivityExport
/**
* Export a resource to the specified directory.
*
* @param int $activityId The ID of the resource.
* @param string $exportDir The directory where the resource will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the resource.
* @param string $exportDir The directory where the resource will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -40,72 +40,72 @@ class ResourceExport extends ActivityExport
}
/**
* Create the XML file for the resource.
* Get resource data dynamically from the course.
*/
private function createResourceXml(array $resourceData, string $resourceDir): void
public function getData(int $resourceId, int $sectionId): array
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $resourceData['id'] . '" moduleid="' . $resourceData['moduleid'] . '" modulename="resource" contextid="' . $resourceData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <resource id="' . $resourceData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($resourceData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro>' . htmlspecialchars($resourceData['intro']) . '</intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <tobemigrated>0</tobemigrated>' . PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>' . PHP_EOL;
$xmlContent .= ' <legacyfileslast>$@NULL@$</legacyfileslast>' . PHP_EOL;
$xmlContent .= ' <display>0</display>' . PHP_EOL;
$xmlContent .= ' <displayoptions>a:1:{s:10:"printintro";i:1;}</displayoptions>' . PHP_EOL;
$xmlContent .= ' <filterfiles>0</filterfiles>' . PHP_EOL;
$xmlContent .= ' <revision>1</revision>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $resourceData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' </resource>' . PHP_EOL;
$xmlContent .= '</activity>' . PHP_EOL;
$resource = $this->course->resources[RESOURCE_DOCUMENT][$resourceId];
$this->createXmlFile('resource', $xmlContent, $resourceDir);
return [
'id' => $resourceId,
'moduleid' => $resource->source_id,
'modulename' => 'resource',
'contextid' => $resource->source_id,
'name' => $resource->title,
'intro' => $resource->comment ?? '',
'sectionid' => $sectionId,
'sectionnumber' => 1,
'timemodified' => time(),
'users' => [],
'files' => [],
];
}
/**
* Creates the inforef.xml file, referencing users and files associated with the activity.
*
* @param array $references Contains 'users' and 'files' arrays to reference in the XML.
* @param string $directory The directory where the XML file will be saved.
* @param array $references Contains 'users' and 'files' arrays to reference in the XML.
* @param string $directory The directory where the XML file will be saved.
*/
protected function createInforefXml(array $references, string $directory): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<inforef>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<inforef>'.PHP_EOL;
$xmlContent .= ' <fileref>' . PHP_EOL;
$xmlContent .= ' <file>' . PHP_EOL;
$xmlContent .= ' <id>' . htmlspecialchars($references['id']) . '</id>' . PHP_EOL;
$xmlContent .= ' </file>' . PHP_EOL;
$xmlContent .= ' </fileref>' . PHP_EOL;
$xmlContent .= ' <fileref>'.PHP_EOL;
$xmlContent .= ' <file>'.PHP_EOL;
$xmlContent .= ' <id>'.htmlspecialchars($references['id']).'</id>'.PHP_EOL;
$xmlContent .= ' </file>'.PHP_EOL;
$xmlContent .= ' </fileref>'.PHP_EOL;
$xmlContent .= '</inforef>' . PHP_EOL;
$xmlContent .= '</inforef>'.PHP_EOL;
// Save the XML content to the directory
$this->createXmlFile('inforef', $xmlContent, $directory);
}
/**
* Get resource data dynamically from the course.
* Create the XML file for the resource.
*/
public function getData(int $resourceId, int $sectionId): array
private function createResourceXml(array $resourceData, string $resourceDir): void
{
$resource = $this->course->resources[RESOURCE_DOCUMENT][$resourceId];
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$resourceData['id'].'" moduleid="'.$resourceData['moduleid'].'" modulename="resource" contextid="'.$resourceData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <resource id="'.$resourceData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($resourceData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro>'.htmlspecialchars($resourceData['intro']).'</intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <tobemigrated>0</tobemigrated>'.PHP_EOL;
$xmlContent .= ' <legacyfiles>0</legacyfiles>'.PHP_EOL;
$xmlContent .= ' <legacyfileslast>$@NULL@$</legacyfileslast>'.PHP_EOL;
$xmlContent .= ' <display>0</display>'.PHP_EOL;
$xmlContent .= ' <displayoptions>a:1:{s:10:"printintro";i:1;}</displayoptions>'.PHP_EOL;
$xmlContent .= ' <filterfiles>0</filterfiles>'.PHP_EOL;
$xmlContent .= ' <revision>1</revision>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$resourceData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' </resource>'.PHP_EOL;
$xmlContent .= '</activity>'.PHP_EOL;
return [
'id' => $resourceId,
'moduleid' => $resource->source_id,
'modulename' => 'resource',
'contextid' => $resource->source_id,
'name' => $resource->title,
'intro' => $resource->comment ?? '',
'sectionid' => $sectionId,
'sectionnumber' => 1,
'timemodified' => time(),
'users' => [],
'files' => [],
];
$this->createXmlFile('resource', $xmlContent, $resourceDir);
}
}

@ -31,7 +31,7 @@ class SectionExport
*/
public function exportSection(int $sectionId, string $exportDir): void
{
$sectionDir = $exportDir . "/sections/section_{$sectionId}";
$sectionDir = $exportDir."/sections/section_{$sectionId}";
if (!is_dir($sectionDir)) {
mkdir($sectionDir, api_get_permissions_for_new_directories(), true);
@ -61,34 +61,6 @@ class SectionExport
$this->exportActivities($sectionData['activities'], $exportDir, $sectionId);
}
/**
* Export the activities of a section.
*/
private function exportActivities(array $activities, string $exportDir, int $sectionId): void
{
$exportClasses = [
'quiz' => QuizExport::class,
'glossary' => GlossaryExport::class,
'url' => UrlExport::class,
'assign' => AssignExport::class,
'forum' => ForumExport::class,
'page' => PageExport::class,
'resource' => ResourceExport::class,
'folder' => FolderExport::class,
'feedback' => FeedbackExport::class,
];
foreach ($activities as $activity) {
$moduleName = $activity['modulename'];
if (isset($exportClasses[$moduleName])) {
$exportClass = new $exportClasses[$moduleName]($this->course);
$exportClass->export($activity['id'], $exportDir, $activity['moduleid'], $sectionId);
} else {
throw new \Exception("Export for module '$moduleName' is not supported.");
}
}
}
/**
* Get all general items not linked to any lesson (learnpath).
*/
@ -135,32 +107,12 @@ class SectionExport
{
$generalLearnpath = (object) [
'items' => $this->getGeneralItems(),
'source_id' => 0
'source_id' => 0,
];
return $this->getActivitiesForSection($generalLearnpath, true);
}
/**
* Check if an item is associated with any learnpath.
*/
private function isItemInLearnpath(object $item, string $type): bool
{
if (!empty($this->course->resources[RESOURCE_LEARNPATH])) {
foreach ($this->course->resources[RESOURCE_LEARNPATH] as $learnpath) {
if (!empty($learnpath->items)) {
foreach ($learnpath->items as $learnpathItem) {
if ($learnpathItem['item_type'] === $type && $learnpathItem['path'] == $item->source_id) {
return true;
}
}
}
}
}
return false;
}
/**
* Get the learnpath object by its ID.
*/
@ -188,7 +140,7 @@ class SectionExport
'sequence' => $learnpath->source_id,
'visible' => $learnpath->visibility,
'timemodified' => strtotime($learnpath->modified_on),
'activities' => $this->getActivitiesForSection($learnpath)
'activities' => $this->getActivitiesForSection($learnpath),
];
}
@ -207,6 +159,54 @@ class SectionExport
return $activities;
}
/**
* Export the activities of a section.
*/
private function exportActivities(array $activities, string $exportDir, int $sectionId): void
{
$exportClasses = [
'quiz' => QuizExport::class,
'glossary' => GlossaryExport::class,
'url' => UrlExport::class,
'assign' => AssignExport::class,
'forum' => ForumExport::class,
'page' => PageExport::class,
'resource' => ResourceExport::class,
'folder' => FolderExport::class,
'feedback' => FeedbackExport::class,
];
foreach ($activities as $activity) {
$moduleName = $activity['modulename'];
if (isset($exportClasses[$moduleName])) {
$exportClass = new $exportClasses[$moduleName]($this->course);
$exportClass->export($activity['id'], $exportDir, $activity['moduleid'], $sectionId);
} else {
throw new \Exception("Export for module '$moduleName' is not supported.");
}
}
}
/**
* Check if an item is associated with any learnpath.
*/
private function isItemInLearnpath(object $item, string $type): bool
{
if (!empty($this->course->resources[RESOURCE_LEARNPATH])) {
foreach ($this->course->resources[RESOURCE_LEARNPATH] as $learnpath) {
if (!empty($learnpath->items)) {
foreach ($learnpath->items as $learnpathItem) {
if ($learnpathItem['item_type'] === $type && $learnpathItem['path'] == $item->source_id) {
return true;
}
}
}
}
}
return false;
}
/**
* Add an activity to the activities list.
*/
@ -287,18 +287,18 @@ class SectionExport
*/
private function createSectionXml(array $sectionData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<section id="' . $sectionData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <number>' . $sectionData['number'] . '</number>' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($sectionData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <summary>' . htmlspecialchars($sectionData['summary']) . '</summary>' . PHP_EOL;
$xmlContent .= ' <summaryformat>1</summaryformat>' . PHP_EOL;
$xmlContent .= ' <sequence>' . implode(',', array_column($sectionData['activities'], 'moduleid')) . '</sequence>' . PHP_EOL;
$xmlContent .= ' <visible>' . $sectionData['visible'] . '</visible>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $sectionData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= '</section>' . PHP_EOL;
$xmlFile = $destinationDir . '/section.xml';
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<section id="'.$sectionData['id'].'">'.PHP_EOL;
$xmlContent .= ' <number>'.$sectionData['number'].'</number>'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($sectionData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <summary>'.htmlspecialchars($sectionData['summary']).'</summary>'.PHP_EOL;
$xmlContent .= ' <summaryformat>1</summaryformat>'.PHP_EOL;
$xmlContent .= ' <sequence>'.implode(',', array_column($sectionData['activities'], 'moduleid')).'</sequence>'.PHP_EOL;
$xmlContent .= ' <visible>'.$sectionData['visible'].'</visible>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$sectionData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= '</section>'.PHP_EOL;
$xmlFile = $destinationDir.'/section.xml';
file_put_contents($xmlFile, $xmlContent);
}
@ -307,16 +307,16 @@ class SectionExport
*/
private function createInforefXml(array $sectionData, string $destinationDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<inforef>' . PHP_EOL;
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<inforef>'.PHP_EOL;
foreach ($sectionData['activities'] as $activity) {
$xmlContent .= ' <activity id="' . $activity['id'] . '">' . htmlspecialchars($activity['name']) . '</activity>' . PHP_EOL;
$xmlContent .= ' <activity id="'.$activity['id'].'">'.htmlspecialchars($activity['name']).'</activity>'.PHP_EOL;
}
$xmlContent .= '</inforef>' . PHP_EOL;
$xmlContent .= '</inforef>'.PHP_EOL;
$xmlFile = $destinationDir . '/inforef.xml';
$xmlFile = $destinationDir.'/inforef.xml';
file_put_contents($xmlFile, $xmlContent);
}
}

@ -14,10 +14,10 @@ class UrlExport extends ActivityExport
/**
* Export all URL resources into a single Moodle activity.
*
* @param int $activityId The ID of the URL.
* @param string $exportDir The directory where the URL will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
* @param int $activityId The ID of the URL.
* @param string $exportDir The directory where the URL will be exported.
* @param int $moduleId The ID of the module.
* @param int $sectionId The ID of the section.
*/
public function export($activityId, $exportDir, $moduleId, $sectionId): void
{
@ -39,28 +39,6 @@ class UrlExport extends ActivityExport
$this->createFiltersXml($urlData, $urlDir);
}
/**
* Create the XML file for the URL.
*/
private function createUrlXml(array $urlData, string $urlDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
$xmlContent .= '<activity id="' . $urlData['id'] . '" moduleid="' . $urlData['moduleid'] . '" modulename="'.$urlData['modulename'].'" contextid="' . $urlData['contextid'] . '">' . PHP_EOL;
$xmlContent .= ' <url id="' . $urlData['id'] . '">' . PHP_EOL;
$xmlContent .= ' <name>' . htmlspecialchars($urlData['name']) . '</name>' . PHP_EOL;
$xmlContent .= ' <intro><![CDATA[' . htmlspecialchars($urlData['description']) . ']]></intro>' . PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>' . PHP_EOL;
$xmlContent .= ' <externalurl>' . htmlspecialchars($urlData['externalurl']) . '</externalurl>' . PHP_EOL;
$xmlContent .= ' <display>0</display>' . PHP_EOL;
$xmlContent .= ' <displayoptions>a:1:{s:10:"printintro";i:1;}</displayoptions>' . PHP_EOL;
$xmlContent .= ' <parameters>a:0:{}</parameters>' . PHP_EOL;
$xmlContent .= ' <timemodified>' . $urlData['timemodified'] . '</timemodified>' . PHP_EOL;
$xmlContent .= ' </url>' . PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('url', $xmlContent, $urlDir);
}
/**
* Get all URL data for the course.
*/
@ -86,4 +64,26 @@ class UrlExport extends ActivityExport
'files' => [],
];
}
/**
* Create the XML file for the URL.
*/
private function createUrlXml(array $urlData, string $urlDir): void
{
$xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
$xmlContent .= '<activity id="'.$urlData['id'].'" moduleid="'.$urlData['moduleid'].'" modulename="'.$urlData['modulename'].'" contextid="'.$urlData['contextid'].'">'.PHP_EOL;
$xmlContent .= ' <url id="'.$urlData['id'].'">'.PHP_EOL;
$xmlContent .= ' <name>'.htmlspecialchars($urlData['name']).'</name>'.PHP_EOL;
$xmlContent .= ' <intro><![CDATA['.htmlspecialchars($urlData['description']).']]></intro>'.PHP_EOL;
$xmlContent .= ' <introformat>1</introformat>'.PHP_EOL;
$xmlContent .= ' <externalurl>'.htmlspecialchars($urlData['externalurl']).'</externalurl>'.PHP_EOL;
$xmlContent .= ' <display>0</display>'.PHP_EOL;
$xmlContent .= ' <displayoptions>a:1:{s:10:"printintro";i:1;}</displayoptions>'.PHP_EOL;
$xmlContent .= ' <parameters>a:0:{}</parameters>'.PHP_EOL;
$xmlContent .= ' <timemodified>'.$urlData['timemodified'].'</timemodified>'.PHP_EOL;
$xmlContent .= ' </url>'.PHP_EOL;
$xmlContent .= '</activity>';
$this->createXmlFile('url', $xmlContent, $urlDir);
}
}

@ -86,6 +86,7 @@ function storage_get($sv_user, $sv_course, $sv_sco, $sv_key)
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
$row = Database::fetch_assoc($res);
return Security::remove_XSS($row['sv_value']);
} else {
return null;
@ -236,6 +237,7 @@ function storage_stack_pop($sv_user, $sv_course, $sv_sco, $sv_key)
$resdelete = Database::query($sqldelete);
if ($resselect && $resdelete) {
Database::query("commit");
return Security::remove_XSS($rowselect['sv_value']);
} else {
Database::query("rollback");

@ -98,7 +98,7 @@ if (ChamiloApi::isAjaxRequest() && isset($_POST['action'])) {
header('Content-Type: application/json');
echo json_encode($users);
die();
exit();
}
function search_users($needle, $type)
@ -799,10 +799,10 @@ $newLinks .= Display::url(
echo Display::get_alphabet_options(); ?>
</select>
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="show_last_ten_users_button" title="<?php echo get_lang('ShowLastTenUsers') ?>">
<button class="btn btn-default" type="button" id="show_last_ten_users_button" title="<?php echo get_lang('ShowLastTenUsers'); ?>">
<i class="fa fa-clock-o"></i>
</button>
<button class="btn btn-default" type="button" id="reset_users_button" title="<?php echo get_lang('Reset') ?>">
<button class="btn btn-default" type="button" id="reset_users_button" title="<?php echo get_lang('Reset'); ?>">
<i class="fa fa-refresh"></i>
</button>
</span>

@ -309,7 +309,7 @@ while ($row = Database::fetch_array($result, 'ASSOC')) {
}
// Highlight the question that was just updated and scrool to it
if ($row['question_id']==$my_question_id_survey) {
if ($row['question_id'] == $my_question_id_survey) {
echo '<tr class="'.$questionsGroupClass.$breakClass.'" style="background-color:#A9DFBF;" >';
echo '<a name="tocupdatelink" id="tocupdatelink" ></a>';
echo '<script>';
@ -319,7 +319,7 @@ while ($row = Database::fetch_array($result, 'ASSOC')) {
echo '});';
echo '</script>';
} else {
echo '<tr class="'.$questionsGroupClass.$breakClass.'">';
echo '<tr class="'.$questionsGroupClass.$breakClass.'">';
}
echo ' <td>'.$question_counter.'</td>';
echo ' <td>';

@ -3533,7 +3533,7 @@ class SurveyUtil
/**
* This function changes the modify column of the sortable table.
*
* @param int $survey_id the id of the survey
* @param int $survey_id the id of the survey
* @param bool $drh
* @param bool $surveyCode
*

@ -2691,7 +2691,7 @@ function getAllWork(
$courseQueryToString = implode(' OR ', $courseQuery);
//try {
$compilatio = new Compilatio();
$compilatio = new Compilatio();
//} catch (Exception $e) {
// $compilatio = null;
//}

@ -1626,13 +1626,10 @@ class ZoomPlugin extends Plugin
}
/**
* @param Meeting $meeting
* @param array<User> $users
*
* @throws OptimisticLockException
* @throws \Doctrine\ORM\ORMException
*
* @return array
*/
public function registerPresenters(Meeting $meeting, array $users): array
{

@ -3,7 +3,6 @@
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Zoom\Meeting;
use Chamilo\PluginBundle\Zoom\Registrant;
use Chamilo\PluginBundle\Zoom\Webinar;
require_once __DIR__.'/config.php';

@ -203,10 +203,10 @@ class CourseSelectForm
echo Display::return_message(get_lang('DontForgetToSelectTheMediaFilesIfYourResourceNeedIt'));
$resource_titles = self::getResourceTitleList();
$element_count = self::parseResources($resource_titles, $course->resources, $forum_categories, $forums, $forum_topics,true, true);
$element_count = self::parseResources($resource_titles, $course->resources, $forum_categories, $forums, $forum_topics, true, true);
// Fixes forum order
if (!empty($element_count)) {
if (!empty($element_count)) {
$type = RESOURCE_FORUMCATEGORY;
echo '<div class="item-backup" onclick="javascript:exp('."'$type'".');">';
echo '<em id="img_'.$type.'" class="fa fa-minus-square-o fa-lg"></em>';

Loading…
Cancel
Save