course = $course; } /** * Export the Moodle course in .mbz format. */ public function export(string $courseId, string $exportDir, int $version) { $tempDir = api_get_path(SYS_ARCHIVE_PATH).$exportDir; if (!is_dir($tempDir)) { if (!mkdir($tempDir, api_get_permissions_for_new_directories(), true)) { throw new Exception(get_lang('ErrorCreatingDirectory')); } } $courseInfo = api_get_course_info($courseId); if (!$courseInfo) { throw new Exception(get_lang('CourseNotFound')); } // Generate the moodle_backup.xml $this->createMoodleBackupXml($tempDir, $version); // Get the activities from the course $activities = $this->getActivities(); // Export course-related files $courseExport = new CourseExport($this->course, $activities); $courseExport->exportCourse($tempDir); // Export files-related data and actual files $fileExport = new FileExport($this->course); $filesData = $fileExport->getFilesData(); $fileExport->exportFiles($filesData, $tempDir); // Export sections of the course $this->exportSections($tempDir); // Export all root XML files $this->exportRootXmlFiles($tempDir); // Compress everything into a .mbz (ZIP) file $exportedFile = $this->createMbzFile($tempDir); // Clean up temporary directory $this->cleanupTempDir($tempDir); return $exportedFile; } /** * Export questions data to XML file. */ public function exportQuestionsXml(array $questionsData, string $exportDir): void { $quizExport = new QuizExport($this->course); $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; foreach ($questionsData as $quiz) { $categoryId = $quiz['questions'][0]['questioncategoryid'] ?? '0'; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' Default for '.htmlspecialchars($quiz['name'] ?? 'Unknown').''.PHP_EOL; $xmlContent .= ' '.($quiz['contextid'] ?? '0').''.PHP_EOL; $xmlContent .= ' 70'.PHP_EOL; $xmlContent .= ' '.($quiz['moduleid'] ?? '0').''.PHP_EOL; $xmlContent .= ' The default category for questions shared in context "'.htmlspecialchars($quiz['name'] ?? 'Unknown').'".'.PHP_EOL; $xmlContent .= ' 0'.PHP_EOL; $xmlContent .= ' moodle+'.time().'+CATEGORYSTAMP'.PHP_EOL; $xmlContent .= ' 0'.PHP_EOL; $xmlContent .= ' 999'.PHP_EOL; $xmlContent .= ' $@NULL@$'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; foreach ($quiz['questions'] as $question) { $xmlContent .= $quizExport->exportQuestion($question); } $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.PHP_EOL; } $xmlContent .= ''; 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. */ private function exportRootXmlFiles(string $exportDir): void { $this->exportBadgesXml($exportDir); $this->exportCompletionXml($exportDir); $this->exportGradebookXml($exportDir); $this->exportGradeHistoryXml($exportDir); $this->exportGroupsXml($exportDir); $this->exportOutcomesXml($exportDir); // Export quizzes and their questions $activities = $this->getActivities(); $questionsData = []; foreach ($activities as $activity) { if ($activity['modulename'] === 'quiz') { $quizExport = new QuizExport($this->course); $quizData = $quizExport->getData($activity['id'], $activity['sectionid']); $questionsData[] = $quizData; } } $this->exportQuestionsXml($questionsData, $exportDir); $this->exportRolesXml($exportDir); $this->exportScalesXml($exportDir); $this->exportUsersXml($exportDir); } /** * Create the moodle_backup.xml file with the required course details. */ private function createMoodleBackupXml(string $destinationDir, int $version): void { // Generate course information and backup metadata $courseInfo = api_get_course_info($this->course->code); $backupId = md5(uniqid(mt_rand(), true)); $siteHash = md5(uniqid(mt_rand(), true)); $wwwRoot = api_get_path(WEB_PATH); $courseStartDate = strtotime($courseInfo['creation_date']); $courseEndDate = $courseStartDate + (365 * 24 * 60 * 60); // Build the XML content for the backup $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' backup-'.htmlspecialchars($courseInfo['code']).'.mbz'.PHP_EOL; $xmlContent .= ' '.($version === 3 ? '2021051718' : '2022041900').''.PHP_EOL; $xmlContent .= ' '.($version === 3 ? '3.11.18 (Build: 20231211)' : '4.x version here').''.PHP_EOL; $xmlContent .= ' '.($version === 3 ? '2021051700' : '2022041900').''.PHP_EOL; $xmlContent .= ' '.($version === 3 ? '3.11' : '4.x').''.PHP_EOL; $xmlContent .= ' '.time().''.PHP_EOL; $xmlContent .= ' 0'.PHP_EOL; $xmlContent .= ' 1'.PHP_EOL; $xmlContent .= ' 0'.PHP_EOL; $xmlContent .= ' '.$wwwRoot.''.PHP_EOL; $xmlContent .= ' '.$siteHash.''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($courseInfo['real_id']).''.PHP_EOL; $xmlContent .= ' '.get_lang('Topics').''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($courseInfo['title']).''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($courseInfo['code']).''.PHP_EOL; $xmlContent .= ' '.$courseStartDate.''.PHP_EOL; $xmlContent .= ' '.$courseEndDate.''.PHP_EOL; $xmlContent .= ' '.$courseInfo['real_id'].''.PHP_EOL; $xmlContent .= ' '.api_get_current_access_url_id().''.PHP_EOL; $xmlContent .= '
'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' course'.PHP_EOL; $xmlContent .= ' moodle2'.PHP_EOL; $xmlContent .= ' 1'.PHP_EOL; $xmlContent .= ' 10'.PHP_EOL; $xmlContent .= ' 1'.PHP_EOL; $xmlContent .= ' 0'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= '
'.PHP_EOL; // Contents with activities and sections $xmlContent .= ' '.PHP_EOL; // Export sections dynamically and add them to the XML $sections = $this->getSections(); if (!empty($sections)) { $xmlContent .= ' '.PHP_EOL; foreach ($sections as $section) { $xmlContent .= '
'.PHP_EOL; $xmlContent .= ' '.$section['id'].''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($section['name']).''.PHP_EOL; $xmlContent .= ' sections/section_'.$section['id'].''.PHP_EOL; $xmlContent .= '
'.PHP_EOL; } $xmlContent .= '
'.PHP_EOL; } $activities = $this->getActivities(); if (!empty($activities)) { $xmlContent .= ' '.PHP_EOL; foreach ($activities as $activity) { $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.$activity['moduleid'].''.PHP_EOL; $xmlContent .= ' '.$activity['sectionid'].''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($activity['modulename']).''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($activity['title']).''.PHP_EOL; $xmlContent .= ' activities/'.$activity['modulename'].'_'.$activity['moduleid'].''.PHP_EOL; $xmlContent .= ' '.PHP_EOL; } $xmlContent .= ' '.PHP_EOL; } // Course directory $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.$courseInfo['real_id'].''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($courseInfo['title']).''.PHP_EOL; $xmlContent .= ' course'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= '
'.PHP_EOL; // Backup settings $xmlContent .= ' '.PHP_EOL; $settings = $this->exportBackupSettings($sections, $activities); foreach ($settings as $setting) { $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($setting['level']).''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($setting['name']).''.PHP_EOL; $xmlContent .= ' '.$setting['value'].''.PHP_EOL; if (isset($setting['section'])) { $xmlContent .= '
'.htmlspecialchars($setting['section']).'
'.PHP_EOL; } if (isset($setting['activity'])) { $xmlContent .= ' '.htmlspecialchars($setting['activity']).''.PHP_EOL; } $xmlContent .= '
'.PHP_EOL; } $xmlContent .= '
'.PHP_EOL; $xmlContent .= '
'.PHP_EOL; $xmlContent .= '
'; $xmlFile = $destinationDir.'/moodle_backup.xml'; file_put_contents($xmlFile, $xmlContent); } /** * Get all sections from the course. */ private function getSections(): array { $sectionExport = new SectionExport($this->course); $sections = []; foreach ($this->course->resources[RESOURCE_LEARNPATH] as $learnpath) { if ($learnpath->lp_type == '1') { $sections[] = $sectionExport->getSectionData($learnpath); } } // Add a general section for resources without a lesson $sections[] = [ 'id' => 0, 'number' => 0, 'name' => get_lang('General'), 'summary' => get_lang('GeneralResourcesCourse'), 'sequence' => 0, 'visible' => 1, 'timemodified' => time(), 'activities' => $sectionExport->getActivitiesForGeneral(), ]; return $sections; } /** * Get all activities from the course. */ private function getActivities(): array { $activities = []; $glossaryAdded = false; foreach ($this->course->resources as $resourceType => $resources) { foreach ($resources as $resource) { $exportClass = null; $moduleName = ''; $title = ''; $id = 0; // Handle quizzes if ($resourceType === RESOURCE_QUIZ && $resource->obj->iid > 0) { $exportClass = QuizExport::class; $moduleName = 'quiz'; $id = $resource->obj->iid; $title = $resource->obj->title; } // Handle links if ($resourceType === RESOURCE_LINK && $resource->source_id > 0) { $exportClass = UrlExport::class; $moduleName = 'url'; $id = $resource->source_id; $title = $resource->title; } // Handle glossaries elseif ($resourceType === RESOURCE_GLOSSARY && $resource->glossary_id > 0 && !$glossaryAdded) { $exportClass = GlossaryExport::class; $moduleName = 'glossary'; $id = 1; $title = get_lang('Glossary'); $glossaryAdded = true; } // Handle forums elseif ($resourceType === RESOURCE_FORUM && $resource->source_id > 0) { $exportClass = ForumExport::class; $moduleName = 'forum'; $id = $resource->obj->iid; $title = $resource->obj->forum_title; } // Handle documents (HTML pages) elseif ($resourceType === RESOURCE_DOCUMENT && $resource->source_id > 0) { $document = \DocumentManager::get_document_data_by_id($resource->source_id, $this->course->code); if ('html' === pathinfo($document['path'], PATHINFO_EXTENSION)) { $exportClass = PageExport::class; $moduleName = 'page'; $id = $resource->source_id; $title = $document['title']; } elseif ('file' === $resource->file_type) { $exportClass = ResourceExport::class; $moduleName = 'resource'; $id = $resource->source_id; $title = $resource->title; } elseif ('folder' === $resource->file_type) { $exportClass = FolderExport::class; $moduleName = 'folder'; $id = $resource->source_id; $title = $resource->title; } } // Handle assignments (work) elseif ($resourceType === RESOURCE_WORK && $resource->source_id > 0) { $exportClass = AssignExport::class; $moduleName = 'assign'; $id = $resource->source_id; $title = $resource->params['title'] ?? ''; } // Handle feedback (survey) elseif ($resourceType === RESOURCE_SURVEY && $resource->source_id > 0) { $exportClass = FeedbackExport::class; $moduleName = 'feedback'; $id = $resource->source_id; $title = $resource->params['title'] ?? ''; } // Add the activity if the class and module name are set if ($exportClass && $moduleName) { $exportInstance = new $exportClass($this->course); $activities[] = [ 'id' => $id, 'sectionid' => $exportInstance->getSectionIdForActivity($id, $resourceType), 'modulename' => $moduleName, 'moduleid' => $id, 'title' => $title, ]; } } } return $activities; } /** * Export the sections of the course. */ private function exportSections(string $exportDir): void { $sections = $this->getSections(); foreach ($sections as $section) { $sectionExport = new SectionExport($this->course); $sectionExport->exportSection($section['id'], $exportDir); } } /** * Create a .mbz (ZIP) file from the exported data. */ private function createMbzFile(string $sourceDir): string { $zip = new ZipArchive(); $zipFile = $sourceDir.'.mbz'; if ($zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { throw new Exception(get_lang('ErrorCreatingZip')); } $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($sourceDir), RecursiveIteratorIterator::LEAVES_ONLY ); foreach ($files as $file) { if (!$file->isDir()) { $filePath = $file->getRealPath(); $relativePath = substr($filePath, strlen($sourceDir) + 1); if (!$zip->addFile($filePath, $relativePath)) { throw new Exception(get_lang('ErrorAddingFileToZip').": $relativePath"); } } } if (!$zip->close()) { throw new Exception(get_lang('ErrorClosingZip')); } return $zipFile; } /** * Clean up the temporary directory used for export. */ private function cleanupTempDir(string $dir): void { $this->recursiveDelete($dir); } /** * Recursively delete a directory and its contents. */ private function recursiveDelete(string $dir): void { $files = array_diff(scandir($dir), ['.', '..']); foreach ($files as $file) { $path = "$dir/$file"; is_dir($path) ? $this->recursiveDelete($path) : unlink($path); } rmdir($dir); } /** * Export badges data to XML file. */ private function exportBadgesXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/badges.xml', $xmlContent); } /** * Export course completion data to XML file. */ private function exportCompletionXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/completion.xml', $xmlContent); } /** * Export gradebook data to XML file. */ private function exportGradebookXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/gradebook.xml', $xmlContent); } /** * Export grade history data to XML file. */ private function exportGradeHistoryXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/grade_history.xml', $xmlContent); } /** * Export groups data to XML file. */ private function exportGroupsXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/groups.xml', $xmlContent); } /** * Export outcomes data to XML file. */ private function exportOutcomesXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/outcomes.xml', $xmlContent); } /** * Export roles data to XML file. */ private function exportRolesXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' student'.PHP_EOL; $xmlContent .= ' $@NULL@$'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' 5'.PHP_EOL; $xmlContent .= ' student'.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ''.PHP_EOL; file_put_contents($exportDir.'/roles.xml', $xmlContent); } /** * Export scales data to XML file. */ private function exportScalesXml(string $exportDir): void { $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ''; file_put_contents($exportDir.'/scales.xml', $xmlContent); } /** * Export the user XML with admin user data. */ private function exportUsersXml(string $exportDir): void { $adminData = self::getAdminUserData(); $xmlContent = ''.PHP_EOL; $xmlContent .= ''.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.$adminData['username'].''.PHP_EOL; $xmlContent .= ' '.$adminData['idnumber'].''.PHP_EOL; $xmlContent .= ' '.$adminData['email'].''.PHP_EOL; $xmlContent .= ' '.$adminData['phone1'].''.PHP_EOL; $xmlContent .= ' '.$adminData['phone2'].''.PHP_EOL; $xmlContent .= ' '.$adminData['institution'].''.PHP_EOL; $xmlContent .= ' '.$adminData['department'].''.PHP_EOL; $xmlContent .= '
'.$adminData['address'].'
'.PHP_EOL; $xmlContent .= ' '.$adminData['city'].''.PHP_EOL; $xmlContent .= ' '.$adminData['country'].''.PHP_EOL; $xmlContent .= ' '.$adminData['lastip'].''.PHP_EOL; $xmlContent .= ' '.$adminData['picture'].''.PHP_EOL; $xmlContent .= ' '.$adminData['description'].''.PHP_EOL; $xmlContent .= ' '.$adminData['descriptionformat'].''.PHP_EOL; $xmlContent .= ' '.$adminData['imagealt'].''.PHP_EOL; $xmlContent .= ' '.$adminData['auth'].''.PHP_EOL; $xmlContent .= ' '.$adminData['firstname'].''.PHP_EOL; $xmlContent .= ' '.$adminData['lastname'].''.PHP_EOL; $xmlContent .= ' '.$adminData['confirmed'].''.PHP_EOL; $xmlContent .= ' '.$adminData['policyagreed'].''.PHP_EOL; $xmlContent .= ' '.$adminData['deleted'].''.PHP_EOL; $xmlContent .= ' '.$adminData['lang'].''.PHP_EOL; $xmlContent .= ' '.$adminData['theme'].''.PHP_EOL; $xmlContent .= ' '.$adminData['timezone'].''.PHP_EOL; $xmlContent .= ' '.$adminData['firstaccess'].''.PHP_EOL; $xmlContent .= ' '.$adminData['lastaccess'].''.PHP_EOL; $xmlContent .= ' '.$adminData['lastlogin'].''.PHP_EOL; $xmlContent .= ' '.$adminData['currentlogin'].''.PHP_EOL; $xmlContent .= ' '.$adminData['mailformat'].''.PHP_EOL; $xmlContent .= ' '.$adminData['maildigest'].''.PHP_EOL; $xmlContent .= ' '.$adminData['maildisplay'].''.PHP_EOL; $xmlContent .= ' '.$adminData['autosubscribe'].''.PHP_EOL; $xmlContent .= ' '.$adminData['trackforums'].''.PHP_EOL; $xmlContent .= ' '.$adminData['timecreated'].''.PHP_EOL; $xmlContent .= ' '.$adminData['timemodified'].''.PHP_EOL; $xmlContent .= ' '.$adminData['trustbitmask'].''.PHP_EOL; // Preferences if (isset($adminData['preferences']) && is_array($adminData['preferences'])) { $xmlContent .= ' '.PHP_EOL; foreach ($adminData['preferences'] as $preference) { $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($preference['name']).''.PHP_EOL; $xmlContent .= ' '.htmlspecialchars($preference['value']).''.PHP_EOL; $xmlContent .= ' '.PHP_EOL; } $xmlContent .= ' '.PHP_EOL; } else { $xmlContent .= ' '.PHP_EOL; } // Roles (empty for now) $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= ' '.PHP_EOL; $xmlContent .= '
'.PHP_EOL; $xmlContent .= '
'; // Save the content to the users.xml file file_put_contents($exportDir.'/users.xml', $xmlContent); } /** * Export the backup settings, including dynamic settings for sections and activities. */ private function exportBackupSettings(array $sections, array $activities): array { // root-level settings $settings = [ ['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'], ['level' => 'root', 'name' => 'role_assignments', 'value' => '1'], ['level' => 'root', 'name' => 'activities', 'value' => '1'], ['level' => 'root', 'name' => 'blocks', 'value' => '1'], ['level' => 'root', 'name' => 'files', 'value' => '1'], ['level' => 'root', 'name' => 'filters', 'value' => '1'], ['level' => 'root', 'name' => 'comments', 'value' => '1'], ['level' => 'root', 'name' => 'badges', 'value' => '1'], ['level' => 'root', 'name' => 'calendarevents', 'value' => '1'], ['level' => 'root', 'name' => 'userscompletion', 'value' => '1'], ['level' => 'root', 'name' => 'logs', 'value' => '0'], ['level' => 'root', 'name' => 'grade_histories', 'value' => '0'], ['level' => 'root', 'name' => 'questionbank', 'value' => '1'], ['level' => 'root', 'name' => 'groups', 'value' => '1'], ['level' => 'root', 'name' => 'competencies', 'value' => '0'], ['level' => 'root', 'name' => 'customfield', 'value' => '1'], ['level' => 'root', 'name' => 'contentbankcontent', 'value' => '1'], ['level' => 'root', 'name' => 'legacyfiles', 'value' => '1'], ]; // section-level settings foreach ($sections as $section) { $settings[] = [ 'level' => 'section', 'section' => 'section_'.$section['id'], 'name' => 'section_'.$section['id'].'_included', 'value' => '1', ]; $settings[] = [ 'level' => 'section', 'section' => 'section_'.$section['id'], 'name' => 'section_'.$section['id'].'_userinfo', 'value' => '1', ]; } // activity-level settings foreach ($activities as $activity) { $settings[] = [ 'level' => 'activity', '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', 'value' => '1', ]; } return $settings; } }