Code;Title;CourseCategory;Language;Visibility;"; $exampleCsv = "COURSE001;Introduction to Biology;BIO;english;1;"; foreach ($fields as $field) { $fieldType = (int) $field['field_type']; switch ($fieldType) { case ExtraField::FIELD_TYPE_CHECKBOX: $exampleValue = '1'; // 1 for true, 0 for false break; case ExtraField::FIELD_TYPE_TAG: $exampleValue = 'tag1,tag2,tag3'; // Comma separated list of tags break; default: $exampleValue = 'xxx'; // Example value for text fields } $headerCsv .= "".$field['field_variable'].";"; $exampleCsv .= "$exampleValue;"; } $modelCsv = $headerCsv."\n".$exampleCsv; return $modelCsv; } /** * Generates an XML model string showing how the XML file should be structured for course updates. */ function generateXmlModel(array $fields): string { $modelXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; $modelXml .= "<Courses>\n"; $modelXml .= " <Course>\n"; $modelXml .= " <Code>COURSE001</Code>\n"; $modelXml .= " <Title>Introduction to Biology</Title>\n"; $modelXml .= " <CourseCategory>BIO</CourseCategory>\n"; $modelXml .= " <Language>english</Language>\n"; $modelXml .= " <Visibility>1</Visibility>\n"; foreach ($fields as $field) { switch ($field['field_type']) { case ExtraField::FIELD_TYPE_CHECKBOX: $exampleValue = '1'; // 1 for true, 0 for false break; case ExtraField::FIELD_TYPE_TAG: $exampleValue = 'tag1,tag2,tag3'; // Comma separated list of tags break; default: $exampleValue = 'xxx'; // Example value for text fields } $modelXml .= " <".$field['field_variable'].">$exampleValue</".$field['field_variable'].">\n"; } $modelXml .= " </Course>\n"; $modelXml .= "</Courses>"; return $modelXml; } /** * Function to validate course data from the CSV/XML file. */ function validateCourseData(array $courses): array { $errors = []; $courseCodes = []; foreach ($courses as $course) { if (empty($course['Code'])) { $errors[] = get_lang("CodeIsRequired"); } else { $courseId = api_get_course_int_id($course['Code']); if (!$courseId) { $errors[] = get_lang("CourseCodeDoesNotExist").': '.$course['Code']; } elseif (in_array($course['Code'], $courseCodes)) { $errors[] = get_lang("DuplicateCode").': '.$course['Code']; } $courseCodes[] = $course['Code']; } } return $errors; } /** * Update course data in the database. */ function updateCourse(array $courseData, int $courseId): void { $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); $fieldsMapping = [ 'Title' => 'title', 'Language' => 'course_language', 'CourseCategory' => 'category_code', 'Visibility' => 'visibility', ]; $params = []; foreach ($fieldsMapping as $inputField => $dbField) { if (isset($courseData[$inputField])) { $params[$dbField] = $courseData[$inputField]; } } Database::update($courseTable, $params, ['id = ?' => $courseId]); if (isset($courseData['extra'])) { $courseData['extra']['code'] = $courseData['Code']; $courseData['extra']['item_id'] = $courseId; $saveOnlyThisFields = []; foreach ($courseData['extra'] as $key => $value) { $newKey = preg_replace('/^extra_/', '', $key); $saveOnlyThisFields[] = $newKey; } $courseFieldValue = new ExtraFieldValue('course'); $courseFieldValue->saveFieldValues( $courseData['extra'], false, false, $saveOnlyThisFields, [], true ); } } /** * Function to update courses from the imported data. */ function updateCourses(array $courses): void { foreach ($courses as $course) { $courseId = api_get_course_int_id($course['Code']); updateCourse($course, $courseId); } } /** * Function to parse CSV data. */ function parseCsvCourseData(string $file, array $extraFields): array { $data = Import::csv_reader($file); $courses = []; foreach ($data as $row) { $courseData = []; foreach ($row as $key => $value) { if (empty($key)) { continue; } if (in_array($key, array_column($extraFields, 'variable'))) { $processedValue = processExtraFieldValue($key, $value, $extraFields); $courseData['extra']['extra_'.$key] = $processedValue; } else { $courseData[$key] = $value; } } $courses[] = $courseData; } return $courses; } /** * Function to parse XML data. */ function parseXmlCourseData(string $file, array $extraFields): array { $xmlContent = Import::xml($file); $courses = []; foreach ($xmlContent->filter('Courses > Course') as $xmlCourse) { $courseData = []; foreach ($xmlCourse->childNodes as $node) { if ($node->nodeName !== '#text') { $key = $node->nodeName; if (empty($key)) { continue; } $value = $node->nodeValue; if (in_array($key, array_column($extraFields, 'variable'))) { $processedValue = processExtraFieldValue($key, $value, $extraFields); $courseData['extra']['extra_'.$key] = $processedValue; } else { $courseData[$key] = $value; } } } if (!empty($courseData)) { $courses[] = $courseData; } } return $courses; } /** * Processes the value of an extra field based on its type. * * This function takes the name and value of an extra field, along with an array of all extra fields, and processes * the value according to the field type. For checkbox fields, it returns an array with the field name as the key * and '1' (checked) or '0' (unchecked) as the value. For tag fields, it splits the string by commas into an array. * For other types, it returns the value as is. */ function processExtraFieldValue(string $fieldName, $value, array $extraFields) { $fieldIndex = array_search($fieldName, array_column($extraFields, 'variable')); if ($fieldIndex === false) { return $value; } $fieldType = $extraFields[$fieldIndex]['field_type']; switch ($fieldType) { case ExtraField::FIELD_TYPE_CHECKBOX: $newValue = 0; if ($value == '1') { $newValue = ['extra_'.$fieldName => '1']; } return $newValue; case ExtraField::FIELD_TYPE_TAG: return explode(',', $value); default: return $value; } } $toolName = get_lang('UpdateCourseListXMLCSV'); $interbreadcrumb[] = ["url" => 'index.php', "name" => get_lang('PlatformAdmin')]; $form = new FormValidator('course_update_import'); $form->addHeader(get_lang('UpdateCourseListXMLCSV')); $form->addFile('importFile', get_lang('ImportCSVFileLocation')); $form->addElement('radio', 'file_type', get_lang('FileType'), get_lang('CSV'), 'csv'); $form->addElement('radio', 'file_type', '', get_lang('XML'), 'xml'); $defaults['file_type'] = 'csv'; $form->setDefaults($defaults); $form->addButtonImport(get_lang('Import')); if ($form->validate()) { if (!isset($_FILES['importFile']['error']) || is_array($_FILES['importFile']['error'])) { Display::addFlash(Display::return_message(get_lang('InvalidFileUpload'), 'error')); } else { switch ($_FILES['importFile']['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_NO_FILE: Display::addFlash(Display::return_message(get_lang('NoFileSent'), 'error')); break; case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: Display::addFlash(Display::return_message(get_lang('ExceededFileSizeLimit'), 'error')); break; default: Display::addFlash(Display::return_message(get_lang('UnknownErrors'), 'error')); } } $fileType = $_POST['file_type']; $fileExt = strtolower(pathinfo($_FILES['importFile']['name'], PATHINFO_EXTENSION)); if (($fileType === 'csv' && $fileExt !== 'csv') || ($fileType === 'xml' && $fileExt !== 'xml')) { Display::addFlash(Display::return_message(get_lang('InvalidFileType'), 'error')); } else { $file = $_FILES['importFile']['tmp_name']; $extraField = new ExtraField('course'); $allExtraFields = $extraField->get_all(); $successfulUpdates = []; $failedUpdates = []; try { if ($fileType === 'csv') { $courses = parseCsvCourseData($file, $allExtraFields); } else { $courses = parseXmlCourseData($file, $allExtraFields); } foreach ($courses as $course) { $courseErrors = validateCourseData([$course]); if (!empty($courseErrors)) { $failedUpdates[] = $course['Code'].': '.implode(', ', $courseErrors); continue; } try { updateCourses([$course]); $successfulUpdates[] = $course['Code']; } catch (Exception $e) { $failedUpdates[] = $course['Code'].': '.$e->getMessage(); } } if (!empty($successfulUpdates)) { Display::addFlash(Display::return_message(get_lang('CoursesUpdatedSuccessfully').': '.implode(', ', $successfulUpdates), 'success')); } if (!empty($failedUpdates)) { foreach ($failedUpdates as $error) { Display::addFlash(Display::return_message(get_lang('UpdateFailedForCourses').': '.$error, 'error')); } } } catch (Exception $e) { Display::addFlash(Display::return_message($e->getMessage(), 'error')); } } } $htmlHeadXtra[] = ""; Display::display_header($toolName); $form->display(); $extraField = new ExtraField('course'); $allExtraFields = $extraField->get_all(); $extraFields = []; foreach ($allExtraFields as $field) { $extraFields[] = [ 'field_variable' => $field['variable'], 'field_type' => $field['field_type'], ]; } $csvContent = generateCsvModel($extraFields); $xmlContent = generateXmlModel($extraFields); echo '
'.get_lang('CSVMustLookLike').' ('.get_lang('MandatoryFields').'):
'; echo ''.$csvContent.'
Visibility: 0=CLOSED, 1=PRIVATE, 2=OPEN, 3=PUBLIC, 4=HIDDEN.