<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @package moodlecore
* @subpackage backup-imscc
* @copyright 2009 Mauro Rondinelli (mauro.rondinelli [AT] uvcms.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
require_once($CFG->dirroot . '/backup/cc/entities.class.php');
require_once($CFG->dirroot . '/backup/cc/entity.label.class.php');
require_once($CFG->dirroot . '/backup/cc/entity.resource.class.php');
require_once($CFG->dirroot . '/backup/cc/entity.forum.class.php');
require_once($CFG->dirroot . '/backup/cc/entity.quiz.class.php');
class cc2moodle {
const CC_TYPE_FORUM = 'imsdt_xmlv1p0';
const CC_TYPE_QUIZ = 'imsqti_xmlv1p2/imscc_xmlv1p0/assessment';
const CC_TYPE_QUESTION_BANK = 'imsqti_xmlv1p2/imscc_xmlv1p0/question-bank';
const CC_TYPE_WEBLINK = 'imswl_xmlv1p0';
const CC_TYPE_WEBCONTENT = 'webcontent';
const CC_TYPE_ASSOCIATED_CONTENT = 'associatedcontent/imscc_xmlv1p0/learning-application-resource';
const CC_TYPE_EMPTY = '';
public static $restypes = array('associatedcontent/imscc_xmlv1p0/learning-application-resource', 'webcontent');
public static $forumns = array('dt' => 'http://www.imsglobal.org/xsd/imsdt_v1p0');
public static $quizns = array('xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2');
public static $resourcens = array('wl' => 'http://www.imsglobal.org/xsd/imswl_v1p0');
/**
*
* @return array
*/
public static function getquizns() {
return static::$quizns;
}
/**
*
* @return array
*/
public static function getforumns() {
return static::$forumns;
}
/**
*
* @return array
*/
public static function getresourcens() {
return static::$resourcens;
}
public static function get_manifest($folder) {
if (!is_dir($folder)) {
return false;
}
// Before iterate over directories, try to find one manifest at top level
if (file_exists($folder . '/imsmanifest.xml')) {
return $folder . '/imsmanifest.xml';
}
$result = false;
try {
$dirIter = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::KEY_AS_PATHNAME);
$recIter = new RecursiveIteratorIterator($dirIter, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($recIter as $info) {
if ($info->isFile() && ($info->getFilename() == 'imsmanifest.xml')) {
$result = $info->getPathname();
break;
}
}
} catch (Exception $e) {}
return $result;
}
public static $instances = array();
public static $manifest;
public static $path_to_manifest_folder;
public static $namespaces = array('imscc' => 'http://www.imsglobal.org/xsd/imscc/imscp_v1p1',
'lomimscc' => 'http://ltsc.ieee.org/xsd/imscc/LOM',
'lom' => 'http://ltsc.ieee.org/xsd/LOM',
'voc' => 'http://ltsc.ieee.org/xsd/LOM/vocab',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'cc' => 'http://www.imsglobal.org/xsd/imsccauth_v1p0');
function __construct ($path_to_manifest) {
static::$manifest = new DOMDocument();
static::$manifest->validateOnParse = false;
static::$path_to_manifest_folder = dirname($path_to_manifest);
static::log_action('Proccess start');
static::log_action('Load the manifest file: ' . $path_to_manifest);
if (!static::$manifest->load($path_to_manifest, LIBXML_NONET)) {
static::log_action('Cannot load the manifest file: ' . $path_to_manifest, true);
}
}
public function is_auth () {
$xpath = static::newx_path(static::$manifest, static::$namespaces);
$count_auth = $xpath->evaluate('count(/imscc:manifest/cc:authorizations)');
if ($count_auth > 0) {
$response = true;
} else {
$response = false;
}
return $response;
}
protected function get_metadata ($section, $key) {
$xpath = static::newx_path(static::$manifest, static::$namespaces);
$metadata = $xpath->query('/imscc:manifest/imscc:metadata/lomimscc:lom/lomimscc:' . $section . '/lomimscc:' . $key . '/lomimscc:string');
$value = !empty($metadata->item(0)->nodeValue) ? $metadata->item(0)->nodeValue : '';
return $value;
}
public function generate_moodle_xml () {
global $CFG, $OUTPUT;
$cdir = static::$path_to_manifest_folder . DIRECTORY_SEPARATOR . 'course_files';
if (!file_exists($cdir)) {
mkdir($cdir, $CFG->directorypermissions, true);
}
$sheet_base = static::loadsheet(SHEET_BASE);
// MOODLE_BACKUP / INFO / DETAILS / MOD
$node_info_details_mod = $this->create_code_info_details_mod();
// MOODLE_BACKUP / BLOCKS / BLOCK
$node_course_blocks_block = $this->create_node_course_blocks_block();
// MOODLE_BACKUP / COURSES / SECTIONS / SECTION
$node_course_sections_section = $this->create_node_course_sections_section();
// MOODLE_BACKUP / COURSES / QUESTION_CATEGORIES
$node_course_question_categories = $this->create_node_question_categories();
// MOODLE_BACKUP / COURSES / MODULES / MOD
$node_course_modules_mod = $this->create_node_course_modules_mod();
// MOODLE_BACKUP / COURSE / HEADER
$node_course_header = $this->create_node_course_header();
// GENERAL INFO
$filename = optional_param('file', 'not_available.zip', PARAM_RAW);
$filename = basename($filename);
$www_root = $CFG->wwwroot;
$find_tags = array('[#zip_filename#]',
'[#www_root#]',
'[#node_course_header#]',
'[#node_info_details_mod#]',
'[#node_course_blocks_block#]',
'[#node_course_sections_section#]',
'[#node_course_question_categories#]',
'[#node_course_modules#]');
$replace_values = array($filename,
$www_root,
$node_course_header,
$node_info_details_mod,
$node_course_blocks_block,
$node_course_sections_section,
$node_course_question_categories,
$node_course_modules_mod);
$result_xml = str_replace($find_tags, $replace_values, $sheet_base);
// COPY RESOURSE FILES
$entities = new entities();
$entities->move_all_files();
if (array_key_exists("index", self::$instances)) {
if (!file_put_contents(static::$path_to_manifest_folder . DIRECTORY_SEPARATOR . 'moodle.xml', $result_xml)) {
< static::log_action('Cannot save the moodle manifest file: ' . static::$path_to_tmp_folder . DIRECTORY_SEPARATOR . 'moodle.xml', true);
> static::log_action('Cannot save the moodle manifest file: ' . static::$path_to_manifest_folder . DIRECTORY_SEPARATOR . 'moodle.xml', true);
} else {
$status = true;
}
} else {
$status = false;
echo $OUTPUT->notification('The course is empty');
static::log_action('The course is empty', false);
}
return $status;
}
protected function get_sections_numbers ($instances) {
$count = 0;
if (array_key_exists("index", $instances)) {
foreach ($instances["index"] as $instance) {
if ($instance["deep"] == ROOT_DEEP) {
$count++;
}
}
}
return $count;
}
protected function create_node_course_header () {
$node_course_header = '';
$sheet_course_header = static::loadsheet(SHEET_COURSE_HEADER);
$course_title = trim($this->get_metadata('general', 'title'));
$course_title = empty($course_title) ? 'Untitled Course' : $course_title;
$course_description = $this->get_metadata('general', 'description');
$section_count = $this->get_sections_numbers(static::$instances) - 1;
if ($section_count == -1) {
$section_count = 0;
}
if (empty($course_title)) {
$this->log_action('The course title not found', true);
}
$course_short_name = $this->create_course_code($course_title);
$find_tags = array('[#course_name#]',
'[#course_short_name#]',
'[#course_description#]',
'[#date_now#]',
'[#section_count#]');
$replace_values = array(entities::safexml($course_title),
entities::safexml($course_short_name),
entities::safexml($course_description),
time(),
$section_count);
$node_course_header = str_replace($find_tags, $replace_values, $sheet_course_header);
return $node_course_header;
}
protected function create_node_question_categories () {
$quiz = new cc_quiz();
static::log_action('Creating node: QUESTION_CATEGORIES');
$node_course_question_categories = $quiz->generate_node_question_categories();
return $node_course_question_categories;
}
protected function create_node_course_modules_mod () {
$labels = new cc_label();
$resources = new cc_resource();
$forums = new cc_forum();
$quiz = new cc_quiz();
static::log_action('Creating node: COURSE/MODULES/MOD');
// LABELS
$node_course_modules_mod_label = $labels->generate_node();
// RESOURCES (WEB CONTENT AND WEB LINK)
$node_course_modules_mod_resource = $resources->generate_node();
// FORUMS
$node_course_modules_mod_forum = $forums->generate_node();
// QUIZ
$node_course_modules_mod_quiz = $quiz->generate_node_course_modules_mod();
//TODO: label
$node_course_modules = $node_course_modules_mod_label . $node_course_modules_mod_resource . $node_course_modules_mod_forum . $node_course_modules_mod_quiz;
return $node_course_modules;
}
protected function create_node_course_sections_section () {
static::log_action('Creating node: COURSE/SECTIONS/SECTION');
$node_course_sections_section = '';
$sheet_course_sections_section = static::loadsheet(SHEET_COURSE_SECTIONS_SECTION);
$topics = $this->get_nodes_by_criteria('deep', ROOT_DEEP);
$i = 0;
if (!empty($topics)) {
foreach ($topics as $topic) {
$i++;
$node_node_course_sections_section_mods_mod = $this->create_node_course_sections_section_mods_mod($topic['index']);
if ($topic['moodle_type'] == MOODLE_TYPE_LABEL) {
$find_tags = array('[#section_id#]',
'[#section_number#]',
'[#section_summary#]',
'[#node_course_sections_section_mods_mod#]');
$replace_values = array($i,
$i - 1,
entities::safexml($topic['title']),
$node_node_course_sections_section_mods_mod);
} else {
$find_tags = array('[#section_id#]',
'[#section_number#]',
'[#section_summary#]',
'[#node_course_sections_section_mods_mod#]');
$replace_values = array($i,
$i - 1,
'',
$node_node_course_sections_section_mods_mod);
}
$node_course_sections_section .= str_replace($find_tags, $replace_values, $sheet_course_sections_section);
}
}
return $node_course_sections_section;
}
protected function create_node_course_blocks_block () {
global $CFG;
static::log_action('Creating node: COURSE/BLOCKS/BLOCK');
$sheet_course_blocks_block = static::loadsheet(SHEET_COURSE_BLOCKS_BLOCK);
$node_course_blocks_block = '';
$format_config = $CFG->dirroot . '/course/format/weeks/config.php';
if (@is_file($format_config) && is_readable($format_config)) {
require ($format_config);
}
if (!empty($format['defaultblocks'])) {
$blocknames = $format['defaultblocks'];
} else {
if (isset($CFG->defaultblocks)) {
$blocknames = $CFG->defaultblocks;
} else {
$blocknames = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
}
}
$blocknames = explode(':', $blocknames);
$blocks_left = explode(',', $blocknames[0]);
$blocks_right = explode(',', $blocknames[1]);
$find_tags = array('[#block_id#]',
'[#block_name#]',
'[#block_position#]',
'[#block_weight#]');
$i = 0;
$weight = 0;
foreach ($blocks_left as $block) {
$i++;
$weight++;
$replace_values = array($i,
$block,
'l',
$weight);
$node_course_blocks_block .= str_replace($find_tags, $replace_values, $sheet_course_blocks_block);
}
$weight = 0;
foreach ($blocks_right as $block) {
$i++;
$weight ++;
$replace_values = array($i,
$block,
'r',
$weight);
$node_course_blocks_block .= str_replace($find_tags, $replace_values, $sheet_course_blocks_block);
}
return $node_course_blocks_block;
}
/**
*
* Is activity visible or not
* @param string $identifier
* @return number
*/
protected function get_module_visible($identifier) {
//Should item be hidden or not
$mod_visible = 1;
if (!empty($identifier)) {
$xpath = static::newx_path(static::$manifest, static::$namespaces);
$query = '/imscc:manifest/imscc:resources/imscc:resource[@identifier="' . $identifier . '"]';
$query .= '//lom:intendedEndUserRole/voc:vocabulary/lom:value';
$intendeduserrole = $xpath->query($query);
if (!empty($intendeduserrole) && ($intendeduserrole->length > 0)) {
$role = trim($intendeduserrole->item(0)->nodeValue);
if (strcasecmp('Instructor', $role) == 0) {
$mod_visible = 0;
}
}
}
return $mod_visible;
}
protected function create_node_course_sections_section_mods_mod ($root_parent) {
$sheet_course_sections_section_mods_mod = static::loadsheet(SHEET_COURSE_SECTIONS_SECTION_MODS_MOD);
$childs = $this->get_nodes_by_criteria('root_parent', $root_parent);
if ($childs) {
$node_course_sections_section_mods_mod = '';
foreach ($childs as $child) {
if ($child['moodle_type'] == MOODLE_TYPE_LABEL) {
if ($child['index'] == $child['root_parent']) {
$is_summary = true;
} else {
$is_summary = false;
}
} else {
$is_summary = false;
}
if (!$is_summary) {
$indent = $child['deep'] - ROOT_DEEP;
if ($indent > 0) {
$indent = $indent - 1;
}
$find_tags = array('[#mod_id#]',
'[#mod_instance_id#]',
'[#mod_type#]',
'[#date_now#]',
'[#mod_indent#]',
'[#mod_visible#]');
$replace_values = array($child['index'],
$child['instance'],
$child['moodle_type'],
time(),
$indent,
$this->get_module_visible($child['resource_indentifier']));
$node_course_sections_section_mods_mod .= str_replace($find_tags, $replace_values, $sheet_course_sections_section_mods_mod);
}
}
$response = $node_course_sections_section_mods_mod;
} else {
$response = '';
}
return $response;
}
public function get_nodes_by_criteria ($key, $value) {
$response = array();
if (array_key_exists('index', static::$instances)) {
foreach (static::$instances['index'] as $item) {
if ($item[$key] == $value) {
$response[] = $item;
}
}
}
return $response;
}
//Modified here
protected function create_code_info_details_mod () {
static::log_action('Creating node: INFO/DETAILS/MOD');
$xpath = static::newx_path(static::$manifest, static::$namespaces);
$items = $xpath->query('/imscc:manifest/imscc:organizations/imscc:organization/imscc:item | /imscc:manifest/imscc:resources/imscc:resource[@type="' . static::CC_TYPE_QUESTION_BANK . '"]');
$this->create_instances($items);
$count_quiz = $this->count_instances(MOODLE_TYPE_QUIZ);
$count_forum = $this->count_instances(MOODLE_TYPE_FORUM);
$count_resource = $this->count_instances(MOODLE_TYPE_RESOURCE);
$count_label = $this->count_instances(MOODLE_TYPE_LABEL);
$sheet_info_details_mod_instances_instance = static::loadsheet(SHEET_INFO_DETAILS_MOD_INSTANCE);
if ($count_resource > 0) {
$resource_instance = $this->create_mod_info_details_mod_instances_instance($sheet_info_details_mod_instances_instance, $count_resource, static::$instances['instances'][MOODLE_TYPE_RESOURCE]);
}
if ($count_quiz > 0) {
$quiz_instance = $this->create_mod_info_details_mod_instances_instance($sheet_info_details_mod_instances_instance, $count_quiz, static::$instances['instances'][MOODLE_TYPE_QUIZ]);
}
if ($count_forum > 0) {
$forum_instance = $this->create_mod_info_details_mod_instances_instance($sheet_info_details_mod_instances_instance, $count_forum, static::$instances['instances'][MOODLE_TYPE_FORUM]);
}
if ($count_label > 0) {
$label_instance = $this->create_mod_info_details_mod_instances_instance($sheet_info_details_mod_instances_instance, $count_label, static::$instances['instances'][MOODLE_TYPE_LABEL]);
}
$resource_mod = $count_resource ? $this->create_mod_info_details_mod(MOODLE_TYPE_RESOURCE, $resource_instance) : '';
$quiz_mod = $count_quiz ? $this->create_mod_info_details_mod(MOODLE_TYPE_QUIZ, $quiz_instance) : '';
$forum_mod = $count_forum ? $this->create_mod_info_details_mod(MOODLE_TYPE_FORUM, $forum_instance) : '';
$label_mod = $count_label ? $this->create_mod_info_details_mod(MOODLE_TYPE_LABEL, $label_instance) : '';
//TODO: label
return $label_mod . $resource_mod . $quiz_mod . $forum_mod;
}
protected function create_mod_info_details_mod ($mod_type, $node_info_details_mod_instances_instance) {
$sheet_info_details_mod = static::loadsheet(SHEET_INFO_DETAILS_MOD);
$find_tags = array('[#mod_type#]' ,'[#node_info_details_mod_instances_instance#]');
$replace_values = array($mod_type , $node_info_details_mod_instances_instance);
return str_replace($find_tags, $replace_values, $sheet_info_details_mod);
}
protected function create_mod_info_details_mod_instances_instance ($sheet, $instances_quantity, $instances) {
$instance = '';
$find_tags = array('[#mod_instance_id#]',
'[#mod_name#]',
'[#mod_user_info#]');
for ($i = 1; $i <= $instances_quantity; $i++) {
$user_info = ($instances[$i - 1]['common_cartriedge_type'] == static::CC_TYPE_FORUM) ? 'true' : 'false';
if ($instances[$i - 1]['common_cartriedge_type'] == static::CC_TYPE_EMPTY) {
if ($instances[$i - 1]['deep'] <= ROOT_DEEP ) {
continue;
}
}
$replace_values = array($instances[$i - 1]['instance'],
entities::safexml($instances[$i - 1]['title']),
$user_info);
$instance .= str_replace($find_tags, $replace_values, $sheet);
}
return $instance;
}
protected function create_instances ($items, $level = 0, &$array_index = 0, $index_root = 0) {
$level++;
$i = 1;
if ($items) {
$xpath = self::newx_path(static::$manifest, static::$namespaces);
foreach ($items as $item) {
$array_index++;
if ($item->nodeName == "item") {
$identifierref = '';
if ($item->hasAttribute('identifierref')) {
$identifierref = $item->getAttribute('identifierref');
}
$title = '';
$titles = $xpath->query('imscc:title', $item);
if ($titles->length > 0) {
$title = $titles->item(0)->nodeValue;
}
$cc_type = $this->get_item_cc_type($identifierref);
$moodle_type = $this->convert_to_moodle_type($cc_type);
//Fix the label issue - MDL-33523
if (empty($identifierref) && empty($title)) {
$moodle_type = TYPE_UNKNOWN;
}
}
elseif ($item->nodeName == "resource") {
$identifierref = $xpath->query('@identifier', $item);
$identifierref = !empty($identifierref->item(0)->nodeValue) ? $identifierref->item(0)->nodeValue : '';
$cc_type = $this->get_item_cc_type($identifierref);
$moodle_type = $this->convert_to_moodle_type($cc_type);
$title = 'Quiz Bank ' . ($this->count_instances($moodle_type) + 1);
}
if ($level == ROOT_DEEP) {
$index_root = $array_index;
}
static::$instances['index'][$array_index]['common_cartriedge_type'] = $cc_type;
static::$instances['index'][$array_index]['moodle_type'] = $moodle_type;
static::$instances['index'][$array_index]['title'] = $title ? $title : '';
static::$instances['index'][$array_index]['root_parent'] = $index_root;
static::$instances['index'][$array_index]['index'] = $array_index;
static::$instances['index'][$array_index]['deep'] = $level;
static::$instances['index'][$array_index]['instance'] = $this->count_instances($moodle_type);
static::$instances['index'][$array_index]['resource_indentifier'] = $identifierref;
static::$instances['instances'][$moodle_type][] = array('title' => $title,
'instance' => static::$instances['index'][$array_index]['instance'],
'common_cartriedge_type' => $cc_type,
'resource_indentifier' => $identifierref,
'deep' => $level);
$more_items = $xpath->query('imscc:item', $item);
if ($more_items->length > 0) {
$this->create_instances($more_items, $level, $array_index, $index_root);
}
$i++;
}
}
}
public function count_instances ($type) {
$quantity = 0;
if (array_key_exists('index', static::$instances)) {
if (static::$instances['index'] && $type) {
foreach (static::$instances['index'] as $instance) {
if (!empty($instance['moodle_type'])) {
$types[] = $instance['moodle_type'];
}
}
$quantity_instances = array_count_values($types);
$quantity = array_key_exists($type, $quantity_instances) ? $quantity_instances[$type] : 0;
}
}
return $quantity;
}
public function convert_to_moodle_type ($cc_type) {
$type = TYPE_UNKNOWN;
if ($cc_type == static::CC_TYPE_FORUM) {
$type = MOODLE_TYPE_FORUM;
}
if ($cc_type == static::CC_TYPE_QUIZ) {
$type = MOODLE_TYPE_QUIZ;
}
if ($cc_type == static::CC_TYPE_WEBLINK) {
$type = MOODLE_TYPE_RESOURCE;
}
if ($cc_type == static::CC_TYPE_WEBCONTENT) {
$type = MOODLE_TYPE_RESOURCE;
}
if ($cc_type == static::CC_TYPE_ASSOCIATED_CONTENT) {
$type = MOODLE_TYPE_RESOURCE;
}
if ($cc_type == static::CC_TYPE_QUESTION_BANK) {
$type = MOODLE_TYPE_QUESTION_BANK;
}
//TODO: label
if ($cc_type == static::CC_TYPE_EMPTY) {
$type = MOODLE_TYPE_LABEL;
}
return $type;
}
public function get_item_cc_type ($identifier) {
$xpath = static::newx_path(static::$manifest, static::$namespaces);
$nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="' . $identifier . '"]/@type');
if ($nodes && !empty($nodes->item(0)->nodeValue)) {
return $nodes->item(0)->nodeValue;
} else {
return '';
}
}
public static function newx_path (DOMDocument $manifest, $namespaces = '') {
$xpath = new DOMXPath($manifest);
if (!empty($namespaces)) {
foreach ($namespaces as $prefix => $ns) {
if (!$xpath->registerNamespace($prefix, $ns)) {
static::log_action('Cannot register the namespace: ' . $prefix . ':' . $ns, true);
}
}
}
return $xpath;
}
public static function loadsheet ($file) {
$content = (is_readable($file) && ($content = file_get_contents($file))) ? $content : false;
static::log_action('Loading sheet: ' . $file);
if (!$content) {
static::log_action('Cannot load the xml sheet: ' . $file, true);
}
static::log_action('Load OK!');
return $content;
}
public static function log_file() {
return static::$path_to_manifest_folder . DIRECTORY_SEPARATOR . 'cc2moodle.log';
}
public static function log_action ($text, $critical_error = false) {
$full_message = strtoupper(date("j/n/Y g:i:s a")) . " - " . $text . "\r";
file_put_contents(static::log_file(), $full_message, FILE_APPEND);
if ($critical_error) {
static::critical_error($text);
}
}
protected static function critical_error ($text) {
$path_to_log = static::log_file();
echo '
<p>
<hr />A critical error has been found!
<p>' . $text . '</p>
<p>
The process has been stopped. Please see the <a href="' . $path_to_log . '">log file</a> for more information.</p>
<p>Log: ' . $path_to_log . '</p>
<hr />
</p>
';
die();
}
protected function create_course_code ($title) {
//Making sure that text of the short name does not go over the DB limit.
//and leaving the space to add additional characters by the platform
$code = substr(strtoupper(str_replace(' ', '', trim($title))),0,94);
return $code;
}
}