Files
Chamilo/main/common_cartridge/import/src/base/CcBase.php
2025-04-10 12:49:05 +02:00

380 lines
12 KiB
PHP

<?php
/* For licensing terms, see /license.txt */
class 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_WEBCONTENT = 'webcontent';
public const CC_TYPE_ASSOCIATED_CONTENT = 'associatedcontent/imscc_xmlv1p3/learning-application-resource';
public const CC_TYPE_EMPTY = '';
public static $restypes = ['associatedcontent/imscc_xmlv1p0/learning-application-resource', 'webcontent'];
public static $forumns = ['dt' => 'http://www.imsglobal.org/xsd/imsdt_v1p0'];
public static $quizns = ['xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2'];
public static $resourcens = ['wl' => 'http://www.imsglobal.org/xsd/imswl_v1p0'];
public static $instances = [];
public static $manifest;
public static $pathToManifestFolder;
public static $namespaces = ['imscc' => 'http://www.imsglobal.org/xsd/imscc/imscp_v1p1',
'lomimscc' => 'http://ltsc.ieee.org/xsd/imscc/LOM',
'lom' => 'http://ltsc.ieee.org/xsd/LOM',
'voc' => 'http://ltsc.ieee.org/xsd/LOM/vocab',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'cc' => 'http://www.imsglobal.org/xsd/imsccauth_v1p0', ];
public function __construct($path_to_manifest)
{
static::$manifest = new DOMDocument();
static::$manifest->validateOnParse = false;
static::$pathToManifestFolder = dirname($path_to_manifest);
static::logAction('Proccess start');
static::logAction('Load the manifest file: '.$path_to_manifest);
if (!static::$manifest->load($path_to_manifest, LIBXML_NONET)) {
static::logAction('Cannot load the manifest file: '.$path_to_manifest, true);
}
}
/**
* @return array
*/
public static function getquizns()
{
return static::$quizns;
}
/**
* @return array
*/
public static function getforumns()
{
return static::$forumns;
}
/**
* @return array
*/
public static function getresourcens()
{
return static::$resourcens;
}
/**
* Find the imsmanifest.xml file inside the given folder and return its path.
*
* @param string $folder Full path name of the folder in which we expect to find imsmanifest.xml
*
* @return false|string
*/
public static function getManifest(string $folder)
{
if (!is_dir($folder)) {
return false;
}
// Before iterate over directories, try to find one manifest at top level
if (file_exists($folder.'/imsmanifest.xml')) {
return $folder.'/imsmanifest.xml';
}
$result = false;
try {
$dirIter = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::KEY_AS_PATHNAME);
$recIter = new RecursiveIteratorIterator($dirIter, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($recIter as $info) {
if ($info->isFile() && ($info->getFilename() == 'imsmanifest.xml')) {
$result = $info->getPathname();
break;
}
}
} catch (Exception $e) {
}
return $result;
}
public function isAuth()
{
$xpath = static::newxPath(static::$manifest, static::$namespaces);
$count_auth = $xpath->evaluate('count(/imscc:manifest/cc:authorizations)');
if ($count_auth > 0) {
$response = true;
} else {
$response = false;
}
return $response;
}
public function getNodesByCriteria($key, $value)
{
$response = [];
if (array_key_exists('index', static::$instances)) {
foreach (static::$instances['index'] as $item) {
if ($item[$key] == $value) {
$response[] = $item;
}
}
}
return $response;
}
public function countInstances($type)
{
$quantity = 0;
if (array_key_exists('index', static::$instances)) {
if (static::$instances['index'] && $type) {
foreach (static::$instances['index'] as $instance) {
if (!empty($instance['tool_type'])) {
$types[] = $instance['tool_type'];
}
}
$quantityInstances = array_count_values($types);
$quantity = array_key_exists($type, $quantityInstances) ? $quantityInstances[$type] : 0;
}
}
return $quantity;
}
public function getItemCcType($identifier)
{
$xpath = static::newxPath(static::$manifest, static::$namespaces);
$nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]/@type');
if ($nodes && !empty($nodes->item(0)->nodeValue)) {
return $nodes->item(0)->nodeValue;
} else {
return '';
}
}
public function getItemHref($identifier)
{
$xpath = static::newxPath(static::$manifest, static::$namespaces);
$nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]/imscc:file/@href');
if ($nodes && !empty($nodes->item(0)->nodeValue)) {
return $nodes->item(0)->nodeValue;
} else {
return '';
}
}
public static function newxPath(DOMDocument $manifest, $namespaces = '')
{
$xpath = new DOMXPath($manifest);
if (!empty($namespaces)) {
foreach ($namespaces as $prefix => $ns) {
if (!$xpath->registerNamespace($prefix, $ns)) {
static::logAction('Cannot register the namespace: '.$prefix.':'.$ns, true);
}
}
}
return $xpath;
}
public static function logFile()
{
return static::$pathToManifestFolder.DIRECTORY_SEPARATOR.'cc_import.log';
}
public static function logAction($text, $criticalError = false)
{
$full_message = strtoupper(date("j/n/Y g:i:s a"))." - ".$text."\r";
file_put_contents(static::logFile(), $full_message, FILE_APPEND);
if ($criticalError) {
static::criticalError($text);
}
}
public function convertToToolType($ccType)
{
$type = TYPE_UNKNOWN;
if ($ccType == static::CC_TYPE_FORUM) {
$type = TOOL_TYPE_FORUM;
}
if ($ccType == static::CC_TYPE_QUIZ) {
$type = TOOL_TYPE_QUIZ;
}
if ($ccType == static::CC_TYPE_WEBLINK) {
$type = TOOL_TYPE_WEBLINK;
}
if ($ccType == static::CC_TYPE_WEBCONTENT) {
$type = TOOL_TYPE_DOCUMENT;
}
return $type;
}
protected function getMetadata($section, $key)
{
$xpath = static::newxPath(static::$manifest, static::$namespaces);
$metadata = $xpath->query('/imscc:manifest/imscc:metadata/lomimscc:lom/lomimscc:'.$section.'/lomimscc:'.$key.'/lomimscc:string');
$value = !empty($metadata->item(0)->nodeValue) ? $metadata->item(0)->nodeValue : '';
return $value;
}
/**
* Is activity visible or not.
*
* @param string $identifier
*
* @return number
*/
protected function getModuleVisible($identifier)
{
//Should item be hidden or not
$mod_visible = 1;
if (!empty($identifier)) {
$xpath = static::newxPath(static::$manifest, static::$namespaces);
$query = '/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]';
$query .= '//lom:intendedEndUserRole/voc:vocabulary/lom:value';
$intendeduserrole = $xpath->query($query);
if (!empty($intendeduserrole) && ($intendeduserrole->length > 0)) {
$role = trim($intendeduserrole->item(0)->nodeValue);
if (strcasecmp('Instructor', $role) == 0) {
$mod_visible = 0;
}
}
}
return $mod_visible;
}
protected function createInstances($items, $level = 0, &$array_index = 0, $index_root = 0)
{
$level++;
$i = 1;
if ($items) {
$xpath = self::newxPath(static::$manifest, static::$namespaces);
foreach ($items as $item) {
$array_index++;
$title = $path = $tool_type = $identifierref = '';
if ($item->nodeName == 'item') {
if ($item->hasAttribute('identifierref')) {
$identifierref = $item->getAttribute('identifierref');
}
$titles = $xpath->query('imscc:title', $item);
if ($titles->length > 0) {
$title = $titles->item(0)->nodeValue;
}
$ccType = $this->getItemCcType($identifierref);
$tool_type = $this->convertToToolType($ccType);
//Fix the label issue - MDL-33523
if (empty($identifierref) && empty($title)) {
$tool_type = TYPE_UNKNOWN;
}
} elseif ($item->nodeName == 'resource') {
$identifierref = $xpath->query('@identifier', $item);
$identifierref = !empty($identifierref->item(0)->nodeValue) ? $identifierref->item(0)->nodeValue : '';
$ccType = $this->getItemCcType($identifierref);
$tool_type = $this->convertToToolType($ccType);
if (self::CC_TYPE_WEBCONTENT == $ccType) {
$path = $this->getItemHref($identifierref);
$title = basename($path);
} else { // A resource but not a file... we assume it's a quiz bank and its assigned identifier is irrelevant to its name
$title = 'Quiz Bank '.($this->countInstances($tool_type) + 1);
}
}
if ($level == ROOT_DEEP) {
$index_root = $array_index;
}
static::$instances['index'][$array_index] = [
'common_cartridge_type' => $ccType,
'tool_type' => $tool_type,
'title' => $title ? $title : '',
'root_parent' => $index_root,
'index' => $array_index,
'deep' => $level,
'instance' => $this->countInstances($tool_type),
'resource_identifier' => $identifierref,
];
static::$instances['instances'][$tool_type][] = [
'title' => $title,
'instance' => static::$instances['index'][$array_index]['instance'],
'common_cartridge_type' => $ccType,
'resource_identifier' => $identifierref,
'deep' => $level,
'src' => $path,
];
$more_items = $xpath->query('imscc:item', $item);
if ($more_items->length > 0) {
$this->createInstances($more_items, $level, $array_index, $index_root);
}
$i++;
}
}
}
protected static function criticalError($text)
{
$path_to_log = static::logFile();
echo '
<p>
<hr />A critical error has been found!
<p>'.$text.'</p>
<p>
The process has been stopped. Please see the <a href="'.$path_to_log.'">log file</a> for more information.</p>
<p>Log: '.$path_to_log.'</p>
<hr />
</p>
';
exit();
}
protected function createCourseCode($title)
{
//Making sure that text of the short name does not go over the DB limit.
//and leaving the space to add additional characters by the platform
$code = substr(strtoupper(str_replace(' ', '', trim($title))), 0, 94);
return $code;
}
}