This commit is contained in:
Xes
2025-08-14 22:37:50 +02:00
parent fb6d5d5926
commit 3641e93527
9156 changed files with 1813532 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'common_cartridge/export/src/lib/ccdependencyparser.php';
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
use Chamilo\CourseBundle\Component\CourseCopy\CourseSelectForm;
$current_course_tool = TOOL_COURSE_MAINTENANCE;
api_protect_course_script(true);
// Check access rights (only teachers are allowed here)
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
api_check_archive_dir();
api_set_more_memory_and_time_limits();
// Section for the tabs
$this_section = SECTION_COURSES;
// Breadcrumbs
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'course_info/maintenance.php',
'name' => get_lang('Maintenance'),
];
// Displaying the header
$nameTools = get_lang('ExportCcVersion13');
Display::display_header($nameTools);
// Display the tool title
echo Display::page_header($nameTools);
$action = isset($_POST['action']) ? $_POST['action'] : '';
$backupOption = 'select_items';
if (Security::check_token('post') && ($action === 'course_select_form')) {
// Clear token
Security::clear_token();
$resources = Security::remove_XSS($_POST['resource']);
if (!empty($resources)) {
$cb = new CourseBuilder('partial');
// Build the course object with all selected resources
/* @var \Chamilo\CourseBundle\Component\CourseCopy\Course $course */
$course = $cb->build(0, null, false, array_keys($resources), $resources);
$course = CourseSelectForm::get_posted_course(null, 0, '', $course);
$imsccFile = Cc13ExportConvert::export($course);
if ($imsccFile !== false) {
echo Display::return_message(get_lang('IMSCCCreated'), 'confirm');
echo '<br />';
echo Display::toolbarButton(
get_lang('Download'),
api_get_path(WEB_CODE_PATH).'course_info/download.php?archive='.$imsccFile.'&'.api_get_cidreq(),
'file-zip-o',
'primary'
);
/*echo Display::url(
get_lang('Download'),
api_get_path(WEB_CODE_PATH).'course_info/download.php?archive='.$imsccFile.'&'.api_get_cidreq(),
['class' => 'btn btn-primary btn-large']
);*/
}
}
} else {
// Clear token
Security::clear_token();
$cb = new CourseBuilder('partial');
$toolsToBuild = [
RESOURCE_DOCUMENT,
RESOURCE_FORUMCATEGORY,
RESOURCE_FORUM,
RESOURCE_FORUMTOPIC,
RESOURCE_QUIZ,
RESOURCE_TEST_CATEGORY,
RESOURCE_LINK,
RESOURCE_WIKI,
];
$course = $cb->build(0, null, false, $toolsToBuild);
if ($course->has_resources()) {
// Add token to Course select form
$hiddenFields['sec_token'] = Security::get_token();
CourseSelectForm::display_form($course, $hiddenFields, false, true, true);
} else {
echo Display::return_message(get_lang('NoResourcesToBackup'), 'warning');
}
}
Display::display_footer();

View File

@@ -0,0 +1,77 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'common_cartridge/import/src/lib/validateurlsyntax.php';
require_once api_get_path(SYS_CODE_PATH).'common_cartridge/import/src/inc/constants.php';
$current_course_tool = TOOL_COURSE_MAINTENANCE;
api_protect_course_script(true);
// Check access rights (only teachers are allowed here)
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
api_set_more_memory_and_time_limits();
// Section for the tabs
$this_section = SECTION_COURSES;
// Breadcrumbs
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'course_info/maintenance.php?'.api_get_cidreq(),
'name' => get_lang('Maintenance'),
];
$form = new FormValidator('cc_import', 'post', api_get_self().'?'.api_get_cidreq());
$form->addFile('cc_file', get_lang('IMSCCFile'));
$form->addButtonImport(get_lang('Import'));
if ($form->validate()) {
$file = $_FILES['cc_file'];
if (empty($file['tmp_name'])) {
$errorMessage = get_lang('UplUploadFailed');
echo Display::return_message($errorMessage, 'error', false);
} else {
$allowedFileMimetype = ['imscc'];
$extImportFile = substr($file['name'], (strrpos($file['name'], '.') + 1));
if (!in_array($extImportFile, $allowedFileMimetype)) {
echo Display::return_message(get_lang('YouMustImportAFileAccordingToSelectedOption'), 'error');
} else {
// Unzip the whole archive into app/cache/imsccImport/, which is a *temporary* directory
$baseDir = api_get_path(SYS_ARCHIVE_PATH);
$uploadPath = 'imsccImport/';
$errors = [];
if (!is_dir($baseDir.$uploadPath)) {
@mkdir($baseDir.$uploadPath);
}
$filepath = $baseDir.$uploadPath;
if (!Imscc13Import::unzip($file['tmp_name'], $filepath)) {
return false;
}
// We detect if it is cc v1.3
$detected = Imscc13Import::detectFormat($filepath);
if ($detected) {
$importObject = new Imscc13Import();
$importObject->execute($filepath);
Display::addFlash(Display::return_message(get_lang('IMSCCFileImported'), 'normal', false));
}
}
}
}
$template = new Template(get_lang('ImportCcVersion13'));
Display::addFlash(Display::return_message(get_lang('IMSCCImportInstructions'), 'normal', false));
$template->assign('form', $form->returnForm());
$templateName = $template->get_template('common_cartridge/import_cc.tpl');
$content = $template->fetch($templateName);
$template->assign('header', get_lang('ImportCcVersion13'));
$template->assign('content', $content);
$template->display_one_col_template();

View File

@@ -0,0 +1,360 @@
<?php
/* For licensing terms, see /license.txt */
class Cc13Convert
{
/**
* Converts a course object into a CC13 package and writes it to disk.
*
* @param \Chamilo\CourseBundle\Component\CourseCopy\Course $objCourse The Course object is "augmented" with info from the api_get_course_info() function, into the "$objCourse->info" array attribute.
*
* @throws Exception
*
* @return bool
*/
public static function convert(string $packagedir, string $outdir, Chamilo\CourseBundle\Component\CourseCopy\Course $objCourse)
{
$dir = realpath($packagedir);
if (empty($dir)) {
throw new InvalidArgumentException('Directory does not exist!');
}
$odir = realpath($outdir);
if (empty($odir)) {
throw new InvalidArgumentException('Directory does not exist!');
}
if (!empty($objCourse)) {
//Initialize the manifest metadata class
$meta = new CcMetadataManifest();
//Package metadata
$metageneral = new CcMetadataGeneral();
$metageneral->setLanguage($objCourse->info['language']);
$metageneral->setTitle($objCourse->info['title'], $objCourse->info['language']);
$metageneral->setDescription('', $objCourse->info['language']);
$metageneral->setCatalog('category');
$metageneral->setEntry($objCourse->info['categoryName']);
$meta->addMetadataGeneral($metageneral);
// Create the manifest
$manifest = new CcManifest();
$manifest->addMetadataManifest($meta);
$organization = null;
//Get the course structure - this will be transformed into organization
//Step 1 - Get the list and order of sections/topics
$count = 1;
$sections = [];
$resources = $objCourse->resources;
// We check the quiz sections
if (isset($resources['quiz'])) {
$quizSections = self::getItemSections(
$resources['quiz'], // array of quiz IDs generated by the course backup process
'quiz',
$count,
$objCourse->info['code'],
$resources[RESOURCE_QUIZQUESTION] // selected question IDs from the course export form
);
$sections = array_merge($sections, $quizSections);
}
// We check the document sections
if (isset($resources['document'])) {
$documentSections = self::getItemSections(
$resources['document'],
'document',
$count,
$objCourse->info['code']
);
$sections = array_merge($sections, $documentSections);
}
// We check the wiki sections
if (isset($resources['wiki'])) {
$wikiSections = self::getItemSections(
$resources['wiki'],
'wiki',
$count,
$objCourse->info['code']
);
$sections = array_merge($sections, $wikiSections);
}
// We check the forum sections
if (isset($resources['forum'])) {
$forumSections = self::getItemSections(
$resources['forum'],
'forum',
$count,
$objCourse->info['code'],
$resources['Forum_Category']
);
$sections = array_merge($sections, $forumSections);
}
// We check the link sections
if (isset($resources['link'])) {
$linkSections = self::getItemSections(
$resources['link'],
'link',
$count,
$objCourse->info['code'],
$resources['Link_Category']
);
$sections = array_merge($sections, $linkSections);
}
//organization title
$organization = new CcOrganization();
foreach ($sections as $sectionid => $values) {
$item = new CcItem();
$item->title = $values[0];
self::processSequence($item, $manifest, $values[1], $dir, $odir);
$organization->addItem($item);
}
$manifest->putNodes();
if (!empty($organization)) {
$manifest->addNewOrganization($organization);
}
$manifestpath = $outdir.DIRECTORY_SEPARATOR.'imsmanifest.xml';
$saved = $manifest->saveTo($manifestpath);
return $saved;
}
return false;
}
/**
* Return array of type $sections[1]['quiz', [sequence]] where sequence is the result of a call to getSequence().
*
* @param string $courseCode The course code litteral
* @param ?array $itmesExtraData If defined, represents the items IDs selected in the course export form
*
* @return array
* @reference self::getSequence()
*/
protected static function getItemSections(array $itemData, string $itemType, int &$count, string $courseCode, ?array $itmesExtraData = null)
{
$sections = [];
switch ($itemType) {
case 'quiz':
case 'document':
case 'wiki':
$convertType = $itemType;
if ($itemType == 'wiki') {
$convertType = 'Page';
}
$sectionid = $count;
$sectiontitle = ucfirst($itemType);
$sequence = self::getSequence($itemData, 0, $convertType, $courseCode, $itmesExtraData);
$sections[$sectionid] = [$sectiontitle, $sequence];
$count++;
break;
case 'link':
$links = self::getSequence($itemData, null, $itemType);
foreach ($links as $categoryId => $sequence) {
$sectionid = $count;
if (isset($itmesExtraData[$categoryId])) {
$sectiontitle = $itmesExtraData[$categoryId]->title;
} else {
$sectiontitle = 'General';
}
$sections[$sectionid] = [$sectiontitle, $sequence];
$count++;
}
break;
case 'forum':
if (isset($itmesExtraData)) {
foreach ($itmesExtraData as $fcategory) {
if (isset($fcategory->obj)) {
$objCategory = $fcategory->obj;
$sectionid = $count;
$sectiontitle = $objCategory->cat_title;
$sequence = self::getSequence($itemData, $objCategory->iid, $itemType);
$sections[$sectionid] = [$sectiontitle, $sequence];
$count++;
}
}
}
break;
}
return $sections;
}
/**
* Return array of items by category and item ID ("test" level, not "question" level) with details like title,
* comment (description), type, questions, max_attempt, etc.
*
* @param array $objItems Array of item objects as returned by the course backup code
* @param ?int $categoryId
* @param ?string $itemType
* @param ?string $coursecode
* @param ?array $itemQuestions
*
* @return array|mixed
*/
protected static function getSequence(array $objItems, ?int $categoryId = null, ?string $itemType = null, ?string $coursecode = null, ?array $itemQuestions = null)
{
$sequences = [];
switch ($itemType) {
case 'quiz':
$sequence = [];
foreach ($objItems as $objItem) {
if ($categoryId === 0) {
$questions = [];
foreach ($objItem->obj->question_ids as $questionId) {
if (isset($itemQuestions[$questionId])) {
$questions[$questionId] = $itemQuestions[$questionId];
}
}
// As weird as this may sound, the constructors for the different object types (found in
// src/CourseBundle/Component/CourseCopy/Resources/[objecttype].php) store the object property
// in the "obj" attribute. Old code...
// So here we recover properties from the quiz object, including questions (array built above).
$sequence[$categoryId][$objItem->obj->iid] = [
'title' => $objItem->obj->title,
'comment' => $objItem->obj->description,
'cc_type' => 'quiz',
'source_id' => $objItem->obj->iid,
'questions' => $questions,
'max_attempt' => $objItem->obj->max_attempt,
'expired_time' => $objItem->obj->expired_time,
'pass_percentage' => $objItem->obj->pass_percentage,
'random_answers' => $objItem->obj->random_answers,
'course_code' => $coursecode,
];
}
}
$sequences = $sequence[$categoryId];
break;
case 'document':
$sequence = [];
foreach ($objItems as $objItem) {
if ($categoryId === 0) {
$sequence[$categoryId][$objItem->source_id] = [
'title' => $objItem->title,
'comment' => $objItem->comment,
'cc_type' => ($objItem->file_type == 'folder' ? 'folder' : 'resource'),
'source_id' => $objItem->source_id,
'path' => $objItem->path,
'file_type' => $objItem->file_type,
'course_code' => $coursecode,
];
}
}
$sequences = $sequence[$categoryId];
break;
case 'forum':
foreach ($objItems as $objItem) {
if ($categoryId == $objItem->obj->forum_category) {
$sequence[$categoryId][$objItem->obj->forum_id] = [
'title' => $objItem->obj->forum_title,
'comment' => $objItem->obj->forum_comment,
'cc_type' => 'forum',
'source_id' => $objItem->obj->iid,
];
}
}
$sequences = $sequence[$categoryId];
break;
case 'page':
foreach ($objItems as $objItem) {
if ($categoryId === 0) {
$sequence[$categoryId][$objItem->page_id] = [
'title' => $objItem->title,
'comment' => $objItem->content,
'cc_type' => 'page',
'source_id' => $objItem->page_id,
'reflink' => $objItem->reflink,
];
}
}
$sequences = $sequence[$categoryId];
break;
case 'link':
if (!isset($categoryId)) {
$categories = [];
foreach ($objItems as $objItem) {
$categories[$objItem->category_id] = self::getSequence($objItems, $objItem->category_id, $itemType);
}
$sequences = $categories;
} else {
foreach ($objItems as $objItem) {
if ($categoryId == $objItem->category_id) {
$sequence[$categoryId][$objItem->source_id] = [
'title' => $objItem->title,
'comment' => $objItem->description,
'cc_type' => 'url',
'source_id' => $objItem->source_id,
'url' => $objItem->url,
'target' => $objItem->target,
];
}
}
$sequences = $sequence[$categoryId];
}
break;
}
return $sequences;
}
/**
* Process the different types of activities exported from the course.
* When dealing with tests, the "sequence" provided here is a test, not a question.
* For each sequence, call the corresponding CcConverter[Type] object instantiation method in export/src/converter/.
*
* @return void
*/
protected static function processSequence(CcIItem &$item, CcIManifest &$manifest, array $sequence, string $packageroot, string $outdir)
{
if (!empty($sequence)) {
foreach ($sequence as $seq) {
$activity_type = ucfirst($seq['cc_type']);
$activity_indentation = 0;
$aitem = self::itemIndenter($item, $activity_indentation);
$caller = "CcConverter{$activity_type}";
if (class_exists($caller)) {
$obj = new $caller($aitem, $manifest, $packageroot, $outdir);
if (!$obj->convert($outdir, $seq)) {
throw new RuntimeException("failed to convert {$activity_type}");
}
}
}
}
}
protected static function itemIndenter(CcIItem &$item, $level = 0)
{
$indent = (int) $level;
$indent = ($indent) <= 0 ? 0 : $indent;
$nprev = null;
$nfirst = null;
for ($pos = 0, $size = $indent; $pos < $size; $pos++) {
$nitem = new CcItem();
$nitem->title = '';
if (empty($nfirst)) {
$nfirst = $nitem;
}
if (!empty($nprev)) {
$nprev->addChildItem($nitem);
}
$nprev = $nitem;
}
$result = $item;
if (!empty($nfirst)) {
$item->addChildItem($nfirst);
$result = $nprev;
}
return $result;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Component\CourseCopy\CourseArchiver;
class Cc13ExportConvert
{
/**
* Export the CommonCartridge object to the app/cache/course_backups/CourseCC13Archiver_[hash] directory.
*
* @param \Chamilo\CourseBundle\Component\CourseCopy\Course $objCourse
*
* @return false|string
*/
public static function export($objCourse)
{
$permDirs = api_get_permissions_for_new_directories();
$backupDirectory = CourseArchiver::getBackupDir();
// Create a temp directory
$backupDir = $backupDirectory.'CourseCC13Archiver_'.api_get_unique_id();
if (mkdir($backupDir, $permDirs, true)) {
$converted = Cc13Convert::convert($backupDirectory, $backupDir, $objCourse);
if ($converted) {
$imsccFileName = self::createImscc($backupDir, $objCourse);
return $imsccFileName;
}
}
return false;
}
/**
* @param $backupDir
* @param $objCourse
*
* @throws Exception
*
* @return string Filename of the created .imscc (zip) file
*/
public static function createImscc($backupDir, $objCourse)
{
$backupDirectory = CourseArchiver::getBackupDir();
$date = new \DateTime(api_get_local_time());
$imsccFileName = $objCourse->info['code'].'_'.$date->format('Ymd-His').'.imscc';
$imsccFilePath = $backupDirectory.$imsccFileName;
// Zip the course-contents
$zip = new \PclZip($imsccFilePath);
$zip->create($backupDir, PCLZIP_OPT_REMOVE_PATH, $backupDir);
// Remove the temp-dir.
rmdirr($backupDir);
return $imsccFileName;
}
}

View File

@@ -0,0 +1,49 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_forum.php under GNU/GPL license */
class CcForum extends CcGeneralFile
{
public const DEAFULTNAME = 'discussion.xml';
protected $rootns = 'dt';
protected $rootname = 'topic';
protected $ccnamespaces = ['dt' => 'http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', ];
protected $ccnsnames = ['dt' => 'http://www.imsglobal.org/profile/cc/ccv1p3/ccv1p3_imsdt_v1p3.xsd'];
protected $title = null;
protected $textType = 'text/plain';
protected $text = null;
protected $attachments = [];
public function setTitle($title)
{
$this->title = self::safexml($title);
}
public function setText($text, $type = 'text/plain')
{
$this->text = self::safexml($text);
$this->textType = $type;
}
public function setAttachments(array $attachments)
{
$this->attachments = $attachments;
}
protected function onSave()
{
$rns = $this->ccnamespaces[$this->rootns];
$this->appendNewElementNs($this->root, $rns, 'title', $this->title);
$text = $this->appendNewElementNs($this->root, $rns, 'text', $this->text);
$this->appendNewAttributeNs($text, $rns, 'texttype', $this->textType);
if (!empty($this->attachments)) {
$attachments = $this->appendNewElementNs($this->root, $rns, 'attachments');
foreach ($this->attachments as $value) {
$att = $this->appendNewElementNs($attachments, $rns, 'attachment');
$this->appendNewAttributeNs($att, $rns, 'href', $value);
}
}
return true;
}
}

View File

@@ -0,0 +1,151 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Item Class.
*/
class CcItem implements CcIItem
{
public $identifier = null;
public $identifierref = null;
public $isvisible = null;
public $title = null;
public $parameters = null;
public $childitems = null;
private $parentItem = null;
private $isempty = true;
public function __construct($node = null, $doc = null)
{
if (is_object($node)) {
$clname = get_class($node);
if ($clname == 'CcResource') {
$this->initNewItem();
$this->identifierref = $node->identifier;
$this->title = is_string($doc) && (!empty($doc)) ? $doc : 'item';
} elseif ($clname == 'CcManifest') {
$this->initNewItem();
$this->identifierref = $node->manifestID();
$this->title = is_string($doc) && (!empty($doc)) ? $doc : 'item';
} elseif (is_object($doc)) {
$this->processItem($node, $doc);
} else {
$this->initNewItem();
}
} else {
$this->initNewItem();
}
}
public function attrValue(&$nod, $name, $ns = null)
{
return is_null($ns) ?
($nod->hasAttribute($name) ? $nod->getAttribute($name) : null) :
($nod->hasAttributeNS($ns, $name) ? $nod->getAttributeNS($ns, $name) : null);
}
public function processItem(&$node, &$doc)
{
$this->identifier = $this->attrValue($node, "identifier");
$this->structure = $this->attrValue($node, "structure");
$this->identifierref = $this->attrValue($node, "identifierref");
$atr = $this->attrValue($node, "isvisible");
$this->isvisible = is_null($atr) ? true : $atr;
$nlist = $node->getElementsByTagName('title');
if (is_object($nlist) && ($nlist->length > 0)) {
$this->title = $nlist->item(0)->nodeValue;
}
$nlist = $doc->nodeList("//imscc:item[@identifier='".$this->identifier."']/imscc:item");
if ($nlist->length > 0) {
$this->childitems = [];
foreach ($nlist as $item) {
$key = $this->attrValue($item, "identifier");
$this->childitems[$key] = new CcItem($item, $doc);
}
}
$this->isempty = false;
}
/**
* Add one Child Item.
*/
public function addChildItem(CcIItem &$item)
{
if (is_null($this->childitems)) {
$this->childitems = [];
}
$this->childitems[$item->identifier] = $item;
}
/**
* Add new child Item.
*
* @param string $title
*
* @return CcIItem
*/
public function add_new_child_item($title = '')
{
$sc = new CcItem();
$sc->title = $title;
$this->addChildItem($sc);
return $sc;
}
public function attachResource($resource)
{
if ($this->hasChildItems()) {
throw new Exception("Can not attach resource to item that contains other items!");
}
$resident = null;
if (is_string($resource)) {
$resident = $resource;
} elseif (is_object($resource)) {
$clname = get_class($resource);
if ($clname == 'CcResource') {
$resident = $resource->identifier;
} elseif ($clname == 'CcManifest') {
$resident = $resource->manifestID();
} else {
throw new Exception("Unable to attach resource. Invalid object.");
}
}
if (is_null($resident) || (empty($resident))) {
throw new Exception("Resource must have valid identifier!");
}
$this->identifierref = $resident;
}
public function hasChildItems()
{
return is_array($this->childitems) && (count($this->childitems) > 0);
}
public function child_item($identifier)
{
return $this->hasChildItems() ? $this->childitems[$identifier] : null;
}
public function initClean()
{
$this->identifier = null;
$this->isvisible = null;
$this->title = null;
$this->parameters = null;
$this->childitems = null;
$this->parentItem = null;
$this->isempty = true;
}
public function initNewItem()
{
$this->identifier = CcHelpers::uuidgen('I_');
$this->isvisible = true; //default is true
$this->title = null;
$this->parameters = null;
$this->childitems = null;
$this->parentItem = null;
$this->isempty = false;
}
}

View File

@@ -0,0 +1,329 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_manifest.php under GNU/GPL license */
class CcManifest extends XMLGenericDocument implements CcIManifest
{
private $ccversion = null;
private $ccobj = null;
private $rootmanifest = null;
private $activemanifest = null;
private $parentmanifest = null;
private $parentparentmanifest = null;
private $ares = [];
private $mainidentifier = null;
public function __construct($ccver = 13, $activemanifest = null,
$parentmanifest = null, $parentparentmanifest = null)
{
$this->ccversion = $ccver;
$this->ccobj = new CcVersion13();
parent::__construct('UTF-8', true);
}
/**
* Register Namespace for use XPATH.
*/
public function registerNamespacesForXpath()
{
$scnam = $this->activemanifest->getCcNamespaces();
foreach ($scnam as $key => $value) {
$this->registerNS($key, $value);
}
}
/**
* Add Metadata For Manifest.
*/
public function addMetadataManifest(CcIMetadataManifest $met)
{
$metanode = $this->node("//imscc:manifest[@identifier='".
$this->activemanifest->manifestID().
"']/imscc:metadata");
$nmeta = $this->activemanifest->createMetadataNode($met, $this->doc, $metanode);
$metanode->appendChild($nmeta);
}
/**
* Add Metadata For Resource.
*
* @param string $identifier
*/
public function addMetadataResource(CcIMetadataResource $met, $identifier)
{
$metanode = $this->node("//imscc:resource".
"[@identifier='".
$identifier.
"']");
$metanode2 = $this->node("//imscc:resource".
"[@identifier='".
$identifier.
"']/imscc:file");
$nspaces = $this->activemanifest->getCcNamespaces();
$dnode = $this->appendNewElementNs($metanode2, $nspaces['imscc'], 'metadata');
$this->activemanifest->createMetadataResourceNode($met, $this->doc, $dnode);
}
/**
* Add Metadata For File.
*
* @param string $identifier
* @param string $filename
*/
public function addMetadataFile(CcIMetadataFile $met, $identifier, $filename)
{
if (empty($met) || empty($identifier) || empty($filename)) {
throw new Exception('Try to add a metadata file with nulls values given!');
}
$metanode = $this->node("//imscc:resource".
"[@identifier='".
$identifier.
"']/imscc:file".
"[@href='".
$filename.
"']");
$nspaces = $this->activemanifest->getCcNamespaces();
$dnode = $this->doc->createElementNS($nspaces['imscc'], "metadata");
$metanode->appendChild($dnode);
$this->activemanifest->createMetadataFileNode($met, $this->doc, $dnode);
}
public function onCreate()
{
$this->activemanifest = new CcVersion13();
$this->rootmanifest = $this->activemanifest;
$result = $this->activemanifest->createManifest($this->doc);
$this->registerNamespacesForXpath();
return $result;
}
public function getRelativeBasePath()
{
return $this->activemanifest->base();
}
public function parentManifest()
{
return new CcManifest($this, $this->parentmanifest, $this->parentparentmanifest);
}
public function rootManifest()
{
return new CcManifest($this, $this->rootmanifest);
}
public function manifestID()
{
return $this->activemanifest->manifestID();
}
public function getManifestNamespaces()
{
return $this->rootmanifest->getCcNamespaces();
}
/**
* Add a new organization.
*/
public function addNewOrganization(CcIOrganization &$org)
{
$norg = $this->activemanifest->createOrganizationNode($org, $this->doc);
$orgnode = $this->node("//imscc:manifest[@identifier='".
$this->activemanifest->manifestID().
"']/imscc:organizations");
$orgnode->appendChild($norg);
}
public function getResources($searchspecific = '')
{
$reslist = $this->getResourceList($searchspecific);
$resourcelist = [];
foreach ($reslist as $resourceitem) {
$resourcelist[] = new CcResources($this, $resourceitem);
}
return $resourcelist;
}
public function getCcNamespacePath($nsname)
{
if (is_string($nsname) && (!empty($nsname))) {
$scnam = $this->activemanifest->getCcNamespaces();
return $scnam[$nsname];
}
return null;
}
public function getResourceList($searchspecific = '')
{
return $this->nodeList("//imscc:manifest[@identifier='".
$this->activemanifest->manifestID().
"']/imscc:resources/imscc:resource".$searchspecific);
}
public function onLoad()
{
$this->registerNamespacesForXpath();
$this->fillManifest();
return true;
}
public function onSave()
{
return true;
}
/**
* Add a resource to the manifest.
*
* @param string $identifier
* @param string $type
*
* @return array
*/
public function addResource(CcIResource $res, $identifier = null, $type = 'webcontent')
{
if (!$this->ccobj->valid($type)) {
throw new Exception("Type invalid...");
}
if ($res == null) {
throw new Exception('Invalid Resource or dont give it');
}
$rst = $res;
// TODO: This has to be reviewed since it does not handle multiple files properly.
// Dependencies.
if (is_object($identifier)) {
$this->activemanifest->createResourceNode($rst, $this->doc, $identifier);
} else {
$nresnode = null;
$rst->type = $type;
if (!CcHelpers::isHtml($rst->filename)) {
$rst->href = null;
}
$this->activemanifest->createResourceNode($rst, $this->doc, $nresnode);
foreach ($rst->files as $file) {
$ident = $this->getIdentifierByFilename($file);
if ($ident == null) {
$newres = new CcResources($rst->manifestroot, $file);
if (!CcHelpers::isHtml($file)) {
$newres->href = null;
}
$newres->type = 'webcontent';
$this->activemanifest->createResourceNode($newres, $this->doc, $nresnode);
}
}
}
$tmparray = [$rst->identifier, $rst->files[0]];
return $tmparray;
}
public function updateInstructoronly($identifier, $value = false)
{
if (isset($this->activemanifest->resources[$identifier])) {
$resource = $this->activemanifest->resources[$identifier];
$resource->instructoronly = $value;
}
}
/**
* Append the resources nodes in the Manifest.
*
* @return DOMNode
*/
public function putNodes()
{
$resnodestr = "//imscc:manifest[@identifier='".$this->activemanifest->manifestID().
"']/imscc:resources";
$resnode = $this->node($resnodestr);
foreach ($this->activemanifest->resources as $k => $v) {
($k);
$depen = $this->checkIfExistInOther($v->files[0], $v->identifier);
if (!empty($depen)) {
$this->replaceFileXDependency($depen, $v->files[0]);
$v->type = 'webcontent';
}
}
foreach ($this->activemanifest->resources as $node) {
$rnode = $this->activemanifest->createResourceNode($node, $this->doc, null);
$resnode->appendChild($rnode);
if ($node->instructoronly) {
$metafileceduc = new CcMetadataResourceEducational();
$metafileceduc->setValue(intended_user_role::INSTRUCTOR);
$metafile = new CcMetadataResource();
$metafile->addMetadataResourceEducational($metafileceduc);
$this->activemanifest->createMetadataEducational($metafile, $this->doc, $rnode);
}
}
return $resnode;
}
/**
* TODO - implement this method - critical.
*/
private function fillManifest()
{
}
private function checkIfExistInOther($name, $identifier)
{
$status = [];
foreach ($this->activemanifest->resources as $value) {
if (($value->identifier != $identifier) && isset($value->files[$name])) {
$status[] = $value->identifier;
}
}
return $status;
}
private function replaceFileXDependency($depen, $name)
{
foreach ($depen as $key => $value) {
($key);
$ident = $this->getIdentifierByFilename($name);
$this->activemanifest->resources[$value]->files =
$this->arrayRemoveByValue($this->activemanifest->resources[$value]->files, $name);
if (!in_array($ident, $this->activemanifest->resources[$value]->dependency)) {
array_push($this->activemanifest->resources[$value]->dependency, $ident);
}
}
return true;
}
private function getIdentifierByFilename($name)
{
$result = null;
if (isset($this->activemanifest->resourcesInd[$name])) {
$result = $this->activemanifest->resourcesInd[$name];
}
return $result;
}
private function arrayRemoveByValue($arr, $value)
{
return array_values(array_diff($arr, [$value]));
}
private function arrayRemoveByKey($arr, $key)
{
return array_values(array_diff_key($arr, [$key]));
}
}

View File

@@ -0,0 +1,51 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_manifest.php under GNU/GPL license */
/**
* Metadata General Type.
*/
class CcMetadataGeneral
{
public $title = [];
public $language = [];
public $description = [];
public $keyword = [];
public $coverage = [];
public $catalog = [];
public $entry = [];
public function setCoverage($coverage, $language)
{
$this->coverage[] = [$language, $coverage];
}
public function setDescription($description, $language)
{
$this->description[] = [$language, $description];
}
public function setKeyword($keyword, $language)
{
$this->keyword[] = [$language, $keyword];
}
public function setLanguage($language)
{
$this->language[] = [$language];
}
public function setTitle($title, $language)
{
$this->title[] = [$language, $title];
}
public function setCatalog($cat)
{
$this->catalog[] = [$cat];
}
public function setEntry($entry)
{
$this->entry[] = [$entry];
}
}

View File

@@ -0,0 +1,52 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_manifest.php under GNU/GPL license */
class CcMetadataManifest implements CcIMetadataManifest
{
public $arraygeneral = [];
public $arraytech = [];
public $arrayrights = [];
public $arraylifecycle = [];
public function addMetadataGeneral($obj)
{
if (empty($obj)) {
throw new Exception('Medatada Object given is invalid or null!');
}
!is_null($obj->title) ? $this->arraygeneral['title'] = $obj->title : null;
!is_null($obj->language) ? $this->arraygeneral['language'] = $obj->language : null;
!is_null($obj->description) ? $this->arraygeneral['description'] = $obj->description : null;
!is_null($obj->keyword) ? $this->arraygeneral['keyword'] = $obj->keyword : null;
!is_null($obj->coverage) ? $this->arraygeneral['coverage'] = $obj->coverage : null;
!is_null($obj->catalog) ? $this->arraygeneral['catalog'] = $obj->catalog : null;
!is_null($obj->entry) ? $this->arraygeneral['entry'] = $obj->entry : null;
}
public function addMetadataTechnical($obj)
{
if (empty($obj)) {
throw new Exception('Medatada Object given is invalid or null!');
}
!is_null($obj->format) ? $this->arraytech['format'] = $obj->format : null;
}
public function addMetadataRights($obj)
{
if (empty($obj)) {
throw new Exception('Medatada Object given is invalid or null!');
}
!is_null($obj->copyright) ? $this->arrayrights['copyrightAndOtherRestrictions'] = $obj->copyright : null;
!is_null($obj->description) ? $this->arrayrights['description'] = $obj->description : null;
!is_null($obj->cost) ? $this->arrayrights['cost'] = $obj->cost : null;
}
public function addMetadataLifecycle($obj)
{
if (empty($obj)) {
throw new Exception('Medatada Object given is invalid or null!');
}
!is_null($obj->role) ? $this->arraylifecycle['role'] = $obj->role : null;
!is_null($obj->entity) ? $this->arraylifecycle['entity'] = $obj->entity : null;
!is_null($obj->date) ? $this->arraylifecycle['date'] = $obj->date : null;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_metadata_resource.php under GNU/GPL license */
/**
* Metadata Resource.
*/
class CcMetadataResource implements CcIMetadataResource
{
public $arrayeducational = [];
public function addMetadataResourceEducational($obj)
{
if (empty($obj)) {
throw new Exception('Medatada Object given is invalid or null!');
}
$this->arrayeducational['value'] = (!is_null($obj->value) ? $obj->value : null);
}
}

View File

@@ -0,0 +1,16 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_metadata_resource.php under GNU/GPL license */
/**
* Metadata Resource Educational Type.
*/
class CcMetadataResourceEducational
{
public $value = [];
public function setValue($value)
{
$arr = [$value];
$this->value[] = $arr;
}
}

View File

@@ -0,0 +1,97 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_organization.php under GNU/GPL license */
/**
* Organization Class.
*/
class CcOrganization implements CcIOrganization
{
public $title = null;
public $identifier = null;
public $structure = null;
public $itemlist = null;
private $metadata = null;
private $sequencing = null;
public function __construct($node = null, $doc = null)
{
if (is_object($node) && is_object($doc)) {
$this->processOrganization($node, $doc);
} else {
$this->initNew();
}
}
/**
* Add one Item into the Organization.
*/
public function addItem(CcIItem &$item)
{
if (is_null($this->itemlist)) {
$this->itemlist = [];
}
$this->itemlist[$item->identifier] = $item;
}
/**
* Add new Item into the Organization.
*
* @param string $title
*
* @return CcIItem
*/
public function addNewItem($title = '')
{
$nitem = new CcItem();
$nitem->title = $title;
$this->addItem($nitem);
return $nitem;
}
public function hasItems()
{
return is_array($this->itemlist) && (count($this->itemlist) > 0);
}
public function attrValue(&$nod, $name, $ns = null)
{
return is_null($ns) ?
($nod->hasAttribute($name) ? $nod->getAttribute($name) : null) :
($nod->hasAttributeNS($ns, $name) ? $nod->getAttributeNS($ns, $name) : null);
}
public function processOrganization(&$node, &$doc)
{
$this->identifier = $this->attrValue($node, "identifier");
$this->structure = $this->attrValue($node, "structure");
$this->title = '';
$nlist = $node->getElementsByTagName('title');
if (is_object($nlist) && ($nlist->length > 0)) {
$this->title = $nlist->item(0)->nodeValue;
}
$nlist = $doc->nodeList("//imscc:organization[@identifier='".$this->identifier."']/imscc:item");
$this->itemlist = [];
foreach ($nlist as $item) {
$this->itemlist[$item->getAttribute("identifier")] = new CcItem($item, $doc);
}
$this->isempty = false;
}
public function initNew()
{
$this->title = null;
$this->identifier = CcHelpers::uuidgen('O_');
$this->structure = 'rooted-hierarchy';
$this->itemlist = null;
$this->metadata = null;
$this->sequencing = null;
}
public function uuidgen()
{
$uuid = sprintf('%04x%04x', mt_rand(0, 65535), mt_rand(0, 65535));
return strtoupper(trim($uuid));
}
}

View File

@@ -0,0 +1,98 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_page.php under GNU/GPL license */
class CcPage extends CcGeneralFile
{
protected $rootns = 'xmlns';
protected $rootname = 'html';
protected $ccnamespaces = ['xmlns' => 'http://www.w3.org/1999/xhtml'];
protected $content = null;
protected $title = null;
protected $intro = null;
public function setContent($value)
{
// We are not cleaning up this one on purpose.
$this->content = $value;
}
public function setTitle($value)
{
$this->title = self::safexml($value);
}
public function setIntro($value)
{
$this->intro = self::safexml(strip_tags($value));
}
public function onSave()
{
$rns = $this->ccnamespaces[$this->rootns];
// Add the basic tags.
$head = $this->appendNewElementNs($this->root, $rns, 'head');
$this->appendNewAttributeNs($head, $rns, 'profile', 'http://dublincore.org/documents/dc-html/');
// Linking Dublin Core Metadata 1.1.
$link_dc = $this->appendNewElementNs($head, $rns, 'link');
$this->appendNewAttributeNs($link_dc, $rns, 'rel', 'schema.DC');
$this->appendNewAttributeNs($link_dc, $rns, 'href', 'http://purl.org/dc/elements/1.1/');
$link_dcterms = $this->appendNewElementNs($head, $rns, 'link');
$this->appendNewAttributeNs($link_dcterms, $rns, 'rel', 'schema.DCTERMS');
$this->appendNewAttributeNs($link_dcterms, $rns, 'href', 'http://purl.org/dc/terms/');
// Content type.
$meta_type = $this->appendNewElementNs($head, $rns, 'meta');
$this->appendNewAttributeNs($meta_type, $rns, 'name', 'DC.type');
$this->appendNewAttributeNs($meta_type, $rns, 'scheme', 'DCTERMS.DCMIType');
$this->appendNewAttributeNs($meta_type, $rns, 'content', 'Text');
// Content description.
if (!empty($this->intro)) {
$meta_description = $this->appendNewElementNs($head, $rns, 'meta');
$this->appendNewAttributeNs($meta_description, $rns, 'name', 'DC.description');
$this->appendNewAttributeNs($meta_description, $rns, 'content', $this->intro);
}
$meta = $this->appendNewElementNs($head, $rns, 'meta');
$this->appendNewAttributeNs($meta, $rns, 'http-equiv', 'Content-type');
$this->appendNewAttributeNs($meta, $rns, 'content', 'text/html; charset=UTF-8');
// Set the title.
$title = $this->appendNewElementNs($head, $rns, 'title', $this->title);
$body = $this->appendNewElementNs($this->root, $rns, 'body');
// We are unable to use DOM for embedding HTML due to numerous content errors.
// Therefore we place a dummy tag that will be later replaced with the real content.
$this->appendNewElementNs($body, $rns, 'div', '##REPLACE##');
return true;
}
public function saveTo($fname)
{
$result = $this->onSave();
if ($result) {
$dret = str_replace('<?xml version="1.0"?>'."\n", '', $this->viewXML());
$dret = str_replace('<div>##REPLACE##</div>', $this->content, $dret);
$result = (file_put_contents($fname, $dret) !== false);
if ($result) {
$this->filename = $fname;
$this->processPath();
}
}
return $result;
}
protected function onCreate()
{
$impl = new DOMImplementation();
$dtd = $impl->createDocumentType('html',
'-//W3C//DTD XHTML 1.0 Strict//EN',
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
$doc = $impl->createDocument($this->ccnamespaces[$this->rootns], null, $dtd);
$doc->formatOutput = true;
$doc->preserveWhiteSpace = true;
$this->doc = $doc;
parent::onCreate();
}
}

View File

@@ -0,0 +1,164 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_resources.php under GNU/GPL license */
class CcResources implements CcIResource
{
public $identifier = null;
public $type = null;
public $dependency = [];
public $identifierref = null;
public $href = null;
public $base = null;
public $persiststate = null;
public $metadata = [];
public $filename = null;
public $files = [];
public $isempty = null;
public $manifestroot = null;
public $folder = null;
public $instructoronly = false;
private $throwonerror = true;
public function __construct($manifest, $file, $folder = '', $throwonerror = true)
{
$this->throwonerror = $throwonerror;
if (is_string($manifest)) {
$this->folder = $folder;
$this->processResource($manifest, $file, $folder);
$this->manifestroot = $manifest;
} elseif (is_object($manifest)) {
$this->importResource($file, $manifest);
}
}
/**
* Add resource.
*
* @param string $fname
* @param string $location
*/
public function addResource($fname, $location = '')
{
$this->processResource($fname, $location, null);
}
/**
* Import a resource.
*/
public function importResource(DOMElement &$node, CcIManifest &$doc)
{
$searchstr = "//imscc:manifest[@identifier='".$doc->manifestID().
"']/imscc:resources/imscc:resource";
$this->identifier = $this->getAttrValue($node, "identifier");
$this->type = $this->getAttrValue($node, "type");
$this->href = $this->getAttrValue($node, "href");
$this->base = $this->getAttrValue($node, "base");
$this->persiststate = null;
$nodo = $doc->nodeList($searchstr."[@identifier='".
$this->identifier."']/metadata/@href");
$this->metadata = $nodo->nodeValue;
$this->filename = $this->href;
$nlist = $doc->nodeList($searchstr."[@identifier='".
$this->identifier."']/imscc:file/@href");
$this->files = [];
foreach ($nlist as $file) {
$this->files[] = $file->nodeValue;
}
$nlist = $doc->nodeList($searchstr."[@identifier='".
$this->identifier."']/imscc:dependency/@identifierref");
$this->dependency = [];
foreach ($nlist as $dependency) {
$this->dependency[] = $dependency->nodeValue;
}
$this->isempty = false;
}
/**
* Get a attribute value.
*
* @param DOMElement $nod
* @param string $name
* @param string $ns
*
* @return string
*/
public function getAttrValue(&$nod, $name, $ns = null)
{
if (is_null($ns)) {
return $nod->hasAttribute($name) ? $nod->getAttribute($name) : null;
}
return $nod->hasAttributeNS($ns, $name) ? $nod->getAttributeNS($ns, $name) : null;
}
/**
* Process a resource.
*
* @param string $manifestroot
* @param string $fname
* @param string $folder
*/
public function processResource($manifestroot, &$fname, $folder)
{
$file = empty($folder) ? $manifestroot.'/'.$fname : $manifestroot.'/'.$folder.'/'.$fname;
if (!file_exists($file) && $this->throwonerror) {
throw new Exception('The file doesnt exist!');
}
getDepFiles($manifestroot, $fname, $this->folder, $this->files);
array_unshift($this->files, $folder.$fname);
$this->initEmptyNew();
$this->href = $folder.$fname;
$this->identifierref = $folder.$fname;
$this->filename = $fname;
$this->isempty = false;
$this->folder = $folder;
}
public function adjustPath($mroot, $fname)
{
$result = null;
if (file_exists($fname->filename)) {
$result = pathDiff($fname->filename, $mroot);
} elseif (file_exists($mroot.$fname->filename) || file_exists($mroot.DIRECTORY_SEPARATOR.$fname->filename)) {
$result = $fname->filename;
toUrlPath($result);
$result = trim($result, "/");
}
return $result;
}
public function initClean()
{
$this->identifier = null;
$this->type = null;
$this->href = null;
$this->base = null;
$this->metadata = [];
$this->dependency = [];
$this->identifierref = null;
$this->persiststate = null;
$this->filename = '';
$this->files = [];
$this->isempty = true;
}
public function initEmptyNew()
{
$this->identifier = CcHelpers::uuidgen('I_', '_R');
$this->type = null;
$this->href = null;
$this->persiststate = null;
$this->filename = null;
$this->isempty = false;
$this->identifierref = null;
}
public function getManifestroot()
{
return $this->manifestroot;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/* For licensing terms, see /license.txt */
class CcVersion13 extends CcVersion1
{
public const WEBCONTENT = 'webcontent';
public const QUESTIONBANK = 'imsqti_xmlv1p3/imscc_xmlv1p3/question-bank';
public const ASSESSMENT = 'imsqti_xmlv1p3/imscc_xmlv1p3/assessment';
public const ASSOCIATEDCONTENT = 'associatedcontent/imscc_xmlv1p3/learning-application-resource';
public const DISCUSSIONTOPIC = 'imsdt_xmlv1p3';
public const WEBLINK = 'imswl_xmlv1p3';
public const BASICLTI = 'imsbasiclti_xmlv1p3';
public static $checker = [self::WEBCONTENT,
self::ASSESSMENT,
self::ASSOCIATEDCONTENT,
self::DISCUSSIONTOPIC,
self::QUESTIONBANK,
self::WEBLINK,
self::BASICLTI, ];
public function __construct()
{
$this->ccnamespaces = ['imscc' => 'http://www.imsglobal.org/xsd/imsccv1p3/imscp_v1p1',
'lomimscc' => 'http://ltsc.ieee.org/xsd/imsccv1p3/LOM/manifest',
'lom' => 'http://ltsc.ieee.org/xsd/imsccv1p3/LOM/resource',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'cc' => 'http://www.imsglobal.org/xsd/imsccv1p3/imsccauth_v1p1',
];
$this->ccnsnames = ['imscc' => 'http://www.imsglobal.org/profile/cc/ccv1p3/ccv1p3_imscp_v1p2_v1p0.xsd',
'lomimscc' => 'http://www.imsglobal.org/profile/cc/ccv1p3/LOM/ccv1p3_lommanifest_v1p0.xsd',
'lom' => 'http://www.imsglobal.org/profile/cc/ccv1p3/LOM/ccv1p3_lomresource_v1p0.xsd',
];
$this->ccversion = '1.3.0';
$this->camversion = '1.3.0';
$this->_generator = 'Chamilo Common Cartridge generator';
}
/**
* Validate if the type are valid or not.
*
* @param string $type
*
* @return bool
*/
public function valid($type)
{
return in_array($type, self::$checker);
}
/**
* Create Education Metadata (How To).
*
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
public function createMetadataEducational($met, DOMDocument &$doc, $xmlnode)
{
$metadata = $doc->createElementNS($this->ccnamespaces['imscc'], 'metadata');
$xmlnode->insertBefore($metadata, $xmlnode->firstChild);
$lom = $doc->createElementNS($this->ccnamespaces['lom'], 'lom');
$metadata->appendChild($lom);
$educational = $doc->createElementNS($this->ccnamespaces['lom'], 'educational');
$lom->appendChild($educational);
foreach ($met->arrayeducational as $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
$userrole = $doc->createElementNS($this->ccnamespaces['lom'], 'intendedEndUserRole');
$educational->appendChild($userrole);
$nd4 = $doc->createElementNS($this->ccnamespaces['lom'], 'source', 'IMSGLC_CC_Rolesv1p2');
$nd5 = $doc->createElementNS($this->ccnamespaces['lom'], 'value', $v[0]);
$userrole->appendChild($nd4);
$userrole->appendChild($nd5);
}
}
return $metadata;
}
protected function updateItems($items, DOMDocument &$doc, DOMElement &$xmlnode)
{
foreach ($items as $key => $item) {
$itemnode = $doc->createElementNS($this->ccnamespaces['imscc'], 'item');
$this->updateAttribute($doc, 'identifier', $key, $itemnode);
$this->updateAttribute($doc, 'identifierref', $item->identifierref, $itemnode);
if (!is_null($item->title)) {
$titlenode = $doc->createElementNS($this->ccnamespaces['imscc'], 'title');
$titlenode->appendChild(new DOMText($item->title));
$itemnode->appendChild($titlenode);
}
if ($item->hasChildItems()) {
$this->updateItems($item->childitems, $doc, $itemnode);
}
$xmlnode->appendChild($itemnode);
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_weblink.php under GNU/GPL license */
class CcWebLink extends CcGeneralFile
{
public const DEAFULTNAME = 'weblink.xml';
protected $rootns = 'wl';
protected $rootname = 'webLink';
protected $ccnamespaces = ['wl' => 'http://www.imsglobal.org/xsd/imsccv1p3/imswl_v1p3',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', ];
protected $ccnsnames = ['wl' => 'http://www.imsglobal.org/profile/cc/ccv1p3/ccv1p3_imswl_v1p3.xsd'];
protected $url = null;
protected $title = null;
protected $href = null;
protected $target = '_self';
protected $windowFeatures = null;
/**
* Set the url title.
*
* @param string $title
*/
public function setTitle($title)
{
$this->title = self::safexml($title);
}
/**
* Set the url specifics.
*
* @param string $url
* @param string $target
* @param string $windowFeatures
*/
public function setUrl($url, $target = '_self', $windowFeatures = null)
{
$this->url = $url;
$this->target = $target;
$this->windowFeatures = $windowFeatures;
}
protected function onSave()
{
$rns = $this->ccnamespaces[$this->rootns];
$this->appendNewElementNs($this->root, $rns, 'title', $this->title);
$url = $this->appendNewElementNs($this->root, $rns, 'url');
$this->appendNewAttributeNs($url, $rns, 'href', $this->url);
if (!empty($this->target)) {
$this->appendNewAttributeNs($url, $rns, 'target', $this->target);
}
if (!empty($this->windowFeatures)) {
$this->appendNewAttributeNs($url, $rns, 'windowFeatures', $this->windowFeatures);
}
return true;
}
}

View File

@@ -0,0 +1,86 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converters.php under GNU/GPL license */
abstract class CcConverters
{
protected $item = null;
protected $manifest = null;
protected $rootpath = null;
protected $path = null;
protected $defaultfile = null;
protected $defaultname = null;
protected $ccType = null;
protected $doc = null;
/**
* ctor.
*
* @param string $rootpath
* @param string $path
*
* @throws InvalidArgumentException
*/
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$rpath = realpath($rootpath);
if (empty($rpath)) {
throw new InvalidArgumentException('Invalid path!');
}
$rpath2 = realpath($path);
if (empty($rpath)) {
throw new InvalidArgumentException('Invalid path!');
}
$doc = new XMLGenericDocument();
$this->doc = $doc;
$this->item = $item;
$this->manifest = $manifest;
$this->rootpath = $rpath;
$this->path = $rpath2;
}
/**
* performs conversion.
*
* @param string $outdir - root directory of common cartridge
* @param object $objCourse
*
* @return bool
*/
abstract public function convert($outdir, $objCourse);
/**
* Is the element visible in the course?
*
* @throws RuntimeException
*
* @return bool
*/
protected function isVisible()
{
$tdoc = new XMLGenericDocument();
return true;
}
/**
* Stores any files that need to be stored.
*/
protected function store(CcGeneralFile $doc, $outdir, $title, $deps = null)
{
$rdir = new CcResourceLocation($outdir);
$rtp = $rdir->fullpath(true).$this->defaultname;
if ($doc->saveTo($rtp)) {
$resource = new CcResources($rdir->rootdir(), $this->defaultname, $rdir->dirname(true));
$resource->dependency = empty($deps) ? [] : $deps;
$resource->instructoronly = !$this->isVisible();
$res = $this->manifest->addResource($resource, null, $this->ccType);
$resitem = new CcItem();
$resitem->attachResource($res[0]);
$resitem->title = $title;
$this->item->addChildItem($resitem);
} else {
throw new RuntimeException("Unable to save file {$rtp}!");
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_general.php under GNU/GPL license */
class CcGeneralFile extends XMLGenericDocument
{
/**
* Root element.
*
* @var DOMElement
*/
protected $root = null;
protected $rootns = null;
protected $rootname = null;
protected $ccnamespaces = [];
protected $ccnsnames = [];
public function __construct()
{
parent::__construct();
foreach ($this->ccnamespaces as $key => $value) {
$this->registerNS($key, $value);
}
}
protected function onCreate()
{
$rootel = $this->appendNewElementNs($this->doc,
$this->ccnamespaces[$this->rootns],
$this->rootname);
//add all namespaces
foreach ($this->ccnamespaces as $key => $value) {
$dummy_attr = "{$key}:dummy";
$this->doc->createAttributeNS($value, $dummy_attr);
}
// add location of schemas
$schemaLocation = '';
foreach ($this->ccnsnames as $key => $value) {
$vt = empty($schemaLocation) ? '' : ' ';
$schemaLocation .= $vt.$this->ccnamespaces[$key].' '.$value;
}
if (!empty($schemaLocation) && isset($this->ccnamespaces['xsi'])) {
$this->appendNewAttributeNs($rootel,
$this->ccnamespaces['xsi'],
'xsi:schemaLocation',
$schemaLocation);
}
$this->root = $rootel;
}
}

View File

@@ -0,0 +1,507 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_version1.php under GNU/GPL license */
/**
* Version 1 class of Common Cartridge.
*/
class CcVersion1 extends CcVersionBase
{
public const WEBCONTENT = 'webcontent';
public const QUESTIONBANK = 'imsqti_xmlv1p2/imscc_xmlv1p0/question-bank';
public const ASSESSMENT = 'imsqti_xmlv1p2/imscc_xmlv1p0/assessment';
public const ASSOCIATEDCONTENT = 'associatedcontent/imscc_xmlv1p0/learning-application-resource';
public const DISCUSSIONTOPIC = 'imsdt_xmlv1p0';
public const WEBLINK = 'imswl_xmlv1p0';
public static $checker = [self::WEBCONTENT,
self::ASSESSMENT,
self::ASSOCIATEDCONTENT,
self::DISCUSSIONTOPIC,
self::QUESTIONBANK,
self::WEBLINK, ];
public function __construct()
{
$this->ccnamespaces = ['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',
];
$this->ccnsnames = [
'imscc' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/imscp_v1p2_localised.xsd',
'lom' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_2/lomLoose_localised.xsd',
'lomimscc' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_1/lomLoose_localised.xsd',
'voc' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_2/vocab/loose.xsd',
];
$this->ccversion = '1.0.0';
$this->camversion = '1.0.0';
$this->_generator = 'Common Cartridge generator';
}
/**
* Validate if the type are valid or not.
*
* @param string $type
*
* @return bool
*/
public function valid($type)
{
return in_array($type, self::$checker);
}
/**
* Create Education Metadata (How To).
*
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
public function createMetadataEducational($met, DOMDocument &$doc, $xmlnode)
{
$nd = $doc->createElementNS($this->ccnamespaces['lom'], 'educational');
$nd2 = $doc->createElementNS($this->ccnamespaces['lom'], 'intendedEndUserRole');
$nd3 = $doc->createElementNS($this->ccnamespaces['voc'], 'vocabulary');
$xmlnode->appendChild($nd);
$nd->appendChild($nd2);
$nd2->appendChild($nd3);
foreach ($met->arrayeducational as $name => $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
$nd4 = $doc->createElementNS($this->ccnamespaces['voc'], $name, $v[0]);
$nd3->appendChild($nd4);
}
}
return $nd;
}
protected function onCreate(DOMDocument &$doc, $rootmanifestnode = null, $nmanifestID = null)
{
$doc->formatOutput = true;
$doc->preserveWhiteSpace = true;
$this->manifestID = is_null($nmanifestID) ? CcHelpers::uuidgen('M_') : $nmanifestID;
$mUUID = $doc->createAttribute('identifier');
$mUUID->nodeValue = $this->manifestID;
if (is_null($rootmanifestnode)) {
if (!empty($this->_generator)) {
$comment = $doc->createComment($this->_generator);
$doc->appendChild($comment);
}
$rootel = $doc->createElementNS($this->ccnamespaces['imscc'], 'manifest');
$rootel->appendChild($mUUID);
$doc->appendChild($rootel);
// Add all namespaces.
foreach ($this->ccnamespaces as $key => $value) {
$dummy_attr = $key.":dummy";
$doc->createAttributeNS($value, $dummy_attr);
}
// Add location of schemas.
$schemaLocation = '';
foreach ($this->ccnsnames as $key => $value) {
$vt = empty($schemaLocation) ? '' : ' ';
$schemaLocation .= $vt.$this->ccnamespaces[$key].' '.$value;
}
$aSchemaLoc = $doc->createAttributeNS($this->ccnamespaces['xsi'], 'xsi:schemaLocation');
$aSchemaLoc->nodeValue = $schemaLocation;
$rootel->appendChild($aSchemaLoc);
} else {
$rootel = $doc->createElementNS($this->ccnamespaces['imscc'], 'imscc:manifest');
$rootel->appendChild($mUUID);
}
$metadata = $doc->createElementNS($this->ccnamespaces['imscc'], 'metadata');
$schema = $doc->createElementNS($this->ccnamespaces['imscc'], 'schema', 'IMS Common Cartridge');
$schemaversion = $doc->createElementNS($this->ccnamespaces['imscc'], 'schemaversion', $this->ccversion);
$metadata->appendChild($schema);
$metadata->appendChild($schemaversion);
$rootel->appendChild($metadata);
if (!is_null($rootmanifestnode)) {
$rootmanifestnode->appendChild($rootel);
}
$organizations = $doc->createElementNS($this->ccnamespaces['imscc'], 'organizations');
$rootel->appendChild($organizations);
$resources = $doc->createElementNS($this->ccnamespaces['imscc'], 'resources');
$rootel->appendChild($resources);
return true;
}
protected function updateAttribute(DOMDocument &$doc, $attrname, $attrvalue, DOMElement &$node)
{
$busenew = (is_object($node) && $node->hasAttribute($attrname));
$nResult = null;
if (!$busenew && is_null($attrvalue)) {
$node->removeAttribute($attrname);
} else {
$nResult = $busenew ? $node->getAttributeNode($attrname) : $doc->createAttribute($attrname);
$nResult->nodeValue = $attrvalue;
if (!$busenew) {
$node->appendChild($nResult);
}
}
return $nResult;
}
protected function updateAttributeNs(DOMDocument &$doc, $attrname, $attrnamespace, $attrvalue, DOMElement &$node)
{
$busenew = (is_object($node) && $node->hasAttributeNS($attrnamespace, $attrname));
$nResult = null;
if (!$busenew && is_null($attrvalue)) {
$node->removeAttributeNS($attrnamespace, $attrname);
} else {
$nResult = $busenew ? $node->getAttributeNodeNS($attrnamespace, $attrname) :
$doc->createAttributeNS($attrnamespace, $attrname);
$nResult->nodeValue = $attrvalue;
if (!$busenew) {
$node->appendChild($nResult);
}
}
return $nResult;
}
protected function getChildNode(DOMDocument &$doc, $itemname, DOMElement &$node)
{
$nlist = $node->getElementsByTagName($itemname);
$item = is_object($nlist) && ($nlist->length > 0) ? $nlist->item(0) : null;
return $item;
}
protected function updateChildItem(DOMDocument &$doc, $itemname, $itemvalue, DOMElement &$node, $attrtostore = null)
{
$tnode = $this->getChildNode($doc, 'title', $node);
$usenew = is_null($tnode);
$tnode = $usenew ? $doc->createElementNS($this->ccnamespaces['imscc'], $itemname) : $tnode;
if (!is_null($attrtostore)) {
foreach ($attrtostore as $key => $value) {
$this->updateAttribute($doc, $key, $value, $tnode);
}
}
$tnode->nodeValue = $itemvalue;
if ($usenew) {
$node->appendChild($tnode);
}
}
protected function updateItems($items, DOMDocument &$doc, DOMElement &$xmlnode)
{
foreach ($items as $key => $item) {
$itemnode = $doc->createElementNS($this->ccnamespaces['imscc'], 'item');
$this->updateAttribute($doc, 'identifier', $key, $itemnode);
$this->updateAttribute($doc, 'identifierref', $item->identifierref, $itemnode);
$this->updateAttribute($doc, 'parameters', $item->parameters, $itemnode);
if (!empty($item->title)) {
$titlenode = $doc->createElementNS($this->ccnamespaces['imscc'],
'title',
$item->title);
$itemnode->appendChild($titlenode);
}
if ($item->hasChildItems()) {
$this->updateItems($item->childitems, $doc, $itemnode);
}
$xmlnode->appendChild($itemnode);
}
}
/**
* Create a Resource (How to).
*
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createResource(CcIResource &$res, DOMDocument &$doc, $xmlnode = null)
{
$usenew = is_object($xmlnode);
$dnode = $usenew ? $xmlnode : $doc->createElementNS($this->ccnamespaces['imscc'], "resource");
$this->updateAttribute($doc, 'identifier', $res->identifier, $dnode);
$this->updateAttribute($doc, 'type', $res->type, $dnode);
!is_null($res->href) ? $this->updateAttribute($doc, 'href', $res->href, $dnode) : null;
$this->updateAttribute($doc, 'base', $res->base, $dnode);
foreach ($res->files as $file) {
$nd = $doc->createElementNS($this->ccnamespaces['imscc'], 'file');
$ndatt = $doc->createAttribute('href');
$ndatt->nodeValue = $file;
$nd->appendChild($ndatt);
$dnode->appendChild($nd);
}
$this->resources[$res->identifier] = $res;
$this->resourcesInd[$res->files[0]] = $res->identifier;
foreach ($res->dependency as $dependency) {
$nd = $doc->createElementNS($this->ccnamespaces['imscc'], 'dependency');
$ndatt = $doc->createAttribute('identifierref');
$ndatt->nodeValue = $dependency;
$nd->appendChild($ndatt);
$dnode->appendChild($nd);
}
return $dnode;
}
/**
* Create an Item Folder (How To).
*
* @param DOMElement $xmlnode
*/
protected function createItemFolder(CcIOrganization &$org, DOMDocument &$doc, DOMElement &$xmlnode = null)
{
$itemfoldernode = $doc->createElementNS($this->ccnamespaces['imscc'], 'item');
$this->updateAttribute($doc, 'identifier', "root", $itemfoldernode);
if ($org->hasItems()) {
$this->updateItems($org->itemlist, $doc, $itemfoldernode);
}
if (is_null($this->organizations)) {
$this->organizations = [];
}
$this->organizations[$org->identifier] = $org;
$xmlnode->appendChild($itemfoldernode);
}
/**
* Create an Organization (How To).
*
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createOrganization(CcIOrganization &$org, DOMDocument &$doc, $xmlnode = null)
{
$usenew = is_object($xmlnode);
$dnode = $usenew ? $xmlnode : $doc->createElementNS($this->ccnamespaces['imscc'], "organization");
$this->updateAttribute($doc, 'identifier', $org->identifier, $dnode);
$this->updateAttribute($doc, 'structure', $org->structure, $dnode);
$this->createItemFolder($org, $doc, $dnode);
return $dnode;
}
/**
* Create Metadata For Manifest (How To).
*
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataManifest(CcIMetadataManifest $met, DOMDocument &$doc, $xmlnode = null)
{
$dnode = $doc->createElementNS($this->ccnamespaces['lomimscc'], "lom");
if (!empty($xmlnode)) {
$xmlnode->appendChild($dnode);
}
$dnodegeneral = empty($met->arraygeneral) ? null : $this->createMetadataGeneral($met, $doc, $xmlnode);
$dnodetechnical = empty($met->arraytech) ? null : $this->createMetadataTechnical($met, $doc, $xmlnode);
$dnoderights = empty($met->arrayrights) ? null : $this->createMetadataRights($met, $doc, $xmlnode);
$dnodelifecycle = empty($met->arraylifecycle) ? null : $this->createMetadataLifecycle($met, $doc, $xmlnode);
!is_null($dnodegeneral) ? $dnode->appendChild($dnodegeneral) : null;
!is_null($dnodetechnical) ? $dnode->appendChild($dnodetechnical) : null;
!is_null($dnoderights) ? $dnode->appendChild($dnoderights) : null;
!is_null($dnodelifecycle) ? $dnode->appendChild($dnodelifecycle) : null;
return $dnode;
}
/**
* Create Metadata For Resource (How To).
*
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataResource(CcIMetadataResource $met, DOMDocument &$doc, $xmlnode = null)
{
$dnode = $doc->createElementNS($this->ccnamespaces['lom'], "lom");
!empty($xmlnode) ? $xmlnode->appendChild($dnode) : null;
!empty($met->arrayeducational) ? $this->createMetadataEducational($met, $doc, $dnode) : null;
return $dnode;
}
/**
* Create Metadata For File (How To).
*
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataFile(CcIMetadataFile $met, DOMDocument &$doc, $xmlnode = null)
{
$dnode = $doc->createElementNS($this->ccnamespaces['lom'], "lom");
!empty($xmlnode) ? $xmlnode->appendChild($dnode) : null;
!empty($met->arrayeducational) ? $this->createMetadataEducational($met, $doc, $dnode) : null;
return $dnode;
}
/**
* Create General Metadata (How To).
*
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataGeneral($met, DOMDocument &$doc, $xmlnode)
{
$nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'general');
foreach ($met->arraygeneral as $name => $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
if ($name != 'language' && $name != 'catalog' && $name != 'entry') {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'string', $v[1]);
$ndatt = $doc->createAttribute('language');
$ndatt->nodeValue = $v[0];
$nd3->appendChild($ndatt);
$nd2->appendChild($nd3);
$nd->appendChild($nd2);
} else {
if ($name == 'language') {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
$nd->appendChild($nd2);
}
}
}
}
if (!empty($met->arraygeneral['catalog']) || !empty($met->arraygeneral['entry'])) {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'identifier');
$nd->appendChild($nd2);
if (!empty($met->arraygeneral['catalog'])) {
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'catalog', $met->arraygeneral['catalog'][0][0]);
$nd2->appendChild($nd3);
}
if (!empty($met->arraygeneral['entry'])) {
$nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'entry', $met->arraygeneral['entry'][0][0]);
$nd2->appendChild($nd4);
}
}
return $nd;
}
/**
* Create Technical Metadata (How To).
*
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataTechnical($met, DOMDocument &$doc, $xmlnode)
{
$nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'technical');
$xmlnode->appendChild($nd);
foreach ($met->arraytech as $name => $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
$nd->appendChild($nd2);
}
}
return $nd;
}
/**
* Create Rights Metadata (How To).
*
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataRights($met, DOMDocument &$doc, $xmlnode)
{
$nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'rights');
foreach ($met->arrayrights as $name => $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
if ($name == 'description') {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'string', $v[1]);
$ndatt = $doc->createAttribute('language');
$ndatt->nodeValue = $v[0];
$nd3->appendChild($ndatt);
$nd2->appendChild($nd3);
$nd->appendChild($nd2);
} elseif ($name == 'copyrightAndOtherRestrictions' || $name == 'cost') {
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'value', $v[0]);
$nd2->appendChild($nd3);
$nd->appendChild($nd2);
}
}
}
return $nd;
}
/**
* Create Lifecycle Metadata (How To).
*
* @param object $met
* @param object $met
* @param object $xmlnode
*
* @return DOMNode
*/
protected function createMetadataLifecycle($met, DOMDocument &$doc, $xmlnode)
{
$nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'lifeCycle');
$nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'contribute');
$nd->appendChild($nd2);
$xmlnode->appendChild($nd);
foreach ($met->arraylifecycle as $name => $value) {
!is_array($value) ? $value = [$value] : null;
foreach ($value as $v) {
if ($name == 'role') {
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
$nd2->appendChild($nd3);
$nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'value', $v[0]);
$nd3->appendChild($nd4);
} else {
if ($name == 'date') {
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
$nd2->appendChild($nd3);
$nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'dateTime', $v[0]);
$nd3->appendChild($nd4);
} else {
$nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
$nd2->appendChild($nd3);
}
}
}
}
return $nd;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_version_base.php under GNU/GPL license */
/**
* Abstract Version Base class.
*/
abstract class CcVersionBase
{
public $resources = null;
public $resourcesInd = null;
public $organizations = null;
public $ccversion = null;
public $camversion = null;
protected $_generator = null;
protected $ccnamespaces = [];
protected $isrootmanifest = false;
protected $manifestID = null;
protected $organizationid = null;
protected $metadata = null;
protected $base = null;
public function getCcNamespaces()
{
return $this->ccnamespaces;
}
public function createManifest(DOMDocument &$doc, $rootmanifestnode = null)
{
return $this->onCreate($doc, $rootmanifestnode);
}
public function createResourceNode(CcIResource &$res, DOMDocument &$doc, $xmlnode = null)
{
return $this->createResource($res, $doc, $xmlnode);
}
public function createMetadataNode(&$met, DOMDocument &$doc, $xmlnode = null)
{
return $this->createMetadataManifest($met, $doc, $xmlnode);
}
public function createMetadataResourceNode(&$met, DOMDocument &$doc, $xmlnode = null)
{
return $this->createMetadataResource($met, $doc, $xmlnode);
}
public function createMetadataFileNode(&$met, DOMDocument &$doc, $xmlnode = null)
{
return $this->createMetadataFile($met, $doc, $xmlnode);
}
public function createOrganizationNode(CcIOrganization &$org, DOMDocument &$doc, $xmlnode = null)
{
return $this->createOrganization($org, $doc, $xmlnode);
}
public function manifestID()
{
return $this->manifestID;
}
public function setManifestID($id)
{
$this->manifestID = $id;
}
public function getBase()
{
return $this->base;
}
public function setBase($baseval)
{
$this->base = $baseval;
}
public function importResources(DOMElement &$node, CcIManifest &$doc)
{
if (is_null($this->resources)) {
$this->resources = [];
}
$nlist = $node->getElementsByTagNameNS($this->ccnamespaces['imscc'], 'resource');
if (is_object($nlist)) {
foreach ($nlist as $nd) {
$sc = new CcResource($doc, $nd);
$this->resources[$sc->identifier] = $sc;
}
}
}
public function importOrganizationItems(DOMElement &$node, CcIManifest &$doc)
{
if (is_null($this->organizations)) {
$this->organizations = [];
}
$nlist = $node->getElementsByTagNameNS($this->ccnamespaces['imscc'], 'organization');
if (is_object($nlist)) {
foreach ($nlist as $nd) {
$sc = new CcOrganization($nd, $doc);
$this->organizations[$sc->identifier] = $sc;
}
}
}
public function setGenerator($value)
{
$this->_generator = $value;
}
abstract protected function onCreate(DOMDocument &$doc, $rootmanifestnode = null, $nmanifestID = null);
abstract protected function createMetadataManifest(CcIMetadataManifest $met, DOMDocument &$doc, $xmlnode = null);
abstract protected function createMetadataResource(CcIMetadataResource $met, DOMDocument &$doc, $xmlnode = null);
abstract protected function createMetadataFile(CcIMetadataFile $met, DOMDocument &$doc, $xmlnode = null);
abstract protected function createResource(CcIResource &$res, DOMDocument &$doc, $xmlnode = null);
abstract protected function createOrganization(CcIOrganization &$org, DOMDocument &$doc, $xmlnode = null);
}

View File

@@ -0,0 +1,269 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/gral_lib/cssparser.php under GNU/GPL license */
class CssParser
{
private $css;
private $html;
public function __construct($html = true)
{
$this->html = ($html != false);
$this->clear();
}
public function clear()
{
unset($this->css);
$this->css = [];
if ($this->html) {
$this->add("ADDRESS", "");
$this->add("APPLET", "");
$this->add("AREA", "");
$this->add("A", "text-decoration : underline; color : Blue;");
$this->add("A:visited", "color : Purple;");
$this->add("BASE", "");
$this->add("BASEFONT", "");
$this->add("BIG", "");
$this->add("BLOCKQUOTE", "");
$this->add("BODY", "");
$this->add("BR", "");
$this->add("B", "font-weight: bold;");
$this->add("CAPTION", "");
$this->add("CENTER", "");
$this->add("CITE", "");
$this->add("CODE", "");
$this->add("DD", "");
$this->add("DFN", "");
$this->add("DIR", "");
$this->add("DIV", "");
$this->add("DL", "");
$this->add("DT", "");
$this->add("EM", "");
$this->add("FONT", "");
$this->add("FORM", "");
$this->add("H1", "");
$this->add("H2", "");
$this->add("H3", "");
$this->add("H4", "");
$this->add("H5", "");
$this->add("H6", "");
$this->add("HEAD", "");
$this->add("HR", "");
$this->add("HTML", "");
$this->add("IMG", "");
$this->add("INPUT", "");
$this->add("ISINDEX", "");
$this->add("I", "font-style: italic;");
$this->add("KBD", "");
$this->add("LINK", "");
$this->add("LI", "");
$this->add("MAP", "");
$this->add("MENU", "");
$this->add("META", "");
$this->add("OL", "");
$this->add("OPTION", "");
$this->add("PARAM", "");
$this->add("PRE", "");
$this->add("P", "");
$this->add("SAMP", "");
$this->add("SCRIPT", "");
$this->add("SELECT", "");
$this->add("SMALL", "");
$this->add("STRIKE", "");
$this->add("STRONG", "");
$this->add("STYLE", "");
$this->add("SUB", "");
$this->add("SUP", "");
$this->add("TABLE", "");
$this->add("TD", "");
$this->add("TEXTAREA", "");
$this->add("TH", "");
$this->add("TITLE", "");
$this->add("TR", "");
$this->add("TT", "");
$this->add("UL", "");
$this->add("U", "text-decoration : underline;");
$this->add("VAR", "");
}
}
public function setHTML($html)
{
$this->html = ($html != false);
}
public function add($key, $codestr)
{
$key = strtolower($key);
$codestr = strtolower($codestr);
if (!isset($this->css[$key])) {
$this->css[$key] = [];
}
$codes = explode(";", $codestr);
if (count($codes) > 0) {
$codekey = '';
$codevalue = '';
foreach ($codes as $code) {
$code = trim($code);
$this->assignValues(explode(":", $code), $codekey, $codevalue);
if (strlen($codekey) > 0) {
$this->css[$key][trim($codekey)] = trim($codevalue);
}
}
}
}
public function get($key, $property)
{
$key = strtolower($key);
$property = strtolower($property);
$tag = '';
$subtag = '';
$class = '';
$id = '';
$this->assignValues(explode(":", $key), $tag, $subtag);
$this->assignValues(explode(".", $tag), $tag, $class);
$this->assignValues(explode("#", $tag), $tag, $id);
$result = "";
$_subtag = '';
$_class = '';
$_id = '';
foreach ($this->css as $_tag => $value) {
$this->assignValues(explode(":", $_tag), $_tag, $_subtag);
$this->assignValues(explode(".", $_tag), $_tag, $_class);
$this->assignValues(explode("#", $_tag), $_tag, $_id);
$tagmatch = (strcmp($tag, $_tag) == 0) | (strlen($_tag) == 0);
$subtagmatch = (strcmp($subtag, $_subtag) == 0) | (strlen($_subtag) == 0);
$classmatch = (strcmp($class, $_class) == 0) | (strlen($_class) == 0);
$idmatch = (strcmp($id, $_id) == 0);
if ($tagmatch & $subtagmatch & $classmatch & $idmatch) {
$temp = $_tag;
if ((strlen($temp) > 0) & (strlen($_class) > 0)) {
$temp .= ".".$_class;
} elseif (strlen($temp) == 0) {
$temp = ".".$_class;
}
if ((strlen($temp) > 0) & (strlen($_subtag) > 0)) {
$temp .= ":".$_subtag;
} elseif (strlen($temp) == 0) {
$temp = ":".$_subtag;
}
if (isset($this->css[$temp][$property])) {
$result = $this->css[$temp][$property];
}
}
}
return $result;
}
public function getSection($key)
{
$key = strtolower($key);
$tag = '';
$subtag = '';
$class = '';
$id = '';
$_subtag = '';
$_class = '';
$_id = '';
$this->assignValues(explode(":", $key), $tag, $subtag);
$this->assignValues(explode(".", $tag), $tag, $class);
$this->assignValues(explode("#", $tag), $tag, $id);
$result = [];
foreach ($this->css as $_tag => $value) {
$this->assignValues(explode(":", $_tag), $_tag, $_subtag);
$this->assignValues(explode(".", $_tag), $_tag, $_class);
$this->assignValues(explode("#", $_tag), $_tag, $_id);
$tagmatch = (strcmp($tag, $_tag) == 0) | (strlen($_tag) == 0);
$subtagmatch = (strcmp($subtag, $_subtag) == 0) | (strlen($_subtag) == 0);
$classmatch = (strcmp($class, $_class) == 0) | (strlen($_class) == 0);
$idmatch = (strcmp($id, $_id) == 0);
if ($tagmatch & $subtagmatch & $classmatch & $idmatch) {
$temp = $_tag;
if ((strlen($temp) > 0) & (strlen($_class) > 0)) {
$temp .= ".".$_class;
} elseif (strlen($temp) == 0) {
$temp = ".".$_class;
}
if ((strlen($temp) > 0) & (strlen($_subtag) > 0)) {
$temp .= ":".$_subtag;
} elseif (strlen($temp) == 0) {
$temp = ":".$_subtag;
}
foreach ($this->css[$temp] as $property => $value) {
$result[$property] = $value;
}
}
}
return $result;
}
public function parseStr($str)
{
$this->clear();
// Remove comments
$str = preg_replace("/\/\*(.*)?\*\//Usi", "", $str);
// Parse this damn csscode
$parts = explode("}", $str);
if (count($parts) > 0) {
foreach ($parts as $part) {
$keystr = '';
$codestr = '';
$this->assignValues(explode("{", $part), $keystr, $codestr);
$keys = explode(",", trim($keystr));
if (count($keys) > 0) {
foreach ($keys as $key) {
if (strlen($key) > 0) {
$key = str_replace("\n", "", $key);
$key = str_replace("\\", "", $key);
$this->Add($key, trim($codestr));
}
}
}
}
}
return count($this->css) > 0;
}
public function parse($filename)
{
$this->clear();
if (file_exists($filename)) {
return $this->parseStr(file_get_contents($filename));
} else {
return false;
}
}
public function getCSS()
{
$result = "";
foreach ($this->css as $key => $values) {
$result .= $key." {\n";
foreach ($values as $key => $value) {
$result .= " $key: $value;\n";
}
$result .= "}\n\n";
}
return $result;
}
private function assignValues($arr, &$val1, &$val2)
{
$n = count($arr);
if ($n > 0) {
$val1 = $arr[0];
$val2 = ($n > 1) ? $arr[1] : '';
}
}
}

View File

@@ -0,0 +1,470 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/xmlbase.php under GNU/GPL license */
/**
* Base XML class.
*/
class XMLGenericDocument
{
/**
* Document.
*
* @var DOMDocument
*/
public $doc = null;
/**
* Xpath.
*
* @var DOMXPath
*/
protected $dxpath = null;
protected $filename;
private $charset;
private $filepath;
private $isloaded = false;
private $arrayPrefixNS = [];
private $isHtml = false;
public function __construct($ch = 'UTF-8', $validatenow = true)
{
$this->charset = $ch;
$this->documentInit();
$this->doc->validateOnParse = $validatenow;
}
public function __destruct()
{
$this->dxpath = null;
$this->doc = null;
}
/**
* @param string $value
*
* @return string
*/
public static function safexml($value)
{
$result = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'),
ENT_NOQUOTES,
'UTF-8',
false);
return $result;
}
public function viewXML()
{
return $this->doc->saveXML();
}
public function registerNS($prefix, $nsuri)
{
$this->arrayPrefixNS[$prefix] = $nsuri;
}
public function load($fname)
{
// Sine xml will remain loaded should the repeated load fail we should recreate document to be empty.
$this->documentInit(false);
$this->isloaded = $this->doc->load($fname);
if ($this->isloaded) {
$this->filename = $fname;
$this->processPath();
$this->isHtml = false;
}
return $this->onLoad();
}
public function loadUrl($url)
{
$this->documentInit();
$this->isloaded = true;
$this->doc->loadXML(file_get_contents($url));
$this->isHtml = false;
return $this->onLoad();
}
public function loadHTML($content)
{
$this->documentInit();
$this->doc->validateOnParse = false;
$this->isloaded = true;
@$this->doc->loadHTML($content);
$this->isHtml = true;
return $this->onLoad();
}
public function loadXML($content)
{
$this->documentInit();
$this->doc->validateOnParse = false;
$this->isloaded = true;
$this->doc->load($content);
$this->isHtml = true;
return $this->onLoad();
}
public function loadHTMLFile($fname)
{
// Sine xml will remain loaded should the repeated load fail
// we should recreate document to be empty.
$this->documentInit();
$this->doc->validateOnParse = false;
$this->isloaded = $this->doc->loadHTMLFile($fname);
if ($this->isloaded) {
$this->filename = $fname;
$this->processPath();
$this->isHtml = true;
}
return $this->onLoad();
}
public function loadXMLFile($fname)
{
// Sine xml will remain loaded should the repeated load fail
// we should recreate document to be empty.
$this->documentInit();
$this->doc->validateOnParse = false;
$this->isloaded = $this->doc->load($fname);
if ($this->isloaded) {
$this->filename = $fname;
$this->processPath();
$this->isHtml = true;
}
return $this->onLoad();
}
public function loadString($content)
{
$this->doc = new DOMDocument("1.0", $this->charset);
$content = '<virtualtag>'.$content.'</virtualtag>';
$this->doc->loadXML($content);
return true;
}
public function save()
{
$this->saveTo($this->filename);
}
public function saveTo($fname)
{
$status = false;
if ($this->onSave()) {
if ($this->isHtml) {
$this->doc->saveHTMLFile($fname);
} else {
$this->doc->save($fname);
}
$this->filename = $fname;
$this->processPath();
$status = true;
}
return $status;
}
public function validate()
{
return $this->doc->validate();
}
public function attributeValue($path, $attrname, $node = null)
{
$this->chkxpath();
$result = null;
$resultlist = null;
if (is_null($node)) {
$resultlist = $this->dxpath->query($path);
} else {
$resultlist = $this->dxpath->query($path, $node);
}
if (is_object($resultlist) && ($resultlist->length > 0) && $resultlist->item(0)->hasAttribute($attrname)) {
$result = $resultlist->item(0)->getAttribute($attrname);
}
return $result;
}
/**
* Get's text value of the node based on xpath query.
*
* @param string $path
* @param DOMNode $node
* @param int $count
*
* @return string
*/
public function nodeValue($path, $node = null, $count = 1)
{
$nd = $this->node($path, $node, $count);
return $this->nodeTextValue($nd);
}
/**
* Get's text value of the node.
*
* @param DOMNode $node
*
* @return string
*/
public function nodeTextValue($node)
{
$result = '';
if (is_object($node)) {
if ($node->hasChildNodes()) {
$chnodesList = $node->childNodes;
$types = [XML_TEXT_NODE, XML_CDATA_SECTION_NODE];
foreach ($chnodesList as $chnode) {
if (in_array($chnode->nodeType, $types)) {
$result .= $chnode->wholeText;
}
}
}
}
return $result;
}
/**
* Get the nodes from a path.
*
* @param string $path
* @param DOMNode $nd
* @param int $count
*
* @return DOMNode
*/
public function node($path, $nd = null, $count = 1)
{
$result = null;
$resultlist = $this->nodeList($path, $nd);
if (is_object($resultlist) && ($resultlist->length > 0)) {
$result = $resultlist->item($count - 1);
}
return $result;
}
/**
* Get a list of nodes from a path.
*
* @param string $path
* @param DOMNode $node
*
* @return DOMNodeList
*/
public function nodeList($path, $node = null)
{
$this->chkxpath();
$resultlist = null;
if (is_null($node)) {
$resultlist = $this->dxpath->query($path);
} else {
$resultlist = $this->dxpath->query($path, $node);
}
return $resultlist;
}
/**
* Create new attribute.
*
* @param string $namespace
* @param string $name
* @param string $value
*
* @return DOMAttr
*/
public function createAttributeNs($namespace, $name, $value = null)
{
$result = $this->doc->createAttributeNS($namespace, $name);
if (!is_null($value)) {
$result->nodeValue = $value;
}
return $result;
}
/**
* Create new attribute.
*
* @param string $name
* @param string $value
*
* @return DOMAttr
*/
public function createAttribute($name, $value = null)
{
$result = $this->doc->createAttribute($name);
if (!is_null($value)) {
$result->nodeValue = $value;
}
return $result;
}
/**
* Adds new node.
*
* @param string $namespace
* @param string $name
* @param string $value
*
* @return DOMNode
*/
public function appendNewElementNs(DOMNode &$parentnode, $namespace, $name, $value = null)
{
$newnode = null;
if (is_null($value)) {
$newnode = $this->doc->createElementNS($namespace, $name);
} else {
$newnode = $this->doc->createElementNS($namespace, $name, $value);
}
return $parentnode->appendChild($newnode);
}
/**
* New node with CDATA content.
*
* @param string $namespace
* @param string $name
* @param string $value
*/
public function appendNewElementNsCdata(DOMNode &$parentnode, $namespace, $name, $value = null)
{
$newnode = $this->doc->createElementNS($namespace, $name);
if (!is_null($value)) {
$cdata = $this->doc->createCDATASection($value);
$newnode->appendChild($cdata);
}
return $parentnode->appendChild($newnode);
}
/**
* Adds new node.
*
* @param string $name
* @param string $value
*
* @return DOMNode
*/
public function appendNewElement(DOMNode &$parentnode, $name, $value = null)
{
$newnode = null;
if (is_null($value)) {
$newnode = $this->doc->createElement($name);
} else {
$newnode = $this->doc->createElement($name, $value);
}
return $parentnode->appendChild($newnode);
}
/**
* Adds new attribute.
*
* @param string $name
* @param string $value
*
* @return DOMNode
*/
public function appendNewAttribute(DOMNode &$node, $name, $value = null)
{
return $node->appendChild($this->createAttribute($name, $value));
}
/**
* Adds new attribute.
*
* @param string $namespace
* @param string $name
* @param string $value
*
* @return DOMNode
*/
public function appendNewAttributeNs(DOMNode &$node, $namespace, $name, $value = null)
{
return $node->appendChild($this->createAttributeNs($namespace, $name, $value));
}
public function fileName()
{
return $this->filename;
}
public function filePath()
{
return $this->filepath;
}
public function resetXpath()
{
$this->dxpath = null;
$this->chkxpath();
}
protected function onLoad()
{
return $this->isloaded;
}
protected function onSave()
{
return true;
}
protected function onCreate()
{
return true;
}
protected function processPath()
{
$path_parts = pathinfo($this->filename);
$this->filepath = array_key_exists('dirname', $path_parts) ? $path_parts['dirname']."/" : '';
}
private function documentInit($withonCreate = true)
{
$hg = false;
if ($this->isloaded) {
$guardstate = $this->doc->validateOnParse;
$hg = true;
unset($this->dxpath);
unset($this->doc);
$this->isloaded = false;
}
$this->doc = new DOMDocument("1.0", $this->charset);
$this->doc->strictErrorChecking = true;
if ($hg) {
$this->doc->validateOnParse = $guardstate;
}
$this->doc->formatOutput = true;
$this->doc->preserveWhiteSpace = true;
if ($withonCreate) {
$this->onCreate();
}
}
private function chkxpath()
{
if (!isset($this->dxpath) || is_null($this->dxpath)) {
$this->dxpath = new DOMXPath($this->doc);
foreach ($this->arrayPrefixNS as $nskey => $nsuri) {
$this->dxpath->registerNamespace($nskey, $nsuri);
}
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_folder.php under GNU/GPL license */
class CcConverterFolder extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$this->defaultfile = 'folder.xml';
parent::__construct($item, $manifest, $rootpath, $path);
}
public function convert($outdir, $objDocument)
{
$contextid = $objDocument['source_id'];
$folder = api_get_path(SYS_COURSE_PATH).api_get_course_path($objDocument['course_code']).'/'.$objDocument['path'];
$files = CcHelpers::handleStaticContent($this->manifest,
$this->rootpath,
$contextid,
$outdir,
true,
$folder
);
$resvalue = null;
foreach ($files as $values) {
if ($values[2]) {
$resvalue = $values[0];
break;
}
}
$resitem = new CcItem();
$resitem->identifierref = $resvalue;
$resitem->title = $objDocument['title'];
$this->item->addChildItem($resitem);
return true;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_forum.php under GNU/GPL license */
class CcConverterForum extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$this->ccType = CcVersion13::DISCUSSIONTOPIC;
$this->defaultfile = 'forum.xml';
$this->defaultname = 'discussion.xml';
parent::__construct($item, $manifest, $rootpath, $path);
}
public function convert($outdir, $item)
{
$rt = new CcForum();
$title = $item['title'];
$rt->setTitle($title);
$text = $item['comment'];
$deps = null;
if (!empty($text)) {
$contextid = $item['source_id'];
$result = CcHelpers::processLinkedFiles($text,
$this->manifest,
$this->rootpath,
$contextid,
$outdir);
$textformat = 'text/html';
$rt->setText($result[0], $textformat);
$deps = $result[1];
}
$this->store($rt, $outdir, $title, $deps);
return true;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_page.php under GNU/GPL license */
class CcConverterPage extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$this->ccType = CcVersion13::WEBCONTENT;
$this->defaultfile = 'page.xml';
$this->defaultname = uniqid().'.html';
parent::__construct($item, $manifest, $rootpath, $path);
}
public function convert($outdir, $objPage)
{
$rt = new CcPage();
$title = $objPage['title'];
$intro = '';
$contextid = $objPage['source_id'];
$pagecontent = $objPage['comment'];
$rt->setTitle($title);
$rawname = str_replace(' ', '_', strtolower(trim(Security::filter_filename($title))));
if (!empty($rawname)) {
$this->defaultname = $rawname.".html";
}
$result = CcHelpers::processLinkedFiles($pagecontent,
$this->manifest,
$this->rootpath,
$contextid,
$outdir,
true);
$rt->setContent($result[0]);
$rt->setIntro($intro);
//store everything
$this->store($rt, $outdir, $title, $result[1]);
return true;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_quiz.php under GNU/GPL license */
class CcConverterQuiz extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, string $rootpath, string $path)
{
$this->ccType = CcVersion13::ASSESSMENT;
$this->defaultfile = 'quiz.xml';
$this->defaultname = Assesment13ResourceFile::DEAFULTNAME;
parent::__construct($item, $manifest, $rootpath, $path);
}
/**
* Convert a quiz to a CC XML file (.xml) in a subfolder of the whole CC archive.
*
* @param $outdir
* @param $objQuizz
*
* @return bool true
*/
public function convert($outdir, $objQuizz): bool
{
$rt = new Assesment13ResourceFile();
$title = $objQuizz['title'];
$rt->setTitle($title);
// Metadata.
$metadata = new CcAssesmentMetadata();
$rt->setMetadata($metadata);
$metadata->enableFeedback();
$metadata->enableHints();
$metadata->enableSolutions();
// Attempts.
$maxAttempts = $objQuizz['max_attempt'];
if ($maxAttempts > 0) {
// Qti does not support number of specific attempts bigger than 5 (??)
if ($maxAttempts > 5) {
$maxAttempts = CcQtiValues::UNLIMITED;
}
$metadata->setMaxattempts($maxAttempts);
}
// Time limit must be converted into minutes.
$timelimit = $objQuizz['expired_time'];
if ($timelimit > 0) {
$metadata->setTimelimit($timelimit);
$metadata->enableLatesubmissions(false);
}
$contextid = $objQuizz['source_id'];
$result = CcHelpers::processLinkedFiles($objQuizz['comment'],
$this->manifest,
$this->rootpath,
$contextid,
$outdir);
// Use exercise description, get it from $result[0] generated above.
CcAssesmentHelper::addAssesmentDescription($rt, $result[0], CcQtiValues::HTMLTYPE);
// Section.
$section = new CcAssesmentSection();
$rt->setSection($section);
// Process the actual questions.
$ndeps = CcAssesmentHelper::processQuestions($objQuizz,
$this->manifest,
$section,
$this->rootpath,
$contextid,
$outdir
);
if ($ndeps === false) {
// No exportable questions in quiz or quiz has no questions
// so just skip it.
return true;
}
// Store any additional dependencies.
$deps = array_merge($result[1], $ndeps);
// Store everything.
$this->store($rt, $outdir, $title, $deps);
return true;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_resource.php under GNU/GPL license */
class CcConverterResource extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$this->ccType = CcVersion13::WEBCONTENT;
$this->defaultfile = 'resource.xml';
parent::__construct($item, $manifest, $rootpath, $path);
}
public function convert($outdir, $objResource)
{
$title = $objResource['title'];
$contextid = $objResource['source_id'];
$docfilepath = null;
if (isset($objResource['path'])) {
$docfilepath = api_get_path(SYS_COURSE_PATH).api_get_course_path($objResource['course_code']).DIRECTORY_SEPARATOR.$objResource['path'];
}
$files = CcHelpers::handleResourceContent($this->manifest,
$this->rootpath,
$contextid,
$outdir,
true,
$docfilepath);
$deps = null;
$resvalue = null;
foreach ($files as $values) {
if ($values[2]) {
$resvalue = $values[0];
break;
}
}
$resitem = new CcItem();
$resitem->identifierref = $resvalue;
$resitem->title = $title;
$this->item->addChildItem($resitem);
// Checking the visibility.
$this->manifest->updateInstructoronly($resvalue, !$this->isVisible());
return true;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_converter_url.php under GNU/GPL license */
class CcConverterUrl extends CcConverters
{
public function __construct(CcIItem &$item, CcIManifest &$manifest, $rootpath, $path)
{
$this->ccType = CcVersion13::WEBLINK;
$this->defaultfile = 'url.xml';
$this->defaultname = 'weblink.xml';
parent::__construct($item, $manifest, $rootpath, $path);
}
public function convert($outdir, $objLink)
{
$rt = new CcWebLink();
$title = $objLink['title'];
$rt->setTitle($title);
$url = $objLink['url'];
if (!empty($url)) {
$rt->setUrl($url, $objLink['target']);
}
$this->store($rt, $outdir, $title);
return true;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Item Interface.
*/
interface CcIItem
{
public function addChildItem(CcIItem &$item);
public function attachResource($res); // can be object or value
public function hasChildItems();
public function attrValue(&$nod, $name, $ns = null);
public function processItem(&$node, &$doc);
}

View File

@@ -0,0 +1,30 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Manifest Interface.
*/
interface CcIManifest
{
public function onCreate();
public function onLoad();
public function onSave();
public function addNewOrganization(CcIOrganization &$org);
public function getResources();
public function getResourceList();
public function addResource(CcIResource $res, $identifier = null, $type = 'webcontent');
public function addMetadataManifest(CcIMetadataManifest $met);
public function addMetadataResource(CcIMetadataResource $met, $identifier);
public function addMetadataFile(CcIMetadataFile $met, $identifier, $filename);
public function putNodes();
}

View File

@@ -0,0 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Metadata File Interface.
*/
interface CcIMetadataFile
{
public function addMetadataFileEducational($obj);
}

View File

@@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Metadata Manifest Interface.
*/
interface CcIMetadataManifest
{
public function addMetadataGeneral($obj);
public function addMetadataTechnical($obj);
public function addMetadataRights($obj);
public function addMetadataLifecycle($obj);
}

View File

@@ -0,0 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Metadata Resource Interface.
*/
interface CcIMetadataResource
{
public function addMetadataResourceEducational($obj);
}

View File

@@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Organization Interface.
*/
interface CcIOrganization
{
public function addItem(CcIItem &$item);
public function hasItems();
public function attrValue(&$nod, $name, $ns = null);
public function processOrganization(&$node, &$doc);
}

View File

@@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
/**
* CC Resource Interface.
*/
interface CcIResource
{
public function getAttrValue(&$nod, $name, $ns = null);
public function addResource($fname, $location = '');
public function importResource(DOMElement &$node, CcIManifest &$doc);
public function processResource($manifestroot, &$fname, $folder);
}

View File

@@ -0,0 +1,7 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class Assesment13ResourceFile extends Assesment1ResourceFile
{
protected $ccnsnames = ['xmlns' => 'http://www.imsglobal.org/profile/cc/ccv1p3/ccv1p3_qtiasiv1p2p1_v1p0.xsd'];
}

View File

@@ -0,0 +1,74 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class Assesment1ResourceFile extends CcGeneralFile
{
public const DEAFULTNAME = 'assessment.xml';
protected $rootns = 'xmlns';
protected $rootname = CcQtiTags::QUESTESTINTEROP;
protected $ccnamespaces = ['xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', ];
protected $ccnsnames = ['xmlns' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_4/ims_qtiasiv1p2_localised.xsd'];
protected $assessmentTitle = 'Untitled';
protected $metadata = null;
protected $rubric = null;
protected $presentationMaterial = null;
protected $section = null;
public function setMetadata(CcAssesmentMetadata $object)
{
$this->metadata = $object;
}
public function setRubric(CcAssesmentRubricBase $object)
{
$this->rubric = $object;
}
public function setPresentationMaterial(CcAssesmentPresentationMaterialBase $object)
{
$this->presentationMaterial = $object;
}
public function setSection(CcAssesmentSection $object)
{
$this->section = $object;
}
public function setTitle($value)
{
$this->assessmentTitle = self::safexml($value);
}
protected function onSave()
{
$rns = $this->ccnamespaces[$this->rootns];
//root assesment element - required
$assessment = $this->appendNewElementNs($this->root, $rns, CcQtiTags::ASSESSMENT);
$this->appendNewAttributeNs($assessment, $rns, CcQtiTags::IDENT, CcHelpers::uuidgen('QDB_'));
$this->appendNewAttributeNs($assessment, $rns, CcQtiTags::TITLE, $this->assessmentTitle);
//metadata - optional
if (!empty($this->metadata)) {
$this->metadata->generate($this, $assessment, $rns);
}
//rubric - optional
if (!empty($this->rubric)) {
$this->rubric->generate($this, $assessment, $rns);
}
//presentation_material - optional
if (!empty($this->presentationMaterial)) {
$this->presentationMaterial->generate($this, $assessment, $rns);
}
//section - required
if (!empty($this->section)) {
$this->section->generate($this, $assessment, $rns);
}
return true;
}
}

View File

@@ -0,0 +1,11 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentAltmaterial extends CcAssesmentMaterialBase
{
public function __construct($value = null)
{
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML);
$this->tagname = CcQtiTags::ALTMATERIAL;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentDecvartype extends CcQuestionMetadataBase
{
public function __construct()
{
$this->setSetting(CcQtiTags::VARNAME, CcQtiValues::SCORE);
$this->setSetting(CcQtiTags::VARTYPE, CcQtiValues::INTEGER);
$this->setSetting(CcQtiTags::MINVALUE);
$this->setSetting(CcQtiTags::MAXVALUE);
}
public function setVartype($value)
{
$this->setSetting(CcQtiTags::VARTYPE, $value);
}
public function setLimits($min = null, $max = null)
{
$this->setSetting(CcQtiTags::MINVALUE, $min);
$this->setSetting(CcQtiTags::MAXVALUE, $max);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::DECVAR);
$this->generateAttributes($doc, $node, $namespace);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentFlowLabeltype extends CcQuestionMetadataBase
{
protected $flowLabel = null;
protected $responseLabel = null;
public function __construct()
{
$this->setSetting(CcQtiTags::T_CLASS);
}
public function setClass($value)
{
$this->setSetting(CcQtiTags::T_CLASS, $value);
}
public function setFlowLabel(CcAssesmentFlowLabeltype $object)
{
$this->flowLabel = $object;
}
public function setResponseLabel(CcAssesmentResponseLabeltype $object)
{
$this->responseLabel = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::FLOW_LABEL);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->material)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->materialRef)) {
$this->materialRef->generate($doc, $node, $namespace);
}
if (!empty($this->responseLabel)) {
$this->responseLabel->generate($doc, $node, $namespace);
}
if (!empty($this->flowLabel)) {
$this->flowLabel->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,46 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentFlowMatBase extends CcQuestionMetadataBase
{
protected $mattag = null;
public function __construct($value = null)
{
$this->setSetting(CcQtiTags::T_CLASS);
}
public function setFlowMat(CcAssesmentFlowMatBase $object)
{
$this->setTagValue($object);
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->setTagValue($object);
}
public function setMaterialRef(CcAssesmentMatref $object)
{
$this->setTagValue($object);
}
public function setClass($value)
{
$this->setSetting(CcQtiTags::T_CLASS, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::FLOW_MAT);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->mattag)) {
$this->mattag->generate($doc, $node, $namespace);
}
}
protected function setTagValue($object)
{
$this->mattag = $object;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentFlowMattype extends CcQuestionMetadataBase
{
protected $material = null;
protected $materialRef = null;
protected $flowMat = null;
public function __construct()
{
$this->setSetting(CcQtiTags::T_CLASS);
}
public function setClass($value)
{
$this->setSetting(CcQtiTags::T_CLASS, $value);
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function setMaterialRef(CcAssesmentResponseMatref $object)
{
$this->materialRef = $object;
}
public function setFlowMat(CcAssesmentFlowMattype $object)
{
$this->flowMat = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::FLOW_MAT);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->flowMat)) {
$this->flowMat->generate($doc, $node, $namespace);
}
if (!empty($this->material)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->materialRef)) {
$this->materialRef->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentFlowtype extends CcQuestionMetadataBase
{
protected $flow = null;
protected $material = null;
protected $materialRef = null;
protected $responseLid = null;
protected $responseStr = null;
public function __construct()
{
$this->setSetting(CcQtiTags::T_CLASS);
}
public function setClass($value)
{
$this->setSetting(CcQtiTags::T_CLASS, $value);
}
public function setFlow(CcAssesmentFlowtype $object)
{
$this->flow = $object;
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function setMaterialRef(CcAssesmentResponseMatref $object)
{
$this->materialRef = $object;
}
public function setResponseLid(CcResponseLidtype $object)
{
$this->responseLid = $object;
}
public function setResponseStr(CcAssesmentResponseStrtype $object)
{
$this->responseStr = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::FLOW);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->flow)) {
$this->flow->generate($doc, $node, $namespace);
}
if (!empty($this->material)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->responseLid)) {
$this->responseLid->generate($doc, $node, $namespace);
}
if (!empty($this->responseStr)) {
$this->responseStr->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,167 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcAssesmentHelper
{
public static $correctFb = null;
public static $incorrectFb = null;
public static function addFeedback($qitem, $content, $contentType, $ident)
{
if (empty($content)) {
return false;
}
$qitemfeedback = new CcAssesmentItemfeedbacktype();
$qitem->addItemfeedback($qitemfeedback);
if (!empty($ident)) {
$qitemfeedback->setIdent($ident);
}
$qflowmat = new CcAssesmentFlowMattype();
$qitemfeedback->setFlowMat($qflowmat);
$qmaterialfb = new CcAssesmentMaterial();
$qflowmat->setMaterial($qmaterialfb);
$qmattext = new CcAssesmentMattext();
$qmaterialfb->setMattext($qmattext);
$qmattext->setContent($content, $contentType);
return true;
}
public static function addAnswer($qresponseChoice, $content, $contentType)
{
$qresponseLabel = new CcAssesmentResponseLabeltype();
$qresponseChoice->addResponseLabel($qresponseLabel);
$qrespmaterial = new CcAssesmentMaterial();
$qresponseLabel->setMaterial($qrespmaterial);
$qrespmattext = new CcAssesmentMattext();
$qrespmaterial->setMattext($qrespmattext);
$qrespmattext->setContent($content, $contentType);
return $qresponseLabel;
}
public static function addResponseCondition($node, $title, $ident, $feedbackRefid, $respident)
{
$qrespcondition = new CcAssesmentRespconditiontype();
$node->addRespcondition($qrespcondition);
//define rest of the conditions
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
$qvarequal = new CcAssignmentConditionvarVarequaltype($ident);
$qvarequal->enableCase();
$qconditionvar->setVarequal($qvarequal);
$qvarequal->setRespident($respident);
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($feedbackRefid);
}
public static function addAssesmentDescription($rt, $content, $contenttype)
{
if (empty($rt) || empty($content)) {
return;
}
$activity_rubric = new CcAssesmentRubricBase();
$rubric_material = new CcAssesmentMaterial();
$activity_rubric->setMaterial($rubric_material);
$rubric_mattext = new CcAssesmentMattext();
$rubric_material->setLabel('Summary');
$rubric_material->setMattext($rubric_mattext);
$rubric_mattext->setContent($content, $contenttype);
$rt->setRubric($activity_rubric);
}
public static function addRespcondition($node, $title, $feedbackRefid, $gradeValue = null, $continue = false)
{
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle($title);
$node->addRespcondition($qrespcondition);
$qrespcondition->enableContinue($continue);
//Add setvar if grade present
if ($gradeValue !== null) {
$qsetvar = new CcAssignmentSetvartype($gradeValue);
$qrespcondition->addSetvar($qsetvar);
}
//define the condition for success
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
$qother = new CcAssignmentConditionvarOthertype();
$qconditionvar->setOther($qother);
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($feedbackRefid);
}
/**
* Enter description here ...
*
* @param XMLGenericDocument $qdoc
* @param unknown_type $manifest
* @param cc_assesment_section $section
* @param unknown_type $rootpath
* @param unknown_type $contextid
* @param string $outdir
*/
public static function processQuestions(&$objQuizz, &$manifest, CcAssesmentSection &$section, $rootpath, $contextid, $outdir)
{
PkgResourceDependencies::instance()->reset();
$questioncount = 0;
foreach ($objQuizz['questions'] as $question) {
$qtype = $question->quiz_type;
/* Question type comes from the c_quiz_question.type column.
* You can find the different types defined in api.lib.php.
* Look for UNIQUE_ANSWER as the first constant defined
* 1 : Unique Answer (Multiple choice, single response)
* 2 : Multiple Answers (Multiple choice, multiple response)
* 5 : Free Answer ("essay" in CC13)
*/
$questionProcessor = null;
switch ($qtype) {
case UNIQUE_ANSWER:
try {
$questionProcessor = new CcAssesmentQuestionMultichoice($objQuizz, $objQuizz['questions'], $manifest, $section, $question, $rootpath, $contextid, $outdir);
$questionProcessor->generate();
$questioncount++;
} catch (RuntimeException $e) {
error_log($e->getMessage().' in question of test '.$objQuizz['title']);
continue 2;
}
break;
case MULTIPLE_ANSWER:
try {
$questionProcessor = new CcAssesmentQuestionMultichoiceMultiresponse($objQuizz, $objQuizz['questions'], $manifest, $section, $question, $rootpath, $contextid, $outdir);
$questionProcessor->generate();
$questioncount++;
} catch (RuntimeException $e) {
error_log($e->getMessage().' in question of test '.$objQuizz['title']);
continue 2;
}
break;
case FILL_IN_BLANKS:
try {
$questionProcessor = new CcAssesmentQuestionFib($objQuizz, $objQuizz['questions'], $manifest, $section, $question, $rootpath, $contextid, $outdir);
$questionProcessor->generate();
$questioncount++;
} catch (RuntimeException $e) {
error_log($e->getMessage().' in question of test '.$objQuizz['title']);
continue 2;
}
break;
case FREE_ANSWER:
try {
$questionProcessor = new CcAssesmentQuestionEssay($objQuizz, $objQuizz['questions'], $manifest, $section, $question, $rootpath, $contextid, $outdir);
$questionProcessor->generate();
$questioncount++;
} catch (RuntimeException $e) {
error_log($e->getMessage().' in question of test '.$objQuizz['title']);
continue 2;
}
break;
}
}
//return dependencies
return ($questioncount == 0) ? false : PkgResourceDependencies::instance()->getDeps();
}
}

View File

@@ -0,0 +1,16 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbacHinttype extends CcAssesmentItemfeedbackShintypeBase
{
public function __construct()
{
parent::__construct();
$this->tagname = CcQtiTags::HINT;
}
public function addHintmaterial(CcAssesmentItemfeedbackHintmaterial $object)
{
$this->items[] = $object;
}
}

View File

@@ -0,0 +1,10 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbackHintmaterial extends CcAssesmentItemfeedbackShintmaterialBase
{
public function __construct()
{
$this->tagname = CcQtiTags::HINT;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbackShintmaterialBase extends CcQuestionMetadataBase
{
protected $tagname = null;
protected $flowMats = [];
protected $materials = [];
public function addFlowMat(CcAssesmentFlowMattype $object)
{
$this->flowMats[] = $object;
}
public function add_material(CcAssesmentMaterial $object)
{
$this->materials[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, $this->tagname);
if (!empty($this->flowMats)) {
foreach ($this->flowMats as $flowMat) {
$flowMat->generate($doc, $node, $namespace);
}
}
if (!empty($this->materials)) {
foreach ($this->materials as $material) {
$material->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbackShintypeBase extends CcQuestionMetadataBase
{
protected $tagname = null;
protected $items = [];
public function __construct()
{
$this->setSetting(CcQtiTags::FEEDBACKSTYLE, CcQtiValues::COMPLETE);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, $this->tagname);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->items)) {
foreach ($this->items as $telement) {
$telement->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbackSolutionmaterial extends CcAssesmentItemfeedbackShintmaterialBase
{
public function __construct()
{
$this->tagname = CcQtiTags::SOLUTIONMATERIAL;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbackSolutiontype extends CcAssesmentItemfeedbackShintypeBase
{
public function __construct()
{
parent::__construct();
$this->tagname = CcQtiTags::SOLUTION;
}
public function add_solutionmaterial(CcAssesmentItemfeedbackSolutionmaterial $object)
{
$this->items[] = $object;
}
}

View File

@@ -0,0 +1,74 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemfeedbacktype extends CcQuestionMetadataBase
{
protected $flowMat = null;
protected $material = null;
protected $solution = null;
protected $hint = null;
public function __construct()
{
$this->setSetting(CcQtiTags::IDENT, CcHelpers::uuidgen('I_'));
$this->setSetting(CcQtiTags::TITLE);
}
/**
* @param string $value
*/
public function setIdent($value)
{
$this->setSetting(CcQtiTags::IDENT, $value);
}
/**
* @param string $value
*/
public function setTitle($value)
{
$this->setSetting(CcQtiTags::TITLE, $value);
}
public function setFlowMat(CcAssesmentFlowMattype $object)
{
$this->flowMat = $object;
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function set_solution(CcAssesmentItemfeedbackSolutiontype $object)
{
$this->solution = $object;
}
public function set_hint($object)
{
$this->hint = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::ITEMFEEDBACK);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->flowMat) && empty($this->material)) {
$this->flowMat->generate($doc, $node, $namespace);
}
if (!empty($this->material) && empty($this->flowMat)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->solution)) {
$this->solution->generate($doc, $node, $namespace);
}
if (!empty($this->itemfeedback)) {
$this->itemfeedback->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,20 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentItemmetadata extends CcQuestionMetadataBase
{
public function addMetadata($object)
{
$this->metadata[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::ITEMMETADATA);
if (!empty($this->metadata)) {
foreach ($this->metadata as $metaitem) {
$metaitem->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentMatbreak
{
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$doc->appendNewElementNs($item, $namespace, CcQtiTags::MATBREAK);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentMaterial extends CcAssesmentMaterialBase
{
protected $altmaterial = null;
public function __construct($value = null)
{
$this->setSetting(CcQtiTags::LABEL);
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML);
$this->tagname = CcQtiTags::MATERIAL;
}
public function setLabel($value)
{
$this->setSetting(CcQtiTags::LABEL, $value);
}
public function setAltmaterial(CcAssesmentAltmaterial $object)
{
$this->altmaterial = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$material = parent::generate($doc, $item, $namespace);
if (!empty($this->altmaterial)) {
$this->altmaterial->generate($doc, $material, $namespace);
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcAssesmentMaterialBase extends CcQuestionMetadataBase
{
/**
* @var mixed
*/
protected $mattag = null;
protected $tagname = null;
public function setMattext(CcAssesmentMattext $object)
{
$this->setTagValue($object);
}
public function setMatref(CcAssesmentMatref $object)
{
$this->setTagValue($object);
}
public function setMatbreak(CcAssesmentMatbreak $object)
{
$this->setTagValue($object);
}
public function setLang($value)
{
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$material = $doc->appendNewElementNs($item, $namespace, $this->tagname);
$this->generateAttributes($doc, $material, $namespace);
if (!empty($this->mattag)) {
$this->mattag->generate($doc, $material, $namespace);
}
return $material;
}
protected function setTagValue($object)
{
$this->mattag = $object;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentMatref
{
protected $linkref = null;
public function __construct($linkref)
{
$this->linkref = $linkref;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::MATREF, $this->linkref);
$doc->appendNewAttributeNs($node, $namespace, CcQtiTags::LINKREFID, $this->linkref);
}
}

View File

@@ -0,0 +1,62 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentMattext extends CcQuestionMetadataBase
{
protected $value = null;
public function __construct($value = null)
{
$this->setSetting(CcQtiTags::TEXTTYPE, CcQtiValues::TEXTTYPE);
$this->setSetting(CcQtiTags::CHARSET); //, 'ascii-us');
$this->setSetting(CcQtiTags::LABEL);
$this->setSetting(CcQtiTags::URI);
$this->setSetting(CcQtiTags::WIDTH);
$this->setSetting(CcQtiTags::HEIGHT);
$this->setSetting(CcQtiTags::X0);
$this->setSetting(CcQtiTags::Y0);
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML);
$this->setSettingWns(CcQtiTags::XML_SPACE, CcXmlNamespace::XML); //, 'default');
$this->value = $value;
}
public function setLabel($value)
{
$this->setSetting(CcQtiTags::LABEL, $value);
}
public function setUri($value)
{
$this->setSetting(CcQtiTags::URI, $value);
}
public function setWidthHeight($width = null, $height = null)
{
$this->setSetting(CcQtiTags::WIDTH, $width);
$this->setSetting(CcQtiTags::HEIGHT, $height);
}
public function setCoor($x = null, $y = null)
{
$this->setSetting(CcQtiTags::X0, $x);
$this->setSetting(CcQtiTags::Y0, $y);
}
public function setLang($lang = null)
{
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML, $lang);
}
public function setContent($content, $type = CcQtiValues::TEXTTYPE, $charset = null)
{
$this->value = $content;
$this->setSetting(CcQtiTags::TEXTTYPE, $type);
$this->setSetting(CcQtiTags::CHARSET, $charset);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$mattext = $doc->appendNewElementNsCdata($item, $namespace, CcQtiTags::MATTEXT, $this->value);
$this->generateAttributes($doc, $mattext, $namespace);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentMetadata extends CcQuestionMetadataBase
{
public function __construct()
{
//prepared default values
$this->setSetting(CcQtiMetadata::CC_PROFILE, CcQtiValues::EXAM_PROFILE);
$this->setSetting(CcQtiMetadata::QMD_ASSESSMENTTYPE, CcQtiValues::EXAMINATION);
$this->setSetting(CcQtiMetadata::QMD_SCORETYPE, CcQtiValues::PERCENTAGE);
//optional empty values
$this->setSetting(CcQtiMetadata::QMD_FEEDBACKPERMITTED);
$this->setSetting(CcQtiMetadata::QMD_HINTSPERMITTED);
$this->setSetting(CcQtiMetadata::QMD_SOLUTIONSPERMITTED);
$this->setSetting(CcQtiMetadata::QMD_TIMELIMIT);
$this->setSetting(CcQtiMetadata::CC_ALLOW_LATE_SUBMISSION);
$this->setSetting(CcQtiMetadata::CC_MAXATTEMPTS);
}
public function enableHints($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::QMD_HINTSPERMITTED, $value);
}
public function enableSolutions($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::QMD_SOLUTIONSPERMITTED, $value);
}
public function enableLatesubmissions($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::CC_ALLOW_LATE_SUBMISSION, $value);
}
public function enableFeedback($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::QMD_FEEDBACKPERMITTED, $value);
}
public function setTimelimit($value)
{
$ivalue = (int) $value;
if (($ivalue < 0) || ($ivalue > 527401)) {
throw new OutOfRangeException('Time limit value out of permitted range!');
}
$this->setSetting(CcQtiMetadata::QMD_TIMELIMIT, $value);
}
public function setMaxattempts($value)
{
$valid_values = [CcQtiValues::EXAMINATION, CcQtiValues::UNLIMITED, 1, 2, 3, 4, 5];
if (!in_array($value, $valid_values)) {
throw new OutOfRangeException('Max attempts has invalid value');
}
$this->setSetting(CcQtiMetadata::CC_MAXATTEMPTS, $value);
}
}

View File

@@ -0,0 +1,84 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentPresentation extends CcQuestionMetadataBase
{
protected $flow = null;
protected $material = null;
protected $responseLid = null;
protected $responseStr = null;
public function __construct()
{
$this->setSetting(CcQtiTags::LABEL);
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML);
$this->setSetting(CcQtiTags::X0);
$this->setSetting(CcQtiTags::Y0);
$this->setSetting(CcQtiTags::WIDTH);
$this->setSetting(CcQtiTags::HEIGHT);
}
public function setLabel($value)
{
$this->setSetting(CcQtiTags::LABEL, $value);
}
public function setLang($value)
{
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML, $value);
}
public function setCoor($x = null, $y = null)
{
$this->setSetting(CcQtiTags::X0, $x);
$this->setSetting(CcQtiTags::Y0, $y);
}
public function setSize($width = null, $height = null)
{
$this->setSetting(CcQtiTags::WIDTH, $width);
$this->setSetting(CcQtiTags::HEIGHT, $height);
}
public function setFlow(CcAssesmentFlowtype $object)
{
$this->flow = $object;
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function setResponseLid(CcResponseLidtype $object)
{
$this->responseLid = $object;
}
public function setResponseStr(CcAssesmentResponseStrtype $object)
{
$this->responseStr = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::PRESENTATION);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->flow)) {
$this->flow->generate($doc, $node, $namespace);
}
if (!empty($this->material) && empty($this->flow)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->responseLid) && empty($this->flow)) {
$this->responseLid->generate($doc, $node, $namespace);
}
if (!empty($this->responseStr) && empty($this->flow)) {
$this->responseStr->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentPresentationMaterialBase extends CcQuestionMetadataBase
{
protected $flowmats = [];
public function addFlowMat($object)
{
$this->flowmats[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::PRESENTATION_MATERIAL);
if (!empty($this->flowmats)) {
foreach ($this->flowmats as $flowMat) {
$flowMat->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentQuestionEssay extends CcAssesmentQuestionProcBase
{
public function __construct($quiz, $questions, $manifest, $section, $question, $rootpath, $contextid, $outdir)
{
parent::__construct($quiz, $questions, $manifest, $section, $question, $rootpath, $contextid, $outdir);
$this->qtype = CcQtiProfiletype::ESSAY;
$questionScore = $question->ponderation;
/*
// Looks useless for CC13!?
if (is_int($questionScore)) {
$questionScore = ($questionScore).'.0000000';
}
*/
$this->total_grade_value = $questionScore;
$this->totalGradeValue = $questionScore;
$this->qitem->setTitle($question->question);
}
public function onGenerateAnswers()
{
//add responses holder
$answerlist = [];
$this->answerlist = $answerlist;
}
public function onGenerateFeedbacks()
{
parent::onGenerateFeedbacks();
}
public function onGenerateResponseProcessing()
{
parent::onGenerateResponseProcessing();
/**
* General unconditional feedback must be added as a first respcondition
* without any condition and just displayfeedback (if exists).
*/
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle('General feedback');
$this->qresprocessing->addRespcondition($qrespcondition);
$qrespcondition->enableContinue();
}
}

View File

@@ -0,0 +1,121 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentQuestionFib extends CcAssesmentQuestionProcBase
{
public function __construct($quiz, $questions, $manifest, $section, $questionNode, $rootpath, $contextid, $outdir)
{
parent::__construct($quiz, $questions, $manifest, $section, $questionNode, $rootpath, $contextid, $outdir);
$this->qtype = CcQtiProfiletype::FIELD_ENTRY;
$correctAnswerNodes = [];
$questionScore = 0;
foreach ($questionNode->answers as $index => $answer) {
$answerScore = 0;
$answerText = $answer['answer'];
$pos = strrpos($answerText, '::');
list($answerText, $answerRules) = explode('::', $answerText);
$matches = [];
list($weights, $sizes, $others) = explode(':', $answerRules);
$weights = explode(',', $weights);
$i = 0;
// Todo: improve to tolerate all separators
if (preg_match_all('/\[(.*?)\]/', $answerText, $matches)) {
foreach ($matches[1] as $match) {
$correctAnswerNodes[] = $match;
$questionScore += $weights[$i];
$answerScore += $weights[$i];
$i++;
}
}
$questionNode->answers[$index] = [
'answer' => $answerText,
'ponderation' => $answerScore,
'comment' => $answer['comment'],
];
$questionScore++;
}
if (count($correctAnswerNodes) == 0) {
throw new RuntimeException('No correct answer!');
}
$this->correctAnswers = $correctAnswerNodes;
$this->totalGradeValue = $questionScore;
}
public function onGenerateAnswers()
{
//add responses holder
$qresponseLid = new CcResponseLidtype();
$this->qresponseLid = $qresponseLid;
$this->qpresentation->setResponseLid($qresponseLid);
$qresponseChoice = new CcAssesmentRenderFibtype();
$qresponseLid->setRenderFib($qresponseChoice);
//Mark that question has more than one correct answer
$qresponseLid->setRcardinality(CcQtiValues::MULTIPLE);
//are we to shuffle the responses?
$shuffleAnswers = $this->quiz['random_answers'] > 0;
$qresponseChoice->enableShuffle($shuffleAnswers);
$answerlist = [];
$qaResponses = $this->questionNode->answers;
foreach ($qaResponses as $node) {
$answerContent = $node['answer'];
$answerGradeFraction = $node['ponderation'];
$result = CcHelpers::processLinkedFiles($answerContent,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
$qresponseLabel = CcAssesmentHelper::addAnswer($qresponseChoice,
$result[0],
CcQtiValues::HTMLTYPE);
PkgResourceDependencies::instance()->add($result[1]);
$answerIdent = $qresponseLabel->getIdent();
$feedbackIdent = $answerIdent.'_fb';
//add answer specific feedbacks if not empty
$content = $node['comment'];
if (!empty($content)) {
$result = CcHelpers::processLinkedFiles($content,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$feedbackIdent);
PkgResourceDependencies::instance()->add($result[1]);
}
$answerlist[$answerIdent] = [$feedbackIdent, ($answerGradeFraction > 0)];
}
$this->answerlist = $answerlist;
}
public function onGenerateFeedbacks()
{
parent::onGenerateFeedbacks();
}
public function onGenerateResponseProcessing()
{
parent::onGenerateResponseProcessing();
/**
* General unconditional feedback must be added as a first respcondition
* without any condition and just displayfeedback (if exists).
*/
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle('General feedback');
$this->qresprocessing->addRespcondition($qrespcondition);
$qrespcondition->enableContinue();
}
}

View File

@@ -0,0 +1,217 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentQuestionMultichoice extends CcAssesmentQuestionProcBase
{
public function __construct($quiz, $questions, $manifest, $section, $question, $rootpath, $contextid, $outdir)
{
parent::__construct($quiz, $questions, $manifest, $section, $question, $rootpath, $contextid, $outdir);
$this->qtype = CcQtiProfiletype::MULTIPLE_CHOICE;
$correctAnswerNode = 0;
$questionScore = 0;
foreach ($question->answers as $answer) {
if ($answer['correct'] > 0) {
$correctAnswerNode = 1;
$this->correctAnswerNodeId = $answer['id'];
$questionScore = $answer['ponderation'];
break;
}
}
if (empty($correctAnswerNode)) {
throw new RuntimeException('No correct answer!');
}
//$this->total_grade_value = ($question_score).'.0000000';
$this->totalGradeValue = $questionScore;
}
public function onGenerateAnswers()
{
//add responses holder
$qresponseLid = new CcResponseLidtype();
$this->qresponseLid = $qresponseLid;
$this->qpresentation->setResponseLid($qresponseLid);
$qresponseChoice = new CcAssesmentRenderChoicetype();
$qresponseLid->setRenderChoice($qresponseChoice);
//Mark that question has only one correct answer -
//which applies for multiple choice and yes/no questions
$qresponseLid->setRcardinality(CcQtiValues::SINGLE);
//are we to shuffle the responses?
$shuffleAnswers = $this->quiz['random_answers'] > 0;
$qresponseChoice->enableShuffle($shuffleAnswers);
$answerlist = [];
$qaResponses = $this->questionNode->answers;
foreach ($qaResponses as $node) {
$answerContent = $node['answer'];
$id = $node['id'];
$result = CcHelpers::processLinkedFiles($answerContent,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
$qresponseLabel = CcAssesmentHelper::addAnswer($qresponseChoice,
$result[0],
CcQtiValues::HTMLTYPE);
PkgResourceDependencies::instance()->add($result[1]);
$answerIdent = $qresponseLabel->getIdent();
$feedbackIdent = $answerIdent.'_fb';
if (empty($this->correctAnswerIdent) && $id && $this->correctAnswerNodeId == $id) {
$this->correctAnswerIdent = $answerIdent;
}
//add answer specific feedbacks if not empty
$content = $node['comment'];
if (empty($content)) {
$content = '';
}
$result = CcHelpers::processLinkedFiles($content,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$feedbackIdent);
PkgResourceDependencies::instance()->add($result[1]);
$answerlist[$answerIdent] = $feedbackIdent;
}
$this->answerlist = $answerlist;
}
public function onGenerateFeedbacks()
{
parent::onGenerateFeedbacks();
//Question combined feedbacks
$correctQuestionFb = '';
$incorrectQuestionFb = '';
if (empty($correctQuestionFb)) {
//Hardcode some text for now
$correctQuestionFb = 'Well done!';
}
if (empty($incorrectQuestionFb)) {
//Hardcode some text for now
$incorrectQuestionFb = 'Better luck next time!';
}
$proc = ['correct_fb' => $correctQuestionFb, 'general_incorrect_fb' => $incorrectQuestionFb];
foreach ($proc as $ident => $content) {
if (empty($content)) {
continue;
}
$result = CcHelpers::processLinkedFiles($content,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$ident);
PkgResourceDependencies::instance()->add($result[1]);
if ($ident == 'correct_fb') {
$this->correctFeedbacks[] = $ident;
} else {
$this->incorrectFeedbacks[] = $ident;
}
}
}
public function onGenerateResponseProcessing()
{
parent::onGenerateResponseProcessing();
//respconditions
/**
* General unconditional feedback must be added as a first respcondition
* without any condition and just displayfeedback (if exists).
*/
if (!empty($this->generalFeedback)) {
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle('General feedback');
$this->qresprocessing->addRespcondition($qrespcondition);
$qrespcondition->enableContinue();
//define the condition for success
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
$qother = new CcAssignmentConditionvarOthertype();
$qconditionvar->setOther($qother);
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid('general_fb');
}
//success condition
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle('Correct');
$this->qresprocessing->addRespcondition($qrespcondition);
$qrespcondition->enableContinue(false);
$qsetvar = new CcAssignmentSetvartype(100);
$qrespcondition->addSetvar($qsetvar);
//define the condition for success
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
$qvarequal = new CcAssignmentConditionvarVarequaltype($this->correctAnswerIdent);
$qconditionvar->setVarequal($qvarequal);
$qvarequal->setRespident($this->qresponseLid->getIdent());
if (array_key_exists($this->correctAnswerIdent, $this->answerlist)) {
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($this->answerlist[$this->correctAnswerIdent]);
}
foreach ($this->correctFeedbacks as $ident) {
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($ident);
}
//rest of the conditions
foreach ($this->answerlist as $ident => $refid) {
if ($ident == $this->correctAnswerIdent) {
continue;
}
$qrespcondition = new CcAssesmentRespconditiontype();
$this->qresprocessing->addRespcondition($qrespcondition);
$qsetvar = new CcAssignmentSetvartype(0);
$qrespcondition->addSetvar($qsetvar);
//define the condition for fail
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
$qvarequal = new CcAssignmentConditionvarVarequaltype($ident);
$qconditionvar->setVarequal($qvarequal);
$qvarequal->setRespident($this->qresponseLid->getIdent());
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($refid);
foreach ($this->incorrectFeedbacks as $ident) {
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
$qdisplayfeedback->setLinkrefid($ident);
}
}
}
}

View File

@@ -0,0 +1,190 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentQuestionMultichoiceMultiresponse extends CcAssesmentQuestionProcBase
{
protected $correctAnswers = null;
public function __construct($quiz, $questions, $manifest, $section, $questionNode, $rootpath, $contextid, $outdir)
{
parent::__construct($quiz, $questions, $manifest, $section, $questionNode, $rootpath, $contextid, $outdir);
$this->qtype = CcQtiProfiletype::MULTIPLE_RESPONSE;
$correctAnswerNodes = [];
$questionScore = 0;
foreach ($questionNode->answers as $answer) {
if ($answer['correct'] > 0) {
$correctAnswerNodes[] = $answer;
$questionScore += $answer['ponderation'];
}
}
if (count($correctAnswerNodes) == 0) {
throw new RuntimeException('No correct answer!');
}
$this->correctAnswers = $correctAnswerNodes;
$this->totalGradeValue = $questionScore;
}
public function onGenerateAnswers()
{
//add responses holder
$qresponseLid = new CcResponseLidtype();
$this->qresponseLid = $qresponseLid;
$this->qpresentation->setResponseLid($qresponseLid);
$qresponseChoice = new CcAssesmentRenderChoicetype();
$qresponseLid->setRenderChoice($qresponseChoice);
//Mark that question has more than one correct answer
$qresponseLid->setRcardinality(CcQtiValues::MULTIPLE);
//are we to shuffle the responses?
$shuffleAnswers = $this->quiz['random_answers'] > 0;
$qresponseChoice->enableShuffle($shuffleAnswers);
$answerlist = [];
$qaResponses = $this->questionNode->answers;
foreach ($qaResponses as $node) {
$answerContent = $node['answer'];
$answerGradeFraction = $node['ponderation'];
$result = CcHelpers::processLinkedFiles($answerContent,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
$qresponseLabel = CcAssesmentHelper::addAnswer($qresponseChoice,
$result[0],
CcQtiValues::HTMLTYPE);
PkgResourceDependencies::instance()->add($result[1]);
$answerIdent = $qresponseLabel->getIdent();
$feedbackIdent = $answerIdent.'_fb';
//add answer specific feedbacks if not empty
$content = $node['comment'];
if (!empty($content)) {
$result = CcHelpers::processLinkedFiles($content,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$feedbackIdent);
PkgResourceDependencies::instance()->add($result[1]);
}
$answerlist[$answerIdent] = [$feedbackIdent, ($answerGradeFraction > 0)];
}
$this->answerlist = $answerlist;
}
public function onGenerateFeedbacks()
{
parent::onGenerateFeedbacks();
//Question combined feedbacks
$correctQuestionFb = '';
$incorrectQuestionFb = '';
if (empty($correctQuestionFb)) {
//Hardcode some text for now
$correctQuestionFb = 'Well done!';
}
if (empty($incorrectQuestionFb)) {
//Hardcode some text for now
$incorrectQuestionFb = 'Better luck next time!';
}
$proc = ['correct_fb' => $correctQuestionFb, 'incorrect_fb' => $incorrectQuestionFb];
foreach ($proc as $ident => $content) {
if (empty($content)) {
continue;
}
$result = CcHelpers::processLinkedFiles($content,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$ident);
PkgResourceDependencies::instance()->add($result[1]);
if ($ident == 'correct_fb') {
$this->correctFeedbacks[$ident] = $ident;
} else {
$this->incorrectFeedbacks[$ident] = $ident;
}
}
}
public function onGenerateResponseProcessing()
{
parent::onGenerateResponseProcessing();
//respconditions
/**
* General unconditional feedback must be added as a first respcondition
* without any condition and just displayfeedback (if exists).
*/
CcAssesmentHelper::addRespcondition($this->qresprocessing,
'General feedback',
$this->generalFeedback,
null,
true
);
$qrespcondition = new CcAssesmentRespconditiontype();
$qrespcondition->setTitle('Correct');
$this->qresprocessing->addRespcondition($qrespcondition);
$qrespcondition->enableContinue(false);
$qsetvar = new CcAssignmentSetvartype(100);
$qrespcondition->addSetvar($qsetvar);
//define the condition for success
$qconditionvar = new CcAssignmentConditionvar();
$qrespcondition->setConditionvar($qconditionvar);
//create root and condition
$qandcondition = new CcAssignmentConditionvarAndtype();
$qconditionvar->setAnd($qandcondition);
foreach ($this->answerlist as $ident => $refid) {
$qvarequal = new CcAssignmentConditionvarVarequaltype($ident);
$qvarequal->enableCase();
if ($refid[1]) {
$qandcondition->setVarequal($qvarequal);
} else {
$qandcondition->setNot($qvarequal);
}
$qvarequal->setRespident($this->qresponseLid->getIdent());
}
$qdisplayfeedback = new CcAssignmentDisplayfeedbacktype();
$qrespcondition->addDisplayfeedback($qdisplayfeedback);
$qdisplayfeedback->setFeedbacktype(CcQtiValues::RESPONSE);
//TODO: this needs to be fixed
reset($this->correctFeedbacks);
$ident = key($this->correctFeedbacks);
$qdisplayfeedback->setLinkrefid($ident);
//rest of the conditions
foreach ($this->answerlist as $ident => $refid) {
CcAssesmentHelper::addResponseCondition($this->qresprocessing,
'Incorrect feedback',
$refid[0],
$this->generalFeedback,
$this->qresponseLid->getIdent()
);
}
//Final element for incorrect feedback
reset($this->incorrectFeedbacks);
$ident = key($this->incorrectFeedbacks);
CcAssesmentHelper::addRespcondition($this->qresprocessing,
'Incorrect feedback',
$ident,
0
);
}
}

View File

@@ -0,0 +1,153 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentQuestionProcBase
{
protected $quiz = null;
protected $questions = null;
protected $manifest = null;
protected $section = null;
protected $questionNode = null;
protected $rootpath = null;
protected $contextid = null;
protected $outdir = null;
protected $qtype = null;
protected $qmetadata = null;
protected $qitem = null;
protected $qpresentation = null;
protected $qresponseLid = null;
protected $qresprocessing = null;
protected $correct_grade_value = null;
protected $correctAnswerNodeId = null;
protected $correctAnswerIdent = null;
protected $totalGradeValue = null;
protected $answerlist = null;
protected $generalFeedback = null;
protected $correctFeedbacks = [];
protected $incorrectFeedbacks = [];
/**
* @param XMLGenericDocument $questions
* @param cc_assesment_section $section
* @param object $question_node
* @param string $rootpath
* @param string $contextid
* @param string $outdir
*/
public function __construct(&$quiz, &$questions, CcManifest &$manifest, CcAssesmentSection &$section, &$questionNode, $rootpath, $contextid, $outdir)
{
$this->quiz = $quiz;
$this->questions = $questions;
$this->manifest = $manifest;
$this->section = $section;
$this->questionNode = $questionNode;
$this->rootpath = $rootpath;
$this->contextid = $contextid;
$this->outdir = $outdir;
$qitem = new CcAssesmentSectionItem();
$this->section->addItem($qitem);
$qitem->setTitle($questionNode->question);
$this->qitem = $qitem;
}
public function onGenerateMetadata()
{
if (empty($this->qmetadata)) {
$this->qmetadata = new CcQuestionMetadata($this->qtype);
//Get weighting value
$weightingValue = $this->questionNode->ponderation;
if ($weightingValue > 1) {
$this->qmetadata->setWeighting($weightingValue);
}
//Get category
if (!empty($this->questionNode->questionCategory)) {
$this->qmetadata->setCategory($this->questionNode->questionCategory);
}
$rts = new CcAssesmentItemmetadata();
$rts->addMetadata($this->qmetadata);
$this->qitem->setItemmetadata($rts);
}
}
public function onGeneratePresentation()
{
if (empty($this->qpresentation)) {
$qpresentation = new CcAssesmentPresentation();
$this->qitem->setPresentation($qpresentation);
//add question text
$qmaterial = new CcAssesmentMaterial();
$qmattext = new CcAssesmentMattext();
$questionText = $this->questionNode->question.'<br>'.$this->questionNode->description;
$result = CcHelpers::processLinkedFiles($questionText,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
$qmattext->setContent($result[0], CcQtiValues::HTMLTYPE);
$qmaterial->setMattext($qmattext);
$qpresentation->setMaterial($qmaterial);
$this->qpresentation = $qpresentation;
PkgResourceDependencies::instance()->add($result[1]);
}
}
public function onGenerateAnswers()
{
}
public function onGenerateFeedbacks()
{
$generalQuestionFeedback = '';
if (empty($generalQuestionFeedback)) {
return;
}
$name = 'general_fb';
//Add question general feedback - the one that should be always displayed
$result = CcHelpers::processLinkedFiles($generalQuestionFeedback,
$this->manifest,
$this->rootpath,
$this->contextid,
$this->outdir);
CcAssesmentHelper::addFeedback($this->qitem,
$result[0],
CcQtiValues::HTMLTYPE,
$name);
PkgResourceDependencies::instance()->add($result[1]);
$this->generalFeedback = $name;
}
public function onGenerateResponseProcessing()
{
$qresprocessing = new CcAssesmentResprocessingtype();
$this->qitem->addResprocessing($qresprocessing);
$qdecvar = new CcAssesmentDecvartype();
$qresprocessing->setDecvar($qdecvar);
//according to the Common Cartridge 1.1 Profile: Implementation document
//this should always be set to 0, 100 in case of question type that is not essay
$qdecvar->setLimits(0, 100);
$qdecvar->setVartype(CcQtiValues::DECIMAL);
$this->qresprocessing = $qresprocessing;
}
public function generate()
{
$this->onGenerateMetadata();
$this->onGeneratePresentation();
$this->onGenerateAnswers();
$this->onGenerateFeedbacks();
$this->onGenerateResponseProcessing();
}
}

View File

@@ -0,0 +1,78 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentRenderChoicetype extends CcQuestionMetadataBase
{
protected $materials = [];
protected $material_refs = [];
protected $responseLabels = [];
protected $flow_labels = [];
public function __construct()
{
$this->setSetting(CcQtiTags::SHUFFLE, CcQtiValues::NO);
$this->setSetting(CcQtiTags::MINNUMBER);
$this->setSetting(CcQtiTags::MAXNUMBER);
}
public function add_material(CcAssesmentMaterial $object)
{
$this->materials[] = $object;
}
public function add_material_ref(CcAssesmentResponseMatref $object)
{
$this->material_refs[] = $object;
}
public function addResponseLabel(CcAssesmentResponseLabeltype $object)
{
$this->responseLabels[] = $object;
}
public function add_flow_label($object)
{
$this->flow_labels[] = $object;
}
public function enableShuffle($value = true)
{
$this->enableSettingYesno(CcQtiTags::SHUFFLE, $value);
}
public function setLimits($min = null, $max = null)
{
$this->setSetting(CcQtiTags::MINNUMBER, $min);
$this->setSetting(CcQtiTags::MAXNUMBER, $max);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RENDER_CHOICE);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->materials)) {
foreach ($this->materials as $mattag) {
$mattag->generate($doc, $node, $namespace);
}
}
if (!empty($this->material_refs)) {
foreach ($this->material_refs as $matreftag) {
$matreftag->generate($doc, $node, $namespace);
}
}
if (!empty($this->responseLabels)) {
foreach ($this->responseLabels as $resplabtag) {
$resplabtag->generate($doc, $node, $namespace);
}
}
if (!empty($this->flow_labels)) {
foreach ($this->flow_labels as $flowlabtag) {
$flowlabtag->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,65 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentRenderEssaytype extends CcQuestionMetadataBase
{
protected $materials = [];
protected $material_refs = [];
protected $responseLabels = [];
protected $flow_labels = [];
public function __construct()
{
$this->setSetting(CcQtiTags::SHUFFLE, CcQtiValues::NO);
}
public function add_material(CcAssesmentMaterial $object)
{
$this->materials[] = $object;
}
public function add_material_ref(CcAssesmentResponseMatref $object)
{
$this->material_refs[] = $object;
}
public function addResponseLabel(CcAssesmentResponseLabeltype $object)
{
$this->responseLabels[] = $object;
}
public function add_flow_label($object)
{
$this->flow_labels[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RENDER_CHOICE);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->materials)) {
foreach ($this->materials as $mattag) {
$mattag->generate($doc, $node, $namespace);
}
}
if (!empty($this->material_refs)) {
foreach ($this->material_refs as $matreftag) {
$matreftag->generate($doc, $node, $namespace);
}
}
if (!empty($this->responseLabels)) {
foreach ($this->responseLabels as $resplabtag) {
$resplabtag->generate($doc, $node, $namespace);
}
}
if (!empty($this->flow_labels)) {
foreach ($this->flow_labels as $flowlabtag) {
$flowlabtag->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentRenderFibtype extends CcQuestionMetadataBase
{
protected $materials = [];
protected $material_refs = [];
protected $responseLabels = [];
protected $flow_labels = [];
public function __construct()
{
$this->setSetting(CcQtiTags::ENCODING);
$this->setSetting(CcQtiTags::CHARSET);
$this->setSetting(CcQtiTags::ROWS);
$this->setSetting(CcQtiTags::COLUMNS);
$this->setSetting(CcQtiTags::MAXCHARS);
$this->setSetting(CcQtiTags::MINNUMBER);
$this->setSetting(CcQtiTags::MAXNUMBER);
$this->setSetting(CcQtiTags::PROMPT, CcQtiValues::BOX);
$this->setSetting(CcQtiTags::FIBTYPE, CcQtiValues::STRING);
$this->qtype = CcQtiProfiletype::FIELD_ENTRY;
}
public function add_material(CcAssesmentMaterial $object)
{
$this->materials[] = $object;
}
public function add_material_ref(CcAssesmentResponseMatref $object)
{
$this->material_refs[] = $object;
}
public function addResponseLabel(CcAssesmentResponseLabeltype $object)
{
$this->responseLabels[] = $object;
}
public function add_flow_label($object)
{
$this->flow_labels[] = $object;
}
public function enableShuffle($value = true)
{
$this->enableSettingYesno(CcQtiTags::SHUFFLE, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RENDER_FIB);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->materials)) {
foreach ($this->materials as $mattag) {
$mattag->generate($doc, $node, $namespace);
}
}
if (!empty($this->material_refs)) {
foreach ($this->material_refs as $matreftag) {
$matreftag->generate($doc, $node, $namespace);
}
}
if (!empty($this->responseLabels)) {
foreach ($this->responseLabels as $resplabtag) {
$resplabtag->generate($doc, $node, $namespace);
}
}
if (!empty($this->flow_labels)) {
foreach ($this->flow_labels as $flowlabtag) {
$flowlabtag->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentRespconditiontype extends CcQuestionMetadataBase
{
protected $conditionvar = null;
protected $setvar = [];
protected $displayfeedback = [];
public function __construct()
{
$this->setSetting(CcQtiTags::TITLE);
$this->setSetting(CcQtiTags::CONTINUE_, CcQtiValues::NO);
}
public function setTitle($value)
{
$this->setSetting(CcQtiTags::TITLE, $value);
}
public function enableContinue($value = true)
{
$this->enableSettingYesno(CcQtiTags::CONTINUE_, $value);
}
public function setConditionvar(CcAssignmentConditionvar $object)
{
$this->conditionvar = $object;
}
public function addSetvar(CcAssignmentSetvartype $object)
{
$this->setvar[] = $object;
}
public function addDisplayfeedback(CcAssignmentDisplayfeedbacktype $object)
{
$this->displayfeedback[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RESPCONDITION);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->conditionvar)) {
$this->conditionvar->generate($doc, $node, $namespace);
}
if (!empty($this->setvar)) {
foreach ($this->setvar as $setvar) {
$setvar->generate($doc, $node, $namespace);
}
}
if (!empty($this->displayfeedback)) {
foreach ($this->displayfeedback as $displayfeedback) {
$displayfeedback->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,81 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentResponseLabeltype extends CcQuestionMetadataBase
{
protected $material = null;
protected $materialRef = null;
protected $flowMat = null;
public function __construct()
{
$this->setSetting(CcQtiTags::IDENT, CcHelpers::uuidgen('I_'));
$this->setSetting(CcQtiTags::LABELREFID);
$this->setSetting(CcQtiTags::RSHUFFLE);
$this->setSetting(CcQtiTags::MATCH_GROUP);
$this->setSetting(CcQtiTags::MATCH_MAX);
}
public function setIdent($value)
{
$this->setSetting(CcQtiTags::IDENT, $value);
}
public function getIdent()
{
return $this->getSetting(CcQtiTags::IDENT);
}
public function setLabelrefid($value)
{
$this->setSetting(CcQtiTags::LABELREFID, $value);
}
public function enableRshuffle($value = true)
{
$this->enableSettingYesno(CcQtiTags::RSHUFFLE, $value);
}
public function setMatchGroup($value)
{
$this->setSetting(CcQtiTags::MATCH_GROUP, $value);
}
public function setMatchMax($value)
{
$this->setSetting(CcQtiTags::MATCH_MAX, $value);
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function setMaterialRef(CcAssesmentResponseMatref $object)
{
$this->materialRef = $object;
}
public function setFlowMat(CcAssesmentFlowMattype $object)
{
$this->flowMat = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RESPONSE_LABEL);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->material)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->materialRef)) {
$this->materialRef->generate($doc, $node, $namespace);
}
if (!empty($this->flowMat)) {
$this->flowMat->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentResponseMatref extends CcAssesmentMatref
{
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::MATERIAL_REF);
$doc->appendNewAttributeNs($node, $namespace, CcQtiTags::LINKREFID, $this->linkref);
}
}

View File

@@ -0,0 +1,11 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentResponseStrtype extends CcResponseLidtype
{
public function __construct()
{
$rtt = parent::__construct();
$this->tagname = CcQtiTags::RESPONSE_STR;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentResprocessingtype extends CcQuestionMetadataBase
{
protected $decvar = null;
protected $respconditions = [];
public function setDecvar(CcAssesmentDecvartype $object)
{
$this->decvar = $object;
}
public function addRespcondition(CcAssesmentRespconditiontype $object)
{
$this->respconditions[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RESPROCESSING);
$outcomes = $doc->appendNewElementNs($node, $namespace, CcQtiTags::OUTCOMES);
if (!empty($this->decvar)) {
$this->decvar->generate($doc, $outcomes, $namespace);
}
if (!empty($this->respconditions)) {
foreach ($this->respconditions as $rcond) {
$rcond->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,20 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentRubricBase extends CcQuestionMetadataBase
{
protected $material = null;
public function setMaterial($object)
{
$this->material = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$rubric = $doc->appendNewElementNs($item, $namespace, CcQtiTags::RUBRIC);
if (!empty($this->material)) {
$this->material->generate($doc, $rubric, $namespace);
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentSection extends CcQuestionMetadataBase
{
/**
* @var array
*/
protected $items = [];
public function __construct()
{
$this->setSetting(CcQtiTags::IDENT, CcHelpers::uuidgen('I_'));
$this->setSetting(CcQtiTags::TITLE);
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML);
}
public function setIdent($value)
{
$this->setSetting(CcQtiTags::IDENT, $value);
}
public function setTitle($value)
{
$this->setSetting(CcQtiTags::TITLE, $value);
}
public function setLang($value)
{
$this->setSettingWns(CcQtiTags::XML_LANG, CcXmlNamespace::XML, $value);
}
public function addItem(CcAssesmentSectionItem $object)
{
$this->items[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::SECTION);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->items)) {
foreach ($this->items as $item) {
$item->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,56 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssesmentSectionItem extends CcAssesmentSection
{
protected $itemmetadata = null;
protected $presentation = null;
protected $resprocessing = [];
protected $itemfeedback = [];
public function setItemmetadata(CcAssesmentItemmetadata $object)
{
$this->itemmetadata = $object;
}
public function setPresentation(CcAssesmentPresentation $object)
{
$this->presentation = $object;
}
public function addResprocessing(CcAssesmentResprocessingtype $object)
{
$this->resprocessing[] = $object;
}
public function addItemfeedback(CcAssesmentItemfeedbacktype $object)
{
$this->itemfeedback[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::ITEM);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->itemmetadata)) {
$this->itemmetadata->generate($doc, $node, $namespace);
}
if (!empty($this->presentation)) {
$this->presentation->generate($doc, $node, $namespace);
}
if (!empty($this->resprocessing)) {
foreach ($this->resprocessing as $resprocessing) {
$resprocessing->generate($doc, $node, $namespace);
}
}
if (!empty($this->itemfeedback)) {
foreach ($this->itemfeedback as $itemfeedback) {
$itemfeedback->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentConditionvar extends CcQuestionMetadataBase
{
protected $and = null;
protected $other = null;
protected $varequal = [];
protected $varsubstring = null;
public function setAnd(CcAssignmentConditionvarAndtype $object)
{
$this->and = $object;
}
public function setOther(CcAssignmentConditionvarOthertype $object)
{
$this->other = $object;
}
public function setVarequal(CcAssignmentConditionvarVarequaltype $object)
{
$this->varequal[] = $object;
}
public function setVarsubstring(CcAssignmentConditionvarVarsubstringtype $object)
{
$this->varsubstring = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::CONDITIONVAR);
if (!empty($this->and)) {
$this->and->generate($doc, $node, $namespace);
}
if (!empty($this->other)) {
$this->other->generate($doc, $node, $namespace);
}
if (!empty($this->varequal)) {
foreach ($this->varequal as $varequal) {
$varequal->generate($doc, $node, $namespace);
}
}
if (!empty($this->varsubstring)) {
$this->varsubstring->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentConditionvarAndtype extends CcQuestionMetadataBase
{
protected $nots = [];
protected $varequals = [];
public function setNot(CcAssignmentConditionvarVarequaltype $object)
{
$this->nots[] = $object;
}
public function setVarequal(CcAssignmentConditionvarVarequaltype $object)
{
$this->varequals[] = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::AND_);
if (!empty($this->nots)) {
foreach ($this->nots as $notv) {
$not = $doc->appendNewElementNs($node, $namespace, CcQtiTags::NOT_);
$notv->generate($doc, $not, $namespace);
}
}
if (!empty($this->varequals)) {
foreach ($this->varequals as $varequal) {
$varequal->generate($doc, $node, $namespace);
}
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentConditionvarOthertype extends CcQuestionMetadataBase
{
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$doc->appendNewElementNs($item, $namespace, CcQtiTags::OTHER);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentConditionvarVarequaltype extends CcQuestionMetadataBase
{
protected $tagname = null;
protected $answerid = null;
public function __construct($value = null)
{
if (is_null($value)) {
throw new InvalidArgumentException('Must not pass null!');
}
$this->answerid = $value;
$this->setSetting(CcQtiTags::RESPIDENT);
$this->setSetting(CcQtiTags::CASE_);
$this->tagname = CcQtiTags::VAREQUAL;
}
public function setRespident($value)
{
$this->setSetting(CcQtiTags::RESPIDENT, $value);
}
public function enableCase($value = true)
{
$this->enableSettingYesno(CcQtiTags::CASE_, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, $this->tagname, $this->answerid);
$this->generateAttributes($doc, $node, $namespace);
}
}

View File

@@ -0,0 +1,11 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentConditionvarVarsubstringtype extends CcAssignmentConditionvarVarequaltype
{
public function __construct($value)
{
parent::__construct($value);
$this->tagname = CcQtiTags::VARSUBSTRING;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentDisplayfeedbacktype extends CcQuestionMetadataBase
{
public function __construct()
{
$this->setSetting(CcQtiTags::FEEDBACKTYPE);
$this->setSetting(CcQtiTags::LINKREFID);
}
public function setFeedbacktype($value)
{
$this->setSetting(CcQtiTags::FEEDBACKTYPE, $value);
}
public function setLinkrefid($value)
{
$this->setSetting(CcQtiTags::LINKREFID, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::DISPLAYFEEDBACK);
$this->generateAttributes($doc, $node, $namespace);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcAssignmentSetvartype extends CcQuestionMetadataBase
{
protected $tagvalue = null;
public function __construct($tagvalue = 100)
{
$this->setSetting(CcQtiTags::VARNAME, CcQtiValues::SCORE);
$this->setSetting(CcQtiTags::ACTION, CcQtiValues::SET);
$this->tagvalue = $tagvalue;
}
public function setVarname($value)
{
$this->setSetting(CcQtiTags::VARNAME, $value);
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, CcQtiTags::SETVAR, $this->tagvalue);
$this->generateAttributes($doc, $node, $namespace);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcQtiMetadata
{
// Assessment.
public const QMD_ASSESSMENTTYPE = 'qmd_assessmenttype';
public const QMD_SCORETYPE = 'qmd_scoretype';
public const QMD_FEEDBACKPERMITTED = 'qmd_feedbackpermitted';
public const QMD_HINTSPERMITTED = 'qmd_hintspermitted';
public const QMD_SOLUTIONSPERMITTED = 'qmd_solutionspermitted';
public const QMD_TIMELIMIT = 'qmd_timelimit';
public const CC_ALLOW_LATE_SUBMISSION = 'cc_allow_late_submission';
public const CC_MAXATTEMPTS = 'cc_maxattempts';
public const CC_PROFILE = 'cc_profile';
// Items.
public const CC_WEIGHTING = 'cc_weighting';
public const QMD_SCORINGPERMITTED = 'qmd_scoringpermitted';
public const QMD_COMPUTERSCORED = 'qmd_computerscored';
public const CC_QUESTION_CATEGORY = 'cc_question_category';
}

View File

@@ -0,0 +1,33 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcQtiProfiletype
{
public const MULTIPLE_CHOICE = 'cc.multiple_choice.v0p1';
public const MULTIPLE_RESPONSE = 'cc.multiple_response.v0p1';
public const TRUE_FALSE = 'cc.true_false.v0p1';
public const FIELD_ENTRY = 'cc.fib.v0p1';
public const PATTERN_MATCH = 'cc.pattern_match.v0p1';
public const ESSAY = 'cc.essay.v0p1';
/**
* validates a profile value.
*
* @param string $value
*
* @return bool
*/
public static function valid($value)
{
static $verificationValues = [
self::ESSAY,
self::FIELD_ENTRY,
self::MULTIPLE_CHOICE,
self::MULTIPLE_RESPONSE,
self::PATTERN_MATCH,
self::TRUE_FALSE,
];
return in_array($value, $verificationValues);
}
}

View File

@@ -0,0 +1,88 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcQtiTags
{
public const QUESTESTINTEROP = 'questestinterop';
public const ASSESSMENT = 'assessment';
public const QTIMETADATA = 'qtimetadata';
public const QTIMETADATAFIELD = 'qtimetadatafield';
public const FIELDLABEL = 'fieldlabel';
public const FIELDENTRY = 'fieldentry';
public const SECTION = 'section';
public const IDENT = 'ident';
public const ITEM = 'item';
public const TITLE = 'title';
public const ITEMMETADATA = 'itemmetadata';
public const PRESENTATION = 'presentation';
public const MATERIAL = 'material';
public const MATTEXT = 'mattext';
public const MATREF = 'matref';
public const MATBREAK = 'matbreak';
public const TEXTTYPE = 'texttype';
public const RESPONSE_LID = 'response_lid';
public const RENDER_CHOICE = 'render_choice';
public const RESPONSE_LABEL = 'response_label';
public const RESPROCESSING = 'resprocessing';
public const OUTCOMES = 'outcomes';
public const DECVAR = 'decvar';
public const RESPCONDITION = 'respcondition';
public const CONDITIONVAR = 'conditionvar';
public const OTHER = 'other';
public const DISPLAYFEEDBACK = 'displayfeedback';
public const MAXVALUE = 'maxvalue';
public const MINVALUE = 'minvalue';
public const VARNAME = 'varname';
public const VARTYPE = 'vartype';
public const CONTINUE_ = 'continue';
public const FEEDBACKTYPE = 'feedbacktype';
public const LINKREFID = 'linkrefid';
public const VAREQUAL = 'varequal';
public const RESPIDENT = 'respident';
public const ITEMFEEDBACK = 'itemfeedback';
public const FLOW_MAT = 'flow_mat';
public const RCARDINALITY = 'rcardinality';
public const CHARSET = 'charset';
public const LABEL = 'label';
public const URI = 'uri';
public const WIDTH = 'width';
public const HEIGHT = 'height';
public const X0 = 'x0';
public const Y0 = 'y0';
public const XML_LANG = 'lang';
public const XML_SPACE = 'space';
public const RUBRIC = 'rubric';
public const ALTMATERIAL = 'altmaterial';
public const PRESENTATION_MATERIAL = 'presentation_material';
public const T_CLASS = 'class';
public const MATERIAL_REF = 'material_ref';
public const RTIMING = 'rtiming';
public const RENDER_FIB = 'render_fib';
public const SHUFFLE = 'shuffle';
public const MINNUMBER = 'minnumber';
public const MAXNUMBER = 'maxnumber';
public const ENCODING = 'encoding';
public const MAXCHARS = 'maxchars';
public const PROMPT = 'prompt';
public const FIBTYPE = 'fibtype';
public const ROWS = 'rows';
public const COLUMNS = 'columns';
public const LABELREFID = 'labelrefid';
public const RSHUFFLE = 'rshuffle';
public const MATCH_GROUP = 'match_group';
public const MATCH_MAX = 'match_max';
public const FLOW = 'flow';
public const RESPONSE_STR = 'response_str';
public const FLOW_LABEL = 'flow_label';
public const SETVAR = 'setvar';
public const ACTION = 'action';
public const AND_ = 'and';
public const NOT_ = 'not';
public const CASE_ = 'case';
public const VARSUBSTRING = 'varsubstring';
public const HINT = 'hint';
public const SOLUTION = 'solution';
public const FEEDBACKSTYLE = 'feedbackstyle';
public const SOLUTIONMATERIAL = 'solutionmaterial';
public const HINTMATERIAL = 'hintmaterial';
}

View File

@@ -0,0 +1,31 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcQtiValues
{
public const EXAM_PROFILE = 'cc.exam.v0p1';
public const YES = 'Yes';
public const NO = 'No';
public const RESPONSE = 'Response';
public const SOLUTION = 'Solution';
public const HINT = 'Hint';
public const EXAMINATION = 'Examination';
public const PERCENTAGE = 'Percentage';
public const UNLIMITED = 'unlimited';
public const SINGLE = 'Single';
public const MULTIPLE = 'Multiple';
public const ORDERER = 'Ordered';
public const ASTERISK = 'Asterisk';
public const BOX = 'Box';
public const DASHLINE = 'Dashline';
public const UNDERLINE = 'Underline';
public const DECIMAL = 'Decimal';
public const INTEGER = 'Integer';
public const SCIENTIFIC = 'Scientific';
public const STRING = 'String';
public const SCORE = 'SCORE';
public const SET = 'Set';
public const COMPLETE = 'Complete';
public const TEXTTYPE = 'text/plain';
public const HTMLTYPE = 'text/html';
}

View File

@@ -0,0 +1,44 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcQuestionMetadata extends CcQuestionMetadataBase
{
/**
* Constructs metadata.
*
* @param string $profile
*
* @throws InvalidArgumentException
*/
public function __construct($profile)
{
if (!CcQtiProfiletype::valid($profile)) {
throw new InvalidArgumentException('Invalid profile type!');
}
$this->setSetting(CcQtiMetadata::CC_PROFILE, $profile);
$this->setSetting(CcQtiMetadata::CC_QUESTION_CATEGORY);
$this->setSetting(CcQtiMetadata::CC_WEIGHTING);
$this->setSetting(CcQtiMetadata::QMD_SCORINGPERMITTED);
$this->setSetting(CcQtiMetadata::QMD_COMPUTERSCORED);
}
public function setCategory($value)
{
$this->setSetting(CcQtiMetadata::CC_QUESTION_CATEGORY, $value);
}
public function setWeighting($value)
{
$this->setSetting(CcQtiMetadata::CC_WEIGHTING, $value);
}
public function enableScoringpermitted($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::QMD_SCORINGPERMITTED, $value);
}
public function enableComputerscored($value = true)
{
$this->enableSettingYesno(CcQtiMetadata::QMD_COMPUTERSCORED, $value);
}
}

View File

@@ -0,0 +1,86 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcQuestionMetadataBase
{
protected $metadata = [];
/**
* @param string $namespace
*/
public function generateAttributes(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
foreach ($this->metadata as $attribute => $value) {
if (!is_null($value)) {
if (!is_array($value)) {
$doc->appendNewAttributeNs($item, $namespace, $attribute, $value);
} else {
$ns = key($value);
$nval = current($value);
if (!is_null($nval)) {
$doc->appendNewAttributeNs($item, $ns, $attribute, $nval);
}
}
}
}
}
/**
* @param string $namespace
*/
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$qtimetadata = $doc->appendNewElementNs($item, $namespace, CcQtiTags::QTIMETADATA);
foreach ($this->metadata as $label => $entry) {
if (!is_null($entry)) {
$qtimetadatafield = $doc->appendNewElementNs($qtimetadata, $namespace, CcQtiTags::QTIMETADATAFIELD);
$doc->appendNewElementNs($qtimetadatafield, $namespace, CcQtiTags::FIELDLABEL, $label);
$doc->appendNewElementNs($qtimetadatafield, $namespace, CcQtiTags::FIELDENTRY, $entry);
}
}
}
/**
* @param string $setting
* @param mixed $value
*/
protected function setSetting($setting, $value = null)
{
$this->metadata[$setting] = $value;
}
/**
* @param string $setting
*
* @return mixed
*/
protected function getSetting($setting)
{
$result = null;
if (array_key_exists($setting, $this->metadata)) {
$result = $this->metadata[$setting];
}
return $result;
}
/**
* @param string $setting
* @param string $namespace
* @param string $value
*/
protected function setSettingWns($setting, $namespace, $value = null)
{
$this->metadata[$setting] = [$namespace => $value];
}
/**
* @param string $setting
* @param bool $value
*/
protected function enableSettingYesno($setting, $value = true)
{
$svalue = $value ? CcQtiValues::YES : CcQtiValues::NO;
$this->setSetting($setting, $svalue);
}
}

View File

@@ -0,0 +1,81 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
class CcResponseLidtype extends CcQuestionMetadataBase
{
protected $tagname = null;
protected $material = null;
protected $materialRef = null;
protected $renderChoice = null;
protected $renderFib = null;
public function __construct()
{
$this->setSetting(CcQtiTags::RCARDINALITY, CcQtiValues::SINGLE);
$this->setSetting(CcQtiTags::RTIMING);
$this->setSetting(CcQtiTags::IDENT, CcHelpers::uuidgen('I_'));
$this->tagname = CcQtiTags::RESPONSE_LID;
}
public function setRcardinality($value)
{
$this->setSetting(CcQtiTags::RCARDINALITY, $value);
}
public function enableRtiming($value = true)
{
$this->enableSettingYesno(CcQtiTags::RTIMING, $value);
}
public function setIdent($value)
{
$this->setSetting(CcQtiTags::IDENT, $value);
}
public function getIdent()
{
return $this->getSetting(CcQtiTags::IDENT);
}
public function setMaterialRef(CcAssesmentResponseMatref $object)
{
$this->materialRef = $object;
}
public function setMaterial(CcAssesmentMaterial $object)
{
$this->material = $object;
}
public function setRenderChoice(CcAssesmentRenderChoicetype $object)
{
$this->renderChoice = $object;
}
public function setRenderFib(CcAssesmentRenderFibtype $object)
{
$this->renderFib = $object;
}
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace)
{
$node = $doc->appendNewElementNs($item, $namespace, $this->tagname);
$this->generateAttributes($doc, $node, $namespace);
if (!empty($this->material) && empty($this->materialRef)) {
$this->material->generate($doc, $node, $namespace);
}
if (!empty($this->materialRef) && empty($this->material)) {
$this->materialRef->generate($doc, $node, $namespace);
}
if (!empty($this->renderChoice) && empty($this->renderFib)) {
$this->renderChoice->generate($doc, $node, $namespace);
}
if (!empty($this->renderFib) && empty($this->renderChoice)) {
$this->renderFib->generate($doc, $node, $namespace);
}
}
}

View File

@@ -0,0 +1,7 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/cc_asssesment.php under GNU/GPL license */
abstract class CcXmlNamespace
{
public const XML = 'http://www.w3.org/XML/1998/namespace';
}

View File

@@ -0,0 +1,238 @@
<?php
/* Source: https://github.com/moodle/moodle/blob/MOODLE_310_STABLE/backup/cc/cc_lib/gral_lib/ccdependencyparser.php under GNU/GPL license */
/**
* Converts \ Directory separator to the / more suitable for URL.
*
* @param string $path
*/
function toUrlPath(&$path)
{
for ($count = 0; $count < strlen($path); $count++) {
$chr = $path[$count];
if (($chr == '\\')) {
$path[$count] = '/';
}
}
}
/**
* Returns relative path from two directories with full path.
*
* @param string $path1
* @param string $path2
*
* @return string
*/
function pathDiff($path1, $path2)
{
toUrlPath($path1);
toUrlPath($path2);
$result = "";
$bl2 = strlen($path2);
$a = strpos($path1, $path2);
if ($a !== false) {
$result = trim(substr($path1, $bl2 + $a), '/');
}
return $result;
}
/**
* Converts direcotry separator in given path to / to validate in CC
* Value is passed byref hence variable itself is changed.
*
* @param string $path
*/
function toNativePath(&$path)
{
for ($count = 0; $count < strlen($path); $count++) {
$chr = $path[$count];
if (($chr == '\\') || ($chr == '/')) {
$path[$count] = '/';
}
}
}
/**
* Function strips url part from css link.
*
* @param string $path
* @param string $rootDir
*
* @return string
*/
function stripUrl($path, $rootDir = '')
{
$result = $path;
if (is_string($path) && ($path != '')) {
$start = strpos($path, '(') + 1;
$length = strpos($path, ')') - $start;
$rut = $rootDir.substr($path, $start, $length);
$result = fullPath($rut, '/');
}
return $result;
}
/**
* Get full path.
*
* @param string $path
* @param string $dirsep
*
* @return false|string
*/
function fullPath($path, $dirsep = DIRECTORY_SEPARATOR)
{
$token = '/\$(?:IMS|1EdTech)[-_]CC[-_]FILEBASE\$/';
$path = preg_replace($token, '', $path);
if (is_string($path) && ($path != '')) {
$sep = $dirsep;
$dotDir = '.';
$upDir = '..';
$length = strlen($path);
$rtemp = trim($path);
$start = strrpos($path, $sep);
$canContinue = ($start !== false);
$result = $canContinue ? '' : $path;
$rcount = 0;
while ($canContinue) {
$dirPart = ($start !== false) ? substr($rtemp, $start + 1, $length - $start) : $rtemp;
$canContinue = ($dirPart !== false);
if ($canContinue) {
if ($dirPart != $dotDir) {
if ($dirPart == $upDir) {
$rcount++;
} else {
if ($rcount > 0) {
$rcount--;
} else {
$result = ($result == '') ? $dirPart : $dirPart.$sep.$result;
}
}
}
$rtemp = substr($path, 0, $start);
$start = strrpos($rtemp, $sep);
$canContinue = (($start !== false) || (strlen($rtemp) > 0));
}
}
}
return $result;
}
/**
* validates URL.
*
* @param string $url
*
* @return bool
*/
function isUrl($url)
{
$result = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED) !== false;
return $result;
}
/**
* Gets the dependency files of the $fname file.
*
* @param string $manifestroot
* @param string $fname
* @param string $folder
* @param array $filenames
*/
function getDepFiles($manifestroot, $fname, $folder, &$filenames)
{
static $types = ['xhtml' => true, 'html' => true, 'htm' => true];
$extension = strtolower(trim(pathinfo($fname, PATHINFO_EXTENSION)));
$filenames = [];
if (isset($types[$extension])) {
$dcx = new XMLGenericDocument();
$filename = $manifestroot.$folder.$fname;
if (!file_exists($filename)) {
$filename = $manifestroot.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.$fname;
}
if (file_exists($filename)) {
$res = $dcx->loadHTMLFile($filename);
if ($res) {
getDepFilesHTML($manifestroot, $fname, $filenames, $dcx, $folder);
}
}
}
}
/**
* Gets the dependency of .html of the $fname file.
*
* @param string $manifestroot
* @param string $fname
* @param string $filenames
* @param string $dcx
* @param string $folder
*/
function getDepFilesHTML($manifestroot, $fname, &$filenames, &$dcx, $folder)
{
$dcx->resetXpath();
$nlist = $dcx->nodeList("//img/@src | //link/@href | //script/@src | //a[not(starts-with(@href,'#'))]/@href");
$cssObjArray = [];
foreach ($nlist as $nl) {
$item = $folder.$nl->nodeValue;
$path_parts = pathinfo($item);
$fname = $path_parts['basename'];
$ext = array_key_exists('extension', $path_parts) ? $path_parts['extension'] : '';
if (!isUrl($folder.$nl->nodeValue) && !isUrl($nl->nodeValue)) {
$path = $folder.$nl->nodeValue;
$file = fullPath($path, "/");
toNativePath($file);
if (file_exists($manifestroot.DIRECTORY_SEPARATOR.$file)) {
$filenames[$file] = $file;
}
}
if ($ext == 'css') {
$css = new CssParser();
$css->parse($dcx->filePath().$nl->nodeValue);
$cssObjArray[$item] = $css;
}
}
$nlist = $dcx->nodeList("//*/@class");
foreach ($nlist as $nl) {
$item = $folder.$nl->nodeValue;
foreach ($cssObjArray as $csskey => $cssobj) {
$bimg = $cssobj->get($item, "background-image");
$limg = $cssobj->get($item, "list-style-image");
$npath = pathinfo($csskey);
if ((!empty($bimg)) && ($bimg != 'none')) {
$value = stripUrl($bimg, $npath['dirname'].'/');
$filenames[$value] = $value;
} elseif ((!empty($limg)) && ($limg != 'none')) {
$value = stripUrl($limg, $npath['dirname'].'/');
$filenames[$value] = $value;
}
}
}
$elemsToCheck = ["body", "p", "ul", "h4", "a", "th"];
$doWeHaveIt = [];
foreach ($elemsToCheck as $elem) {
$doWeHaveIt[$elem] = ($dcx->nodeList("//".$elem)->length > 0);
}
foreach ($elemsToCheck as $elem) {
if ($doWeHaveIt[$elem]) {
foreach ($cssObjArray as $csskey => $cssobj) {
$sb = $cssobj->get($elem, "background-image");
$sbl = $cssobj->get($elem, "list-style-image");
$npath = pathinfo($csskey);
if ((!empty($sb)) && ($sb != 'none')) {
$value = stripUrl($sb, $npath['dirname'].'/');
$filenames[$value] = $value;
} elseif ((!empty($sbl)) && ($sbl != 'none')) {
$value = stripUrl($sbl, $npath['dirname'].'/');
$filenames[$value] = $value;
}
}
}
}
}

View File

@@ -0,0 +1,328 @@
<?php
/* For licensing terms, see /license.txt */
abstract class CcHelpers
{
/**
* Checks extension of the supplied filename.
*
* @param string $filename
*/
public static function isHtml($filename)
{
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
return in_array($extension, ['htm', 'html']);
}
/**
* Generates unique identifier.
*
* @param string $prefix
* @param string $suffix
*
* @return string
*/
public static function uuidgen($prefix = '', $suffix = '', $uppercase = true)
{
$uuid = trim(sprintf('%s%04x%04x%s', $prefix, mt_rand(0, 65535), mt_rand(0, 65535), $suffix));
$result = $uppercase ? strtoupper($uuid) : strtolower($uuid);
return $result;
}
/**
* Creates new folder with random name.
*
* @param string $where
* @param string $prefix
* @param string $suffix
*
* @return mixed - directory short name or false in case of failure
*/
public static function randomdir($where, $prefix = '', $suffix = '')
{
$permDirs = api_get_permissions_for_new_directories();
$dirname = false;
$randomname = self::uuidgen($prefix, $suffix, false);
$newdirname = $where.DIRECTORY_SEPARATOR.$randomname;
if (mkdir($newdirname)) {
chmod($newdirname, $permDirs);
$dirname = $randomname;
}
return $dirname;
}
public static function buildQuery($attributes, $search)
{
$result = '';
foreach ($attributes as $attribute) {
if ($result != '') {
$result .= ' | ';
}
$result .= "//*[starts-with(@{$attribute},'{$search}')]/@{$attribute}";
}
return $result;
}
public static function processEmbeddedFiles(XMLGenericDocument &$doc, $attributes, $search, $customslash = null)
{
$result = [];
$query = self::buildQuery($attributes, $search);
$list = $doc->nodeList($query);
foreach ($list as $filelink) {
// Prepare the return value of just the filepath from within the course's document folder
$rvalue = str_replace($search, '', $filelink->nodeValue);
if (!empty($customslash)) {
$rvalue = str_replace($customslash, '/', $rvalue);
}
$result[] = rawurldecode($rvalue);
}
return array_unique($result);
}
/**
* Get list of embedded files.
*
* @return multitype:mixed
*/
public static function embeddedFiles(string $html, string $courseDir = null)
{
$result = [];
$doc = new XMLGenericDocument();
$doc->doc->validateOnParse = false;
$doc->doc->strictErrorChecking = false;
if (!empty($html) && $doc->loadHTML($html)) {
$attributes = ['src', 'href'];
$result1 = [];
if (!empty($courseDir) && is_dir(api_get_path(SYS_COURSE_PATH).$courseDir)) {
// get a list of files within the course's "document" directory (only those... for now)
$result1 = self::processEmbeddedFiles($doc, $attributes, '/courses/'.$courseDir.'/document/');
}
$result2 = [];
//$result2 = self::processEmbeddedFiles($doc, $attributes, '/app/upload/users/');
$result = array_merge($result1, $result2);
}
return $result;
}
/**
* Return an array of static media dependencies found in a given document file or a document and its neighbours in the same folder.
*
* @param $packageroot
* @param $contextid
* @param $folder
* @param $docfilepath
*
* @return array
*/
public static function embeddedMapping($packageroot, $contextid = null, $folder = null, $docfilepath = null)
{
if (isset($folder)) {
$files = array_diff(scandir($folder), ['.', '..']);
} else {
$folder = dirname($docfilepath);
$files[] = basename($docfilepath);
}
$basePath = api_get_path(SYS_APP_PATH);
$depfiles = [];
foreach ($files as $file) {
$mainfile = 1;
$filename = $file;
$filepath = DIRECTORY_SEPARATOR;
$source = '';
$author = '';
$license = '';
$hashedname = '';
$hashpart = '';
$location = $folder.DIRECTORY_SEPARATOR.$file;
$type = mime_content_type($basePath.$location);
$depfiles[$filepath.$filename] = [$location,
($mainfile == 1),
strtolower(str_replace(' ', '_', $filename)),
$type,
$source,
$author,
$license,
strtolower(str_replace(' ', '_', $filepath)), ];
}
return $depfiles;
}
public static function addFiles(CcIManifest &$manifest, $packageroot, $outdir, $allinone = true, $folder = null, $docfilepath = null)
{
$permDirs = api_get_permissions_for_new_directories();
$files = CcHelpers::embeddedMapping($packageroot, null, $folder, $docfilepath);
$basePath = api_get_path(SYS_APP_PATH);
$rdir = $allinone ? new CcResourceLocation($outdir) : null;
foreach ($files as $virtual => $values) {
$clean_filename = $values[2];
if (!$allinone) {
$rdir = new CcResourceLocation($outdir);
}
$rtp = $rdir->fullpath().$values[7].$clean_filename;
//Are there any relative virtual directories?
//let us try to recreate them
$justdir = $rdir->fullpath(false).$values[7];
if (!file_exists($justdir)) {
if (!mkdir($justdir, $permDirs, true)) {
throw new RuntimeException('Unable to create directories!');
}
}
$source = $values[0];
if (is_dir($basePath.$source)) {
continue;
}
if (!copy($basePath.$source, $rtp)) {
throw new RuntimeException('Unable to copy files from '.$basePath.$source.' to '.$rtp.'!');
}
$resource = new CcResources($rdir->rootdir(),
$values[7].$clean_filename,
$rdir->dirname(false));
$res = $manifest->addResource($resource, null, CcVersion13::WEBCONTENT);
PkgStaticResources::instance()->add($virtual,
$res[0],
$rdir->dirname(false).$values[7].$clean_filename,
$values[1],
$resource);
}
PkgStaticResources::instance()->finished = true;
}
/**
* Excerpt from IMS CC 1.1 overview :
* No spaces in filenames, directory and file references should
* employ all lowercase or all uppercase - no mixed case.
*
* @param string $packageroot
* @param int $contextid
* @param string $outdir
* @param bool $allinone
*
* @throws RuntimeException
*/
public static function handleStaticContent(CcIManifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true, $folder = null)
{
self::addFiles($manifest, $packageroot, $outdir, $allinone, $folder);
return PkgStaticResources::instance()->getValues();
}
public static function handleResourceContent(CcIManifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true, $docfilepath = null)
{
$result = [];
self::addFiles($manifest, $packageroot, $outdir, $allinone, null, $docfilepath);
$files = self::embeddedMapping($packageroot, $contextid, null, $docfilepath);
$rootnode = null;
$rootvals = null;
$depfiles = [];
$depres = [];
$flocation = null;
foreach ($files as $virtual => $values) {
$vals = PkgStaticResources::instance()->getIdentifier($virtual);
$resource = $vals[3];
$identifier = $resource->identifier;
$flocation = $vals[1];
if ($values[1]) {
$rootnode = $resource;
$rootvals = $flocation;
continue;
}
$depres[] = $identifier;
$depfiles[] = $vals[1];
$result[$virtual] = [$identifier, $flocation, false];
}
if (!empty($rootnode)) {
$rootnode->files = array_merge($rootnode->files, $depfiles);
$result[$virtual] = [$rootnode->identifier, $rootvals, true];
}
return $result;
}
/**
* Detect embedded files in the given HTML string.
*
* @param string $content The HTML string content
* @param CcIManifest $manifest Manifest object (usually empty at this point) that will be filled
* @param $packageroot
* @param $contextid
* @param $outdir
* @param $webcontent
*
* @return array
*/
public static function processLinkedFiles(
string $content,
CcIManifest &$manifest,
$packageroot,
$contextid,
$outdir,
$webcontent = false
) {
// Detect all embedded files
// copy all files in the cc package stripping any spaces and using only lowercase letters
// add those files as resources of the type webcontent to the manifest
// replace the links to the resource using $1Edtech-CC-FILEBASE$ and their new locations
// cc_resource has array of files and array of dependencies
// most likely we would need to add all files as independent resources and than
// attach them all as dependencies to the forum tag.
$courseDir = $internalCourseDocumentsPath = null;
$courseInfo = api_get_course_info();
$replaceprefix = '$1EdTech-CC-FILEBASE$';
$tokenSyntax = api_get_configuration_value('commoncartridge_path_token');
if (!empty($tokenSyntax)) {
$replaceprefix = $tokenSyntax;
}
if (!empty($courseInfo)) {
$courseDir = $courseInfo['directory'];
$internalCourseDocumentsPath = '/courses/'.$courseDir.'/document';
}
$lfiles = self::embeddedFiles($content, $courseDir);
$text = $content;
$deps = [];
if (!empty($lfiles)) {
foreach ($lfiles as $lfile) {
$lfile = DIRECTORY_SEPARATOR.$lfile; // results of handleResourceContent() come prefixed by DIRECTORY_SEPARATOR
$files = self::handleResourceContent(
$manifest,
$packageroot,
$contextid,
$outdir,
true,
$internalCourseDocumentsPath.$lfile
);
$bfile = DIRECTORY_SEPARATOR.basename($lfile);
if (isset($files[$bfile])) {
$filename = str_replace('%2F', '/', rawurlencode($lfile));
$content = str_replace($internalCourseDocumentsPath.$filename,
$replaceprefix.'../'.$files[$bfile][1],
$content);
$deps[] = $files[$bfile][0];
}
}
$text = $content;
}
return [$text, $deps];
}
}

View File

@@ -0,0 +1,77 @@
<?php
/* For licensing terms, see /license.txt */
final class CcResourceLocation
{
/**
* Root directory.
*
* @var string
*/
private $rootdir = null;
/**
* new directory.
*
* @var string
*/
private $dir = null;
/**
* Full precalculated path.
*
* @var string
*/
private $fullpath = null;
/**
* ctor.
*
* @param string $rootdir - path to the containing directory
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function __construct($rootdir)
{
$rdir = realpath($rootdir);
if (empty($rdir)) {
throw new InvalidArgumentException('Invalid path!');
}
$dir = CcHelpers::randomdir($rdir, 'i_');
if ($dir === false) {
throw new RuntimeException('Unable to create directory!');
}
$this->rootdir = $rdir;
$this->dir = $dir;
$this->fullpath = $rdir.DIRECTORY_SEPARATOR.$dir;
}
/**
* Newly created directory.
*
* @return string
*/
public function dirname($endseparator = false)
{
return $this->dir.($endseparator ? '/' : '');
}
/**
* Full path to the new directory.
*
* @return string
*/
public function fullpath($endseparator = false)
{
return $this->fullpath.($endseparator ? DIRECTORY_SEPARATOR : '');
}
/**
* Returns containing dir.
*
* @return string
*/
public function rootdir($endseparator = false)
{
return $this->rootdir.($endseparator ? DIRECTORY_SEPARATOR : '');
}
}

View File

@@ -0,0 +1,39 @@
<?php
/* For licensing terms, see /license.txt */
class PkgResourceDependencies
{
private $values = [];
private static $instance = null;
/**
* @return PkgResourceDependencies
*/
public static function instance()
{
if (empty(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c();
}
return self::$instance;
}
public function add(array $deps)
{
$this->values = array_merge($this->values, $deps);
}
public function reset()
{
$this->values = [];
}
/**
* @return array
*/
public function getDeps()
{
return $this->values;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/* For licensing terms, see /license.txt */
class PkgStaticResources
{
public $finished = false;
private $values = [];
private static $instance = null;
/**
* @return PkgStaticResources
*/
public static function instance()
{
if (empty(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c();
}
return self::$instance;
}
/**
* add new element.
*
* @param string $identifier
* @param string $file
* @param bool $main
*/
public function add($key, $identifier, $file, $main, $node = null)
{
$this->values[$key] = [$identifier, $file, $main, $node];
}
/**
* @return array
*/
public function getValues()
{
return $this->values;
}
public function getIdentifier($location)
{
return isset($this->values[$location]) ? $this->values[$location] : false;
}
public function reset()
{
$this->values = [];
$this->finished = false;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/* For licensing terms, see /license.txt */
class Cc1p3Convert extends CcBase
{
public const CC_TYPE_FORUM = 'imsdt_xmlv1p3';
public const CC_TYPE_QUIZ = 'imsqti_xmlv1p3/imscc_xmlv1p3/assessment';
public const CC_TYPE_QUESTION_BANK = 'imsqti_xmlv1p3/imscc_xmlv1p3/question-bank';
public const CC_TYPE_WEBLINK = 'imswl_xmlv1p3';
public const CC_TYPE_ASSOCIATED_CONTENT = 'associatedcontent/imscc_xmlv1p3/learning-application-resource';
public const CC_TYPE_WEBCONTENT = 'webcontent';
public const CC_TYPE_BASICLTI = 'imsbasiclti_xmlv1p3';
public static $namespaces = ['imscc' => 'http://www.imsglobal.org/xsd/imsccv1p3/imscp_v1p1',
'lomimscc' => 'http://ltsc.ieee.org/xsd/imsccv1p3/LOM/manifest',
'lom' => 'http://ltsc.ieee.org/xsd/imsccv1p3/LOM/resource',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'cc' => 'http://www.imsglobal.org/xsd/imsccv1p3/imsccauth_v1p1', ];
public static $restypes = ['associatedcontent/imscc_xmlv1p3/learning-application-resource', 'webcontent'];
public static $forumns = ['dt' => 'http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3'];
public static $quizns = ['xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2'];
public static $resourcens = ['wl' => 'http://www.imsglobal.org/xsd/imsccv1p3/imswl_v1p3'];
public static $basicltins = [
'xmlns' => 'http://www.imsglobal.org/xsd/imslticc_v1p0',
'blti' => 'http://www.imsglobal.org/xsd/imsbasiclti_v1p0',
'lticm' => 'http://www.imsglobal.org/xsd/imslticm_v1p0',
'lticp' => 'http://www.imsglobal.org/xsd/imslticp_v1p0',
];
public function __construct($path_to_manifest)
{
parent::__construct($path_to_manifest);
}
/**
* Scan the imsmanifest.xml structure to find elements to import to documents, links, forums, quizzes.
*/
public function generateImportData(): void
{
$countInstances = 0;
$xpath = static::newxPath(static::$manifest, static::$namespaces);
// Scan for detached resources of type 'webcontent'
$resources = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@type="'.static::CC_TYPE_WEBCONTENT.'"]');
$this->createInstances($resources, 0, $countInstances);
// Scan for organization items or resources that are tests (question banks)
$items = $xpath->query('/imscc:manifest/imscc:organizations/imscc:organization/imscc:item | /imscc:manifest/imscc:resources/imscc:resource[@type="'.static::CC_TYPE_QUESTION_BANK.'"]');
$this->createInstances($items, 0, $countInstances);
$resources = new Cc13Resource();
$forums = new Cc13Forum();
$quiz = new Cc13Quiz();
// Get the embedded XML files describing resources to import
$documentValues = $resources->generateData('document');
$linkValues = $resources->generateData('link');
$forumValues = $forums->generateData();
$quizValues = $quiz->generateData();
if (!empty($forums) or !empty($quizValues) or !empty($documentValues)) {
$courseInfo = api_get_course_info();
$sessionId = api_get_session_id();
$groupId = api_get_group_id();
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document';
create_unexisting_directory(
$courseInfo,
api_get_user_id(),
$sessionId,
$groupId,
null,
$documentPath,
'/commoncartridge',
'Common Cartridge folder',
0
);
}
// Import the resources, by type
if (!empty($forums)) {
$saved = $forums->storeForums($forumValues);
}
if (!empty($quizValues)) {
$saved = $quiz->storeQuizzes($quizValues);
}
if (!empty($documentValues)) {
$saved = $resources->storeDocuments($documentValues, static::$pathToManifestFolder);
}
if (!empty($linkValues)) {
$saved = $resources->storeLinks($linkValues);
}
}
}

View File

@@ -0,0 +1,99 @@
<?php
/* For licensing terms, see /license.txt */
class Imscc13Import
{
public const FORMAT_IMSCC13 = 'imscc13';
public function log($message, $level, $a = null, $depth = null, $display = false)
{
error_log("(imscc1) $message , level : $level , extra info: $a, message depth : $depth");
}
public static function detectFormat($filepath)
{
$manifest = Cc1p3Convert::getManifest($filepath);
if (file_exists($manifest)) {
// Looks promising, lets load some information.
$handle = fopen($manifest, 'r');
$xmlSnippet = fread($handle, 1024);
fclose($handle);
// Check if it has the required strings.
$xmlSnippet = strtolower($xmlSnippet);
$xmlSnippet = preg_replace('/\s*/m', '', $xmlSnippet);
$xmlSnippet = str_replace("'", '', $xmlSnippet);
$xmlSnippet = str_replace('"', '', $xmlSnippet);
$search_string = "xmlns=http://www.imsglobal.org/xsd/imsccv1p3/imscp_v1p1";
if (strpos($xmlSnippet, $search_string) !== false) {
return self::FORMAT_IMSCC13;
}
}
return null;
}
/**
* Read the imsmanifest.xml file in the app/cache/imsccImport temp folder.
*
* @param $filepath
*
* @return void
*/
public function execute($filepath)
{
$manifest = Cc1p3Convert::getManifest($filepath);
if (empty($manifest)) {
throw new RuntimeException('No Manifest detected!');
}
$validator = new ManifestValidator('schemas13');
if (!$validator->validate($manifest)) {
throw new RuntimeException('validation error(s): '.PHP_EOL.ErrorMessages::instance());
}
$cc113Convert = new Cc1p3Convert($manifest);
if ($cc113Convert->isAuth()) {
throw new RuntimeException('protected_cc_not_supported');
}
$cc113Convert->generateImportData();
}
/**
* Unzip a file into the specified directory. Throws a RuntimeException
* if the extraction failed.
*/
public static function unzip($file, $to = 'cache/zip')
{
@ini_set('memory_limit', '256M');
if (!is_dir($to)) {
mkdir($to);
chmod($to, 0777);
}
if (class_exists('ZipArchive')) {
// use ZipArchive
$zip = new ZipArchive();
$res = $zip->open($file);
if ($res === true) {
$zip->extractTo($to);
$zip->close();
} else {
throw new RuntimeException('Could not open zip file [ZipArchive].');
}
} else {
// use PclZip
$zip = new PclZip($file);
if ($zip->extract(PCLZIP_OPT_PATH, $to) === 0) {
throw new RuntimeException('Could not extract zip file [PclZip].');
}
}
return true;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More