LP: Fix scorm import

pull/3984/head
Julio 4 years ago
parent f87f9cdfc4
commit 4fd6236531
  1. 23
      public/main/lp/learnpath.class.php
  2. 9
      public/main/lp/lp_content.php
  3. 6
      public/main/lp/lp_upload.php
  4. 1
      public/main/lp/lp_view.php
  5. 215
      public/main/lp/scorm.class.php
  6. 11
      public/main/lp/scormItem.class.php
  7. 7
      public/main/lp/scormOrganization.class.php
  8. 47
      src/CoreBundle/Repository/AssetRepository.php
  9. 25
      tests/CoreBundle/Repository/AssetRepositoryTest.php

@ -121,7 +121,7 @@ class learnpath
$this->encoding = api_get_system_encoding(); $this->encoding = api_get_system_encoding();
$lp_id = 0; $lp_id = 0;
if (null !== $entity) { if (null !== $entity) {
$lp_id = (int) $entity->getIid(); $lp_id = $entity->getIid();
} }
$course_info = empty($course_info) ? api_get_course_info() : $course_info; $course_info = empty($course_info) ? api_get_course_info() : $course_info;
$course_id = (int) $course_info['real_id']; $course_id = (int) $course_info['real_id'];
@ -130,7 +130,7 @@ class learnpath
if (empty($lp_id) || empty($course_id)) { if (empty($lp_id) || empty($course_id)) {
$this->error = "Parameter is empty: LpId:'$lp_id', courseId: '$lp_id'"; $this->error = "Parameter is empty: LpId:'$lp_id', courseId: '$lp_id'";
} else { } else {
$this->entity = $entity; //$this->entity = $entity;
$this->lp_id = $lp_id; $this->lp_id = $lp_id;
$this->type = $entity->getLpType(); $this->type = $entity->getLpType();
$this->name = stripslashes($entity->getName()); $this->name = stripslashes($entity->getName());
@ -158,7 +158,7 @@ class learnpath
if ($entity->hasAsset()) { if ($entity->hasAsset()) {
$asset = $entity->getAsset(); $asset = $entity->getAsset();
$this->scormUrl = Container::getAssetRepository()->getAssetUrl($asset).'/'; $this->scormUrl = Container::getAssetRepository()->getAssetUrl($asset).'/'.$entity->getPath().'/';
} }
$this->accumulateScormTime = $entity->getAccumulateWorkTime(); $this->accumulateScormTime = $entity->getAccumulateWorkTime();
@ -235,7 +235,7 @@ class learnpath
'displayOrder' => Criteria::ASC, 'displayOrder' => Criteria::ASC,
] ]
); );
$items = $this->entity->getItems()->matching($criteria); $items = $entity->getItems()->matching($criteria);
$lp_item_id_list = []; $lp_item_id_list = [];
foreach ($items as $item) { foreach ($items as $item) {
$itemId = $item->getIid(); $itemId = $item->getIid();
@ -309,7 +309,6 @@ class learnpath
while ($row = Database:: fetch_array($res)) { while ($row = Database:: fetch_array($res)) {
$status_list[$row['lp_item_id']] = $row['status']; $status_list[$row['lp_item_id']] = $row['status'];
} }
//echo '<pre>'; var_dump($this->items); echo '</pre>';
foreach ($lp_item_id_list as $item_id) { foreach ($lp_item_id_list as $item_id) {
if (isset($status_list[$item_id])) { if (isset($status_list[$item_id])) {
$status = $status_list[$item_id]; $status = $status_list[$item_id];
@ -354,7 +353,7 @@ class learnpath
} }
} }
$this->ordered_items = self::get_flat_ordered_items_list($this->entity, null); $this->ordered_items = self::get_flat_ordered_items_list($entity, null);
$this->max_ordered_items = 0; $this->max_ordered_items = 0;
foreach ($this->ordered_items as $index => $dummy) { foreach ($this->ordered_items as $index => $dummy) {
if ($index > $this->max_ordered_items && !empty($dummy)) { if ($index > $this->max_ordered_items && !empty($dummy)) {
@ -453,7 +452,7 @@ class learnpath
->setTitle($title) ->setTitle($title)
->setDescription($description) ->setDescription($description)
->setPath($id) ->setPath($id)
->setLp($this->entity) ->setLp(api_get_lp_entity($this->get_id()))
->setItemType($type) ->setItemType($type)
->setMaxScore($max_score) ->setMaxScore($max_score)
->setMaxTimeAllowed($max_time_allowed) ->setMaxTimeAllowed($max_time_allowed)
@ -4671,7 +4670,7 @@ class learnpath
return $return; return $return;
} }
public function getBuildTree($noWrapper = false, $dropElement = false) public function getBuildTree($noWrapper = false, $dropElement = false): string
{ {
$mainUrl = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq(); $mainUrl = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq();
@ -4778,7 +4777,7 @@ class learnpath
); );
$url = $mainUrl.'&view=build&id='.$itemId.'&lp_id='.$lpId; $url = $mainUrl.'&view=build&id='.$itemId.'&lp_id='.$lpId;
$preRequisitiesIcon = Display::url( $preRequisitesIcon = Display::url(
Display::return_icon( Display::return_icon(
'accept.png', 'accept.png',
get_lang('Prerequisites'), get_lang('Prerequisites'),
@ -4841,7 +4840,7 @@ class learnpath
'div', 'div',
"<div class=\"btn-group btn-group-sm\"> "<div class=\"btn-group btn-group-sm\">
$editIcon $editIcon
$preRequisitiesIcon $preRequisitesIcon
$orderIcons $orderIcons
$deleteIcon $deleteIcon
</div>", </div>",
@ -4859,6 +4858,7 @@ class learnpath
; ;
}, },
]; ];
$tree = $lpItemRepo->childrenHierarchy($itemRoot, false, $options); $tree = $lpItemRepo->childrenHierarchy($itemRoot, false, $options);
if (empty($tree) && $dropElement) { if (empty($tree) && $dropElement) {
@ -6439,7 +6439,8 @@ class learnpath
public function display_lp_prerequisites_list(FormValidator $form) public function display_lp_prerequisites_list(FormValidator $form)
{ {
$lp_id = $this->lp_id; $lp_id = $this->lp_id;
$prerequisiteId = $this->entity->getPrerequisite(); $lp = api_get_lp_entity($lp_id);
$prerequisiteId = $lp->getPrerequisite();
$repo = Container::getLpRepository(); $repo = Container::getLpRepository();
$qb = $repo->findAllByCourse(api_get_course_entity(), api_get_session_entity()); $qb = $repo->findAllByCourse(api_get_course_entity(), api_get_session_entity());

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */ /* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CLp;
use ChamiloSession as Session; use ChamiloSession as Session;
/** /**
@ -52,7 +53,7 @@ if ($dir) {
$src = 'blank.php'; $src = 'blank.php';
} else { } else {
switch ($lpType) { switch ($lpType) {
case 1: case CLp::LP_TYPE:
$learnPath->stop_previous_item(); $learnPath->stop_previous_item();
$prerequisiteCheck = $learnPath->prerequisites_match($lpItemId); $prerequisiteCheck = $learnPath->prerequisites_match($lpItemId);
if (true === $prerequisiteCheck) { if (true === $prerequisiteCheck) {
@ -76,7 +77,7 @@ if ($dir) {
} }
$src = 'blank.php?'.api_get_cidreq().'&error=prerequisites&prerequisite_message='.Security::remove_XSS($learnPath->error); $src = 'blank.php?'.api_get_cidreq().'&error=prerequisites&prerequisite_message='.Security::remove_XSS($learnPath->error);
break; break;
case 2: case CLp::SCORM_TYPE:
$learnPath->stop_previous_item(); $learnPath->stop_previous_item();
$prerequisiteCheck = $learnPath->prerequisites_match($lpItemId); $prerequisiteCheck = $learnPath->prerequisites_match($lpItemId);
@ -87,7 +88,7 @@ if ($dir) {
$src = 'blank.php?'.api_get_cidreq().'&error=prerequisites&prerequisite_message='.Security::remove_XSS($learnPath->error); $src = 'blank.php?'.api_get_cidreq().'&error=prerequisites&prerequisite_message='.Security::remove_XSS($learnPath->error);
} }
break; break;
case 3: case CLp::AICC_TYPE:
// save old if asset // save old if asset
$learnPath->stop_previous_item(); // save status manually if asset $learnPath->stop_previous_item(); // save status manually if asset
$prerequisiteCheck = $learnPath->prerequisites_match($lpItemId); $prerequisiteCheck = $learnPath->prerequisites_match($lpItemId);
@ -98,8 +99,6 @@ if ($dir) {
$src = 'blank.php'; $src = 'blank.php';
} }
break; break;
case 4:
break;
} }
} }

@ -90,7 +90,7 @@ if (isset($_POST) && $is_error) {
); );
if (!empty($scorm->manifestToString)) { if (!empty($scorm->manifestToString)) {
$scorm->parse_manifest(); $scorm->parse_manifest();
$lp = $scorm->import_manifest(api_get_course_id(), $_REQUEST['use_max_score']); $lp = $scorm->import_manifest(api_get_course_int_id(), $_REQUEST['use_max_score']);
if ($lp) { if ($lp) {
$lp $lp
->setContentLocal($proximity) ->setContentLocal($proximity)
@ -172,8 +172,8 @@ if (isset($_POST) && $is_error) {
$entity = $oScorm->getEntity(); $entity = $oScorm->getEntity();
$manifest = $oScorm->import_local_package($s, $current_dir); $manifest = $oScorm->import_local_package($s, $current_dir);
if (!empty($manifest)) { if (!empty($manifest)) {
$oScorm->parse_manifest($manifest); $oScorm->parse_manifest();
$oScorm->import_manifest(api_get_course_id(), $_REQUEST['use_max_score']); $oScorm->import_manifest(api_get_course_int_id(), $_REQUEST['use_max_score']);
Display::addFlash(Display::return_message(get_lang('File upload succeeded!'))); Display::addFlash(Display::return_message(get_lang('File upload succeeded!')));
} }

@ -244,6 +244,7 @@ if (!isset($src)) {
$oLP->stop_previous_item(); // save status manually if asset $oLP->stop_previous_item(); // save status manually if asset
$htmlHeadXtra[] = '<script src="scorm_api.php"></script>'; $htmlHeadXtra[] = '<script src="scorm_api.php"></script>';
$preReqCheck = $oLP->prerequisites_match($lp_item_id); $preReqCheck = $oLP->prerequisites_match($lp_item_id);
if (true === $preReqCheck) { if (true === $preReqCheck) {
$src = $oLP->get_link('http', $lp_item_id, $get_toc_list); $src = $oLP->get_link('http', $lp_item_id, $get_toc_list);
$oLP->start_current_item(); // starts time counter manually if asset $oLP->start_current_item(); // starts time counter manually if asset

@ -220,94 +220,11 @@ class scorm extends learnpath
} }
// End parsing using PHP5 DOMXML methods. // End parsing using PHP5 DOMXML methods.
} else { } else {
if ($this->debug > 1) { $this->set_error_msg("File could not be read");
error_log('Could not open/read file '.$file);
}
$this->set_error_msg("File $file could not be read");
return null; return null;
} }
// @todo implement learnpath_fix_xerte_template
$fixTemplate = api_get_configuration_value('learnpath_fix_xerte_template');
$proxyPath = api_get_configuration_value('learnpath_proxy_url');
/*if ($fixTemplate && !empty($proxyPath)) {
// Check organisations:
if (isset($this->manifest['organizations'])) {
foreach ($this->manifest['organizations'] as $data) {
if (false !== strpos(strtolower($data), 'xerte')) {
// Check if template.xml exists:
$templatePath = str_replace('imsmanifest.xml', 'template.xml', $file);
if (file_exists($templatePath) && is_file($templatePath)) {
$templateContent = file_get_contents($templatePath);
$find = [
'href="www.',
'href="https://',
'href="http://',
'url="www.',
'pdfs/download.php?',
];
$replace = [
'href="http://www.',
'target = "_blank" href="'.$proxyPath.'?type=link&src=https://',
'target = "_blank" href="'.$proxyPath.'?type=link&src=http://',
'url="http://www.',
'pdfs/download.php&',
];
$templateContent = str_replace($find, $replace, $templateContent);
file_put_contents($templatePath, $templateContent);
}
// Fix link generation:
$linkPath = str_replace('imsmanifest.xml', 'models_html5/links.html', $file);
if (file_exists($linkPath) && is_file($linkPath)) {
$linkContent = file_get_contents($linkPath);
$find = [
':this.getAttribute("url")',
];
$replace = [
':"'.$proxyPath.'?type=link&src=" + this.getAttribute("url")',
];
$linkContent = str_replace($find, $replace, $linkContent);
file_put_contents($linkPath, $linkContent);
}
// Fix iframe generation
$framePath = str_replace('imsmanifest.xml', 'models_html5/embedDiv.html', $file);
if (file_exists($framePath) && is_file($framePath)) {
$content = file_get_contents($framePath);
$find = [
'$iFrameHolder.html(iFrameTag);',
];
$replace = [
'iFrameTag = \'<a target ="_blank" href="'.$proxyPath.'?type=link&src=\'+ pageSrc + \'">Open website. <img width="16px" src="'.Display::returnIconPath('link-external.png').'"></a>\'; $iFrameHolder.html(iFrameTag); ',
];
$content = str_replace($find, $replace, $content);
file_put_contents($framePath, $content);
}
// Fix new window generation
$newWindowPath = str_replace('imsmanifest.xml', 'models_html5/newWindow.html', $file);
if (file_exists($newWindowPath) && is_file($newWindowPath)) {
$content = file_get_contents($newWindowPath);
$find = [
'var src = x_currentPageXML',
];
$replace = [
'var src = "'.$proxyPath.'?type=link&src=" + x_currentPageXML',
];
$content = str_replace($find, $replace, $content);
file_put_contents($newWindowPath, $content);
}
}
}
}
}*/
// TODO: Close the DOM handler. // TODO: Close the DOM handler.
return $this->manifest; return $this->manifest;
} }
@ -315,30 +232,29 @@ class scorm extends learnpath
/** /**
* Import the scorm object (as a result from the parse_manifest function) into the database structure. * Import the scorm object (as a result from the parse_manifest function) into the database structure.
* *
* @param string $courseCode * @param int $courseId
* @param int $userMaxScore * @param int $userMaxScore
* @param int $sessionId * @param int $sessionId
* *
* @return CLp|null * @return CLp|null
*/ */
public function import_manifest($courseCode, $userMaxScore = 1, $sessionId = 0) public function import_manifest($courseId, $userMaxScore = 1, $sessionId = 0)
{ {
if ($this->debug > 0) { if ($this->debug > 0) {
error_log('Entered import_manifest('.$courseCode.')', 0); error_log('Entered import_manifest('.$courseId.')', 0);
} }
$courseInfo = api_get_course_info($courseCode);
$courseId = $courseInfo['real_id']; $course = api_get_course_entity($courseId);
// Get table names. // Get table names.
$lpTable = Database::get_course_table(TABLE_LP_MAIN);
$lpItemTable = Database::get_course_table(TABLE_LP_ITEM); $lpItemTable = Database::get_course_table(TABLE_LP_ITEM);
$userMaxScore = (int) $userMaxScore; $userMaxScore = (int) $userMaxScore;
$sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
$repo = Container::getLpRepository(); $repo = Container::getLpRepository();
$em = Database::getManager(); $lpItemRepo = Container::getLpItemRepository();
$lp = null; $lp = null;
foreach ($this->organizations as $id => $dummy) { foreach ($this->organizations as $id => $dummy) {
/** @var scormOrganization $oOrganization */
$oOrganization = &$this->organizations[$id]; $oOrganization = &$this->organizations[$id];
// Prepare and execute insert queries: // Prepare and execute insert queries:
// -for learnpath // -for learnpath
@ -353,11 +269,10 @@ class scorm extends learnpath
}*/ }*/
$dsp = 1; $dsp = 1;
$courseEntity = api_get_course_entity($courseInfo['real_id']); $name = $oOrganization->get_name();
$myname = api_utf8_decode($oOrganization->get_name());
$lp = (new CLp()) $lp = (new CLp())
->setLpType(CLp::SCORM_TYPE) ->setLpType(CLp::SCORM_TYPE)
->setName($myname) ->setName($name)
->setRef($oOrganization->get_ref()) ->setRef($oOrganization->get_ref())
->setPath($this->subdir) ->setPath($this->subdir)
->setDefaultEncoding($this->manifest_encoding) ->setDefaultEncoding($this->manifest_encoding)
@ -365,11 +280,11 @@ class scorm extends learnpath
->setDisplayOrder($dsp) ->setDisplayOrder($dsp)
->setUseMaxScore($userMaxScore) ->setUseMaxScore($userMaxScore)
->setAsset($this->asset) ->setAsset($this->asset)
->setParent($courseEntity) ->setParent($course)
->addCourseLink($courseEntity, api_get_session_entity()) ->addCourseLink($course, api_get_session_entity($sessionId))
; ;
$repo->create($lp); $repo->createLp($lp);
$lp_id = $lp->getIid(); $lp_id = $lp->getIid();
@ -425,13 +340,13 @@ class scorm extends learnpath
if (empty($title)) { if (empty($title)) {
$title = get_lang('Untitled'); $title = get_lang('Untitled');
} }
$parentEntity = null;
$parentEntity = $lpItemRepo->getRootItem($lp_id);
if (!empty($parent)) { if (!empty($parent)) {
$parentEntity = $em->getRepository(CLpItem::class)->find($parent); $parentEntity = $lpItemRepo->find($parent);
} }
$lpItem = new CLpItem(); $lpItem = (new CLpItem())
$lpItem
->setTitle($title) ->setTitle($title)
->setItemType($type) ->setItemType($type)
->setRef($item['identifier']) ->setRef($item['identifier'])
@ -439,10 +354,10 @@ class scorm extends learnpath
->setMinScore(0) ->setMinScore(0)
->setMaxScore($max_score) ->setMaxScore($max_score)
->setParent($parentEntity) ->setParent($parentEntity)
->setPreviousItemId($previous) //->setPreviousItemId($previous)
->setNextItemId(0) //->setNextItemId(0)
->setPrerequisite($item['prerequisites']) ->setPrerequisite($item['prerequisites'])
->setDisplayOrder($item['rel_order']) //->setDisplayOrder($item['rel_order'])
->setLaunchData($item['datafromlms']) ->setLaunchData($item['datafromlms'])
->setParameters($item['parameters']) ->setParameters($item['parameters'])
->setLp($lp) ->setLp($lp)
@ -455,21 +370,20 @@ class scorm extends learnpath
if (!empty($item['maxtimeallowed'])) { if (!empty($item['maxtimeallowed'])) {
$lpItem->setMaxTimeAllowed($item['maxtimeallowed']); $lpItem->setMaxTimeAllowed($item['maxtimeallowed']);
} }
$em->persist($lpItem); $lpItemRepo->create($lpItem);
$em->flush();
$item_id = $lpItem->getIid(); $item_id = $lpItem->getIid();
if ($item_id) { /*if ($item_id) {
// Now update previous item to change next_item_id. // Now update previous item to change next_item_id.
$upd = "UPDATE $lpItemTable SET next_item_id = $item_id $upd = "UPDATE $lpItemTable SET next_item_id = $item_id
WHERE iid = $previous"; WHERE iid = $previous";
Database::query($upd); Database::query($upd);
// Update previous item id. // Update previous item id.
$previous = $item_id; $previous = $item_id;
} }*/
// Code for indexing, now only index specific fields like terms and the title. // Code for indexing, now only index specific fields like terms and the title.
if (!empty($_POST['index_document'])) { /*if (!empty($_POST['index_document'])) {
$di = new ChamiloIndexer(); $di = new ChamiloIndexer();
isset($_POST['language']) ? $lang = Database::escape_string($_POST['language']) : $lang = 'english'; isset($_POST['language']) ? $lang = Database::escape_string($_POST['language']) : $lang = 'english';
$di->connectDb(null, null, $lang); $di->connectDb(null, null, $lang);
@ -492,12 +406,12 @@ class scorm extends learnpath
$body_to_index = $all_specific_terms.' '.$title; $body_to_index = $all_specific_terms.' '.$title;
$ic_slide->addValue("content", $body_to_index); $ic_slide->addValue("content", $body_to_index);
// TODO: Add a comment to say terms separated by commas. // TODO: Add a comment to say terms separated by commas.
$courseid = api_get_course_id(); $ic_slide->addCourseId($courseId);
$ic_slide->addCourseId($courseid);
$ic_slide->addToolId(TOOL_LEARNPATH); $ic_slide->addToolId(TOOL_LEARNPATH);
// TODO: Unify with other lp types. // TODO: Unify with other lp types.
$xapian_data = [ $xapian_data = [
SE_COURSE_ID => $courseid, SE_COURSE_ID => $courseId,
SE_TOOL_ID => TOOL_LEARNPATH, SE_TOOL_ID => TOOL_LEARNPATH,
SE_DATA => ['lp_id' => $lp_id, 'lp_item' => $previous, 'document_id' => ''], SE_DATA => ['lp_id' => $lp_id, 'lp_item' => $previous, 'document_id' => ''],
SE_USER => api_get_user_id(), SE_USER => api_get_user_id(),
@ -511,10 +425,10 @@ class scorm extends learnpath
$tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF); $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
$sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, ref_id_second_level, search_did) $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, ref_id_second_level, search_did)
VALUES (NULL , \'%s\', \'%s\', %s, %s, %s)'; VALUES (NULL , \'%s\', \'%s\', %s, %s, %s)';
$sql = sprintf($sql, $tbl_se_ref, $courseCode, TOOL_LEARNPATH, $lp_id, $previous, $did); $sql = sprintf($sql, $tbl_se_ref, $course->getCode(), TOOL_LEARNPATH, $lp_id, $previous, $did);
Database::query($sql); Database::query($sql);
} }
} }*/
} }
} }
@ -559,6 +473,7 @@ class scorm extends learnpath
$lpToCheck = null, $lpToCheck = null,
$allowHtaccess = false $allowHtaccess = false
) { ) {
$this->debug= 100;
if ($this->debug) { if ($this->debug) {
error_log( error_log(
'In scorm::import_package('.print_r($zipFileInfo, true).',"'.$currentDir.'") method' 'In scorm::import_package('.print_r($zipFileInfo, true).',"'.$currentDir.'") method'
@ -568,13 +483,6 @@ class scorm extends learnpath
$zipFilePath = $zipFileInfo['tmp_name']; $zipFilePath = $zipFileInfo['tmp_name'];
$zipFileName = $zipFileInfo['name']; $zipFileName = $zipFileInfo['name'];
if ($this->debug > 1) {
error_log(
'import_package() - zip file path = '.$zipFilePath.', zip file name = '.$zipFileName,
0
);
}
$currentDir = api_replace_dangerous_char(trim($currentDir)); // Current dir we are in, inside scorm/ $currentDir = api_replace_dangerous_char(trim($currentDir)); // Current dir we are in, inside scorm/
if ($this->debug > 1) { if ($this->debug > 1) {
@ -589,7 +497,8 @@ class scorm extends learnpath
$this->zipname = $fileBaseName; // Save for later in case we don't have a title. $this->zipname = $fileBaseName; // Save for later in case we don't have a title.
$newDir = api_replace_dangerous_char(trim($fileBaseName)); $newDir = api_replace_dangerous_char(trim($fileBaseName));
$this->subdir = $newDir; $this->subdir = $newDir;
if ($this->debug > 1) { if ($this->debug) {
error_log('$zipFileName: '.$zipFileName);
error_log('Received zip file name: '.$zipFilePath); error_log('Received zip file name: '.$zipFilePath);
error_log("subdir is first set to : ".$this->subdir); error_log("subdir is first set to : ".$this->subdir);
error_log("base file name is : ".$fileBaseName); error_log("base file name is : ".$fileBaseName);
@ -598,7 +507,6 @@ class scorm extends learnpath
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->openFile($zipFilePath); $zipFile->openFile($zipFilePath);
$zipContentArray = $zipFile->getEntries(); $zipContentArray = $zipFile->getEntries();
$packageType = ''; $packageType = '';
$manifestList = []; $manifestList = [];
// The following loop should be stopped as soon as we found the right imsmanifest.xml (how to recognize it?). // The following loop should be stopped as soon as we found the right imsmanifest.xml (how to recognize it?).
@ -612,7 +520,7 @@ class scorm extends learnpath
} elseif (stristr($fileName, 'imsmanifest.xml')) { } elseif (stristr($fileName, 'imsmanifest.xml')) {
if ($fileName == basename($fileName)) { if ($fileName == basename($fileName)) {
} else { } else {
if ($this->debug > 2) { if ($this->debug) {
error_log("subdir is now ".$this->subdir); error_log("subdir is now ".$this->subdir);
} }
} }
@ -633,12 +541,17 @@ class scorm extends learnpath
} }
} }
$firstDir = $this->subdir;
$this->subdir .= '/'.dirname($shortestPath); // Do not concatenate because already done above. $this->subdir .= '/'.dirname($shortestPath); // Do not concatenate because already done above.
if ($this->debug) {
error_log("subdir is now (2): ".$this->subdir);
}
$this->manifestToString = $zipFile->getEntryContents($shortestPath); $this->manifestToString = $zipFile->getEntryContents($shortestPath);
if ($this->debug) { if ($this->debug) {
error_log("Package type is now: '$packageType'"); error_log("Package type is now: '$packageType'");
} }
if ('' === $packageType) { if ('' === $packageType) {
Display::addFlash( Display::addFlash(
Display::return_message(get_lang('This is not a valid SCORM ZIP file !')) Display::return_message(get_lang('This is not a valid SCORM ZIP file !'))
@ -695,58 +608,20 @@ class scorm extends learnpath
if ($request->files->has('user_file')) { if ($request->files->has('user_file')) {
$uploadFile = $request->files->get('user_file'); $uploadFile = $request->files->get('user_file');
} }
$em = Database::getManager();
$repo = Container::getAssetRepository();
$asset = (new Asset()) $asset = (new Asset())
->setCategory(Asset::SCORM) ->setCategory(Asset::SCORM)
->setTitle($zipFileName) ->setTitle($zipFileName)
->setFile($uploadFile) ->setFile($uploadFile)
->setCompressed(true) ->setCompressed(true)
; ;
$em->persist($asset); $repo->update($asset);
$em->flush();
// 2. Unzip file // 2. Unzip file
$repo = Container::getAssetRepository(); $repo->unZipFile($asset, $firstDir);
$repo->unZipFile($asset, $zipFile);
$this->asset = $asset; $this->asset = $asset;
/*if (is_dir($courseSysDir.$newDir) ||
@mkdir(
$courseSysDir.$newDir,
api_get_permissions_for_new_directories()
)
) {
// PHP method - slower...
if ($this->debug >= 1) {
error_log('Changing dir to '.$courseSysDir.$newDir);
}
chdir($courseSysDir.$newDir);
$callBack = 'clean_up_files_in_zip';
if ($allowHtaccess) {
$callBack = 'cleanZipFilesAllowHtaccess';
}
if (api_get_configuration_value('skip_scorm_package_clean_up')) {
$callBack = 'cleanZipFilesNoRename';
}
$zipFile->extract(
PCLZIP_CB_PRE_EXTRACT,
$callBack
);
if (!empty($newDir)) {
$newDir = $newDir.'/';
}
api_chmod_R($courseSysDir.$newDir, api_get_permissions_for_new_directories());
} else {
return false;
}*/
//return $courseSysDir.$newDir.$manifest;
return $asset; return $asset;
} }
@ -945,7 +820,7 @@ class scorm extends learnpath
if ($this->debug > 1) { if ($this->debug > 1) {
error_log('In scorm::reimport_manifest() - Importing manifest '.$manifest_file); error_log('In scorm::reimport_manifest() - Importing manifest '.$manifest_file);
} }
$this->import_manifest($this->cc); $this->import_manifest(api_get_course_int_id());
} else { } else {
if ($this->debug > 0) { if ($this->debug > 0) {
error_log('In scorm::reimport_manifest() - Could not find manifest file at '.$manifest_file); error_log('In scorm::reimport_manifest() - Could not find manifest file at '.$manifest_file);

@ -1,4 +1,5 @@
<?php <?php
/* For licensing terms, see /license.txt */ /* For licensing terms, see /license.txt */
/** /**
@ -15,13 +16,14 @@ class scormItem extends learnpathItem
public $isvisible = ''; public $isvisible = '';
public $parameters = ''; public $parameters = '';
public $title = ''; public $title = '';
/** @var array|scormItem[] */
public $sub_items = []; public $sub_items = [];
public $metadata; public $metadata;
//public $prerequisites = ''; - defined in learnpathItem.class.php //public $prerequisites = ''; - defined in learnpathItem.class.php
// Modified by Ivan Tcholakov, 06-FEB-2010. // Modified by Ivan Tcholakov, 06-FEB-2010.
//public $max_time_allowed = ''; //should be something like HHHH:MM:SS.SS //public $max_time_allowed = ''; //should be something like HHHH:MM:SS.SS
public $max_time_allowed = '00:00:00'; public $max_time_allowed = '00:00:00';
public $timelimitaction = ''; public $timelimitaction = '';
public $datafromlms = ''; public $datafromlms = '';
public $mastery_score = ''; public $mastery_score = '';
@ -35,13 +37,13 @@ class scormItem extends learnpathItem
* @param mixed $element Depending on the type given, DB id for the lp_item or reference to the DOM element * @param mixed $element Depending on the type given, DB id for the lp_item or reference to the DOM element
* @param int $course_id * @param int $course_id
*/ */
public function __construct($type = 'manifest', &$element, $course_id = 0) public function __construct($type = 'manifest', &$element = null)
{ {
if (isset($element)) { if (isset($element)) {
// Parsing using PHP5 DOMXML methods. // Parsing using PHP5 DOMXML methods.
switch ($type) { switch ($type) {
case 'db': case 'db':
parent::__construct($element, api_get_user_id(), $course_id); parent::__construct($element, api_get_user_id());
$this->scorm_contact = false; $this->scorm_contact = false;
// TODO: Implement this way of metadata object creation. // TODO: Implement this way of metadata object creation.
break; break;
@ -137,7 +139,6 @@ class scormItem extends learnpathItem
} }
} }
} }
// End parsing using PHP5 DOMXML methods.
} }
} }
@ -162,7 +163,7 @@ class scormItem extends learnpathItem
'maxtimeallowed' => $this->max_time_allowed, 'maxtimeallowed' => $this->max_time_allowed,
'metadata' => $this->metadata, 'metadata' => $this->metadata,
'parameters' => $this->parameters, 'parameters' => $this->parameters,
'prerequisites' => (!empty($this->prereq_string) ? $this->prereq_string : ''), 'prerequisites' => !empty($this->prereq_string) ? $this->prereq_string : '',
'rel_order' => $rel_order, 'rel_order' => $rel_order,
'timelimitaction' => $this->timelimitaction, 'timelimitaction' => $this->timelimitaction,
'title' => $this->title, 'title' => $this->title,

@ -1,13 +1,12 @@
<?php <?php
/* For licensing terms, see /license.txt */ /* For licensing terms, see /license.txt */
/** /**
* Container for the scormOrganization class. * Container for the scormOrganization class.
* *
* @author Yannick Warnier <ywarnier@beeznest.org> * @author Yannick Warnier <ywarnier@beeznest.org>
*/
/**
* Class defining the <organization> tag in an imsmanifest.xml file. * Class defining the <organization> tag in an imsmanifest.xml file.
*/ */
class scormOrganization class scormOrganization
@ -15,6 +14,7 @@ class scormOrganization
public $identifier = ''; public $identifier = '';
public $structure = ''; public $structure = '';
public $title = ''; public $title = '';
/** @var array|scormItem[] */
public $items = []; public $items = [];
public $metadata; public $metadata;
@ -26,7 +26,7 @@ class scormOrganization
* @param string Type of construction needed ('db' or 'manifest', default = 'manifest') * @param string Type of construction needed ('db' or 'manifest', default = 'manifest')
* @param mixed Depending on the type given, DB id for the lp_item or reference to the DOM element * @param mixed Depending on the type given, DB id for the lp_item or reference to the DOM element
*/ */
public function __construct($type = 'manifest', &$element, $scorm_charset = 'UTF-8') public function __construct($type = 'manifest', &$element = null)
{ {
if (isset($element)) { if (isset($element)) {
// Parsing using PHP5 DOMXML methods. // Parsing using PHP5 DOMXML methods.
@ -91,7 +91,6 @@ class scormOrganization
} }
} }
} }
// End parsing using PHP5 DOMXML methods.
} }
} }

@ -10,6 +10,7 @@ use Chamilo\CoreBundle\Component\Utils\CreateUploadedFile;
use Chamilo\CoreBundle\Entity\Asset; use Chamilo\CoreBundle\Entity\Asset;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
use Exception;
use League\Flysystem\FilesystemOperator; use League\Flysystem\FilesystemOperator;
use PhpZip\ZipFile; use PhpZip\ZipFile;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
@ -44,29 +45,41 @@ class AssetRepository extends ServiceEntityRepository
return $this->filesystem; return $this->filesystem;
} }
public function unZipFile(Asset $asset, ZipFile $zipFile): void public function unZipFile(Asset $asset, string $addFolder = ''): void
{ {
$folder = '/'.$asset->getCategory().'/'.$asset->getTitle(); $folder = '/'.$asset->getCategory().'/'.$asset->getTitle();
if (!empty($addFolder)) {
$folder .= '/'.$addFolder;
}
$fs = $this->getFileSystem(); $fs = $this->getFileSystem();
$file = $this->getStorage()->resolveUri($asset);
if (!$fs->fileExists($file)) {
throw new Exception('file not found');
}
if ($fs->fileExists($folder)) { $stream = $fs->readStream($file);
$list = $zipFile->getEntries(); $zipFile = new ZipFile();
foreach ($list as $item) { $zipFile->openFromStream($stream);
$name = $item->getName();
if ($fs->fileExists($folder.'/'.$name)) {
continue;
}
if ($item->isDirectory()) { $list = $zipFile->getEntries();
$fs->createDirectory($folder.'/'.$name); foreach ($list as $item) {
$name = $item->getName();
error_log('final: '.$folder.'/'.$name);
if ($fs->fileExists($folder.'/'.$name)) {
continue;
}
continue; if ($item->isDirectory()) {
} $fs->createDirectory($folder.'/'.$name);
$content = $zipFile->getEntryContents($name); continue;
$fs->write($folder.'/'.$name, $content);
} }
$content = $zipFile->getEntryContents($name);
$fs->write($folder.'/'.$name, $content);
} }
} }
@ -79,11 +92,11 @@ class AssetRepository extends ServiceEntityRepository
$fs = $this->getFileSystem(); $fs = $this->getFileSystem();
$file = $this->getStorage()->resolveUri($asset); $file = $this->getStorage()->resolveUri($asset);
if ($fs->fileExists($file)) { if (!$fs->fileExists($file)) {
return $this->getFileSystem()->read($file); return '';
} }
return ''; return $this->getFileSystem()->read($file);
} }
public function getFolder(Asset $asset): ?string public function getFolder(Asset $asset): ?string

@ -111,6 +111,31 @@ class AssetRepositoryTest extends AbstractApiTest
$this->assertResponseIsSuccessful(); $this->assertResponseIsSuccessful();
} }
public function testUnZipFileSubFolder(): void
{
$client = static::createClient();
$assetRepo = self::getContainer()->get(AssetRepository::class);
$this->assertSame(0, $assetRepo->count([]));
$file = $this->getUploadedZipFile();
$asset = (new Asset())
->setTitle('my file')
->setCategory(Asset::SCORM)
->setFile($file)
->setCompressed(true)
;
$assetRepo->update($asset);
$this->assertHasNoEntityViolations($asset);
$subDir = 'test/test';
$assetRepo->unZipFile($asset, $subDir);
$url = $assetRepo->getAssetUrl($asset);
$client->request('GET', $url.'/'.$subDir.'/logo.png');
$this->assertResponseIsSuccessful();
}
public function testDelete(): void public function testDelete(): void
{ {
self::bootKernel(); self::bootKernel();

Loading…
Cancel
Save