public/main/inc/lib/add_course.lib.inc.php
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\CourseRelUser;
use Chamilo\CoreBundle\Entity\GradebookCategory;
use Chamilo\CoreBundle\Entity\GradebookLink;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CourseBundle\Entity\CGroupCategory;
use Chamilo\CourseBundle\Entity\CToolIntro;
/**
* Class AddCourse.
*/
class AddCourse
{
public const FIRST_EXPIRATION_DATE = 31536000; // 365 days in seconds
/**
* Defines the four needed keys to create a course based on several parameters.
*
* @param string The code you want for this course
* @param string Prefix added for ALL keys
* @param string Prefix added for databases only
* @param string Prefix added for paths only
* @param bool Add unique prefix
* @param bool Use code-independent keys
*
* @return array An array with the needed keys ['currentCourseCode'], ['currentCourseId'], ['currentCourseDbName'],
* ['currentCourseRepository']
*
* @todo Eliminate the global variables.
* @assert (null) === false
*/
public static function define_course_keys(
$wanted_code,
$prefix_for_all = '',
$prefix_for_base_name = '',
$prefix_for_path = '',
$add_unique_prefix = false,
$use_code_indepedent_keys = true
) {
$course_table = Database::get_main_table(TABLE_MAIN_COURSE);
$wanted_code = CourseManager::generate_course_code($wanted_code);
$keys_course_code = $wanted_code;
if (!$use_code_indepedent_keys) {
$wanted_code = '';
}
$unique_prefix = '';
if ($add_unique_prefix) {
$unique_prefix = substr(md5(uniqid(rand())), 0, 10);
}
$keys = [];
$final_suffix = ['CourseId' => '', 'CourseDb' => '', 'CourseDir' => ''];
$limit_numb_try = 100;
$keys_are_unique = false;
$try_new_fsc_id = $try_new_fsc_db = $try_new_fsc_dir = 0;
while (!$keys_are_unique) {
$keys_course_id = $prefix_for_all.$unique_prefix.$wanted_code.$final_suffix['CourseId'];
$keys_course_repository = $prefix_for_path.$unique_prefix.$wanted_code.$final_suffix['CourseDir'];
$keys_are_unique = true;
// Check whether they are unique.
$query = "SELECT 1 FROM $course_table
WHERE code='".$keys_course_id."'
LIMIT 0, 1";
$result = Database::query($query);
if (Database::num_rows($result)) {
$keys_are_unique = false;
$try_new_fsc_id++;
$final_suffix['CourseId'] = substr(md5(uniqid(rand())), 0, 4);
}
if (($try_new_fsc_id + $try_new_fsc_db + $try_new_fsc_dir) > $limit_numb_try) {
return $keys;
}
}
$keys['currentCourseCode'] = $keys_course_code;
$keys['currentCourseId'] = $keys_course_id;
$keys['currentCourseRepository'] = $keys_course_repository;
return $keys;
}
/**
* Gets an array with all the course tables (deprecated?).
*
* @return array
*
* @assert (null) !== null
*/
public static function get_course_tables()
{
$tables = [];
//$tables[] = 'item_property';
$tables[] = 'tool';
$tables[] = 'tool_intro';
$tables[] = 'group_info';
$tables[] = 'group_category';
$tables[] = 'group_rel_user';
$tables[] = 'group_rel_tutor';
$tables[] = 'userinfo_content';
$tables[] = 'userinfo_def';
$tables[] = 'course_description';
$tables[] = 'calendar_event';
$tables[] = 'calendar_event_repeat';
$tables[] = 'calendar_event_repeat_not';
$tables[] = 'calendar_event_attachment';
$tables[] = 'announcement';
$tables[] = 'announcement_attachment';
//$tables[] = 'resource';
$tables[] = 'student_publication';
$tables[] = 'student_publication_assignment';
$tables[] = 'document';
/*$tables[] = 'forum_category';
$tables[] = 'forum_forum';
$tables[] = 'forum_thread';
$tables[] = 'forum_post';
$tables[] = 'forum_mailcue';
$tables[] = 'forum_attachment';
$tables[] = 'forum_notification';
$tables[] = 'forum_thread_qualify';
$tables[] = 'forum_thread_qualify_log';*/
$tables[] = 'link';
$tables[] = 'link_category';
$tables[] = 'online_connected';
$tables[] = 'online_link';
$tables[] = 'chat_connected';
$tables[] = 'quiz';
$tables[] = 'quiz_rel_question';
$tables[] = 'quiz_question';
$tables[] = 'quiz_answer';
$tables[] = 'quiz_question_option';
$tables[] = 'quiz_question_category';
$tables[] = 'quiz_question_rel_category';
$tables[] = 'dropbox_post';
$tables[] = 'dropbox_file';
$tables[] = 'dropbox_person';
$tables[] = 'dropbox_category';
$tables[] = 'dropbox_feedback';
$tables[] = 'lp';
$tables[] = 'lp_item';
$tables[] = 'lp_view';
$tables[] = 'lp_item_view';
$tables[] = 'lp_iv_interaction';
$tables[] = 'lp_iv_objective';
$tables[] = 'blog';
$tables[] = 'blog_comment';
$tables[] = 'blog_post';
$tables[] = 'blog_rating';
$tables[] = 'blog_rel_user';
$tables[] = 'blog_task';
$tables[] = 'blog_task_rel_user';
$tables[] = 'blog_attachment';
$tables[] = 'permission_group';
$tables[] = 'permission_user';
$tables[] = 'permission_task';
$tables[] = 'role';
$tables[] = 'role_group';
$tables[] = 'role_permissions';
$tables[] = 'role_user';
$tables[] = 'survey';
$tables[] = 'survey_question';
$tables[] = 'survey_question_option';
$tables[] = 'survey_invitation';
$tables[] = 'survey_answer';
$tables[] = 'survey_group';
$tables[] = 'wiki';
$tables[] = 'wiki_conf';
$tables[] = 'wiki_discuss';
$tables[] = 'wiki_mailcue';
$tables[] = 'course_setting';
$tables[] = 'glossary';
$tables[] = 'notebook';
$tables[] = 'attendance';
$tables[] = 'attendance_sheet';
$tables[] = 'attendance_calendar';
$tables[] = 'attendance_result';
$tables[] = 'attendance_sheet_log';
$tables[] = 'thematic';
$tables[] = 'thematic_plan';
$tables[] = 'thematic_advance';
return $tables;
}
/**
* Executed only before create_course_tables().
*
* @assert (null) === null
*/
public static function drop_course_tables()
{
$list = self::get_course_tables();
foreach ($list as $table) {
$sql = "DROP TABLE IF EXISTS ".DB_COURSE_PREFIX.$table;
Database::query($sql);
}
}
/**
* Sorts pictures by type (used?).
*
* @param array List of files (sthg like array(0=>array('png'=>1)))
* @param string $type
*
* @return array The received array without files not matching type
* @assert (array(),null) === array()
*/
public static function sort_pictures($files, $type)
{
$pictures = [];
foreach ($files as $value) {
if (isset($value[$type]) && '' != $value[$type]) {
$pictures[][$type] = $value[$type];
}
}
return $pictures;
}
/**
* Populates the course with essential settings, group categories, example content, and installs course plugins.
*
* This method initializes a new course by setting up various course settings, creating a default group category,
* inserting example content if required, and installing course-specific plugins. The method can also fill the course
* with exemplary content based on the parameter provided or the system setting for example content creation.
*
* @param Course $course The course entity to be populated.
* @param bool|null $fillWithExemplaryContent Determines whether to fill the course with exemplary content. If null,
* the system setting for example material course creation is used.
* @param int $authorId The ID of the user who is considered the author of the exemplary content. Defaults to the
* current user if not specified.
*
* @return bool Returns true if the course is successfully populated, false otherwise.
*
* @throws Exception Throws exception on error.
*/
public static function fillCourse(Course $course, bool $fillWithExemplaryContent = null, int $authorId = 0): bool
{
$entityManager = Database::getManager();
$authorId = $authorId ?: api_get_user_id();
self::insertCourseSettings($course);
self::createGroupCategory($course);
$gradebook = self::createRootGradebook($course);
if ($fillWithExemplaryContent ?? api_get_setting('example_material_course_creation') !== 'false') {
self::insertExampleContent($course, $authorId, $entityManager);
}
self::installCoursePlugins($course->getId());
return true;
}
/**
* Inserts default and specified settings for a given course.
*
* This method takes a Course object as input and applies a predefined
* set of settings. These settings include configurations for email alerts,
* permissions for users to edit various components like agenda and announcements,
* theme settings, and more. It also handles the case where a course needs to
* enable certain features by default based on platform-wide settings.
*
* @param Course $course The course object to which the settings will be applied.
*
* @return void
* @throws Exception
*/
private static function insertCourseSettings(Course $course): void
{
$TABLESETTING = Database::get_course_table(TABLE_COURSE_SETTING);
$settingsManager = Container::getCourseSettingsManager();
$settingsManager->setCourse($course);
$alert = api_get_setting('email_alert_manager_on_new_quiz');
$defaultEmailExerciseAlert = 0;
if ('true' === $alert) {
$defaultEmailExerciseAlert = 1;
}
/* course_setting table (courseinfo tool) */
$settings = [
'email_alert_manager_on_new_doc' => ['title' => '', 'default' => 0, 'category' => 'work'],
'email_alert_on_new_doc_dropbox' => ['default' => 0, 'category' => 'dropbox'],
'allow_user_edit_agenda' => ['default' => 0, 'category' => 'agenda'],
'allow_user_edit_announcement' => ['default' => 0, 'category' => 'announcement'],
'email_alert_manager_on_new_quiz' => ['default' => $defaultEmailExerciseAlert, 'category' => 'quiz'],
'allow_user_image_forum' => ['default' => 1, 'category' => 'forum'],
'course_theme' => ['default' => '', 'category' => 'theme'],
'allow_learning_path_theme' => ['default' => 1, 'category' => 'theme'],
'allow_open_chat_window' => ['default' => 1, 'category' => 'chat'],
'email_alert_to_teacher_on_new_user_in_course' => ['default' => 0, 'category' => 'registration'],
'allow_user_view_user_list' => ['default' => 1, 'category' => 'user'],
'display_info_advance_inside_homecourse' => ['default' => 1, 'category' => 'thematic_advance'],
'email_alert_students_on_new_homework' => ['default' => 0, 'category' => 'work'],
'enable_lp_auto_launch' => ['default' => 0, 'category' => 'learning_path'],
'enable_exercise_auto_launch' => ['default' => 0, 'category' => 'exercise'],
'enable_document_auto_launch' => ['default' => 0, 'category' => 'document'],
'pdf_export_watermark_text' => ['default' => '', 'category' => 'learning_path'],
'allow_public_certificates' => [
'default' => 'true' === api_get_setting('allow_public_certificates') ? 1 : '',
'category' => 'certificates',
],
'documents_default_visibility' => ['default' => 'visible', 'category' => 'document'],
'show_course_in_user_language' => ['default' => 2, 'category' => null],
'email_to_teachers_on_new_work_feedback' => ['default' => 1, 'category' => null],
];
$counter = 1;
foreach ($settings as $variable => $setting) {
$title = $setting['title'] ?? '';
Database::query(
"INSERT INTO $TABLESETTING (c_id, title, variable, value, category)
VALUES ({$course->getId()}, '".$title."', '".$variable."', '".$setting['default']."', '".$setting['category']."')"
);
$counter++;
}
}
/**
* Creates a default group category for the specified course.
*
* This method initializes a new group category with a default title
* and associates it with the given course. The default group category
* is essential for organizing groups within the course, allowing for
* better management and classification of course participants.
*
* @param Course $course The course object for which the default group category is created.
*
* @return void
*/
private static function createGroupCategory(Course $course): void
{
$groupCategory = new CGroupCategory();
$groupCategory
->setTitle(get_lang('Default groups'))
->setParent($course)
->addCourseLink($course)
;
Database::getManager()->persist($groupCategory);
Database::getManager()->flush();
}
/**
* Inserts example content into a given course.
*
* This method populates the specified course with a predefined set of example
* content, including documents, links, announcements, and exercises. This content
* serves as a template or starting point for instructors, showcasing the various
* types of materials and activities that can be included in a course. The content
* is added under the authority of the specified author ID.
*
* @param Course $course The course object into which the example content will be inserted.
* @param int $authorId The ID of the user who will be listed as the author of the inserted content.
* @param GradebookCategory $gradebook
*
* @return void
* @throws Exception
*/
private static function insertExampleContent(Course $course, int $authorId, GradebookCategory $gradebook): void
{
$now = api_get_utc_datetime();
$files = [
['path' => '/audio', 'title' => get_lang('Audio'), 'filetype' => 'folder', 'size' => 0],
['path' => '/images', 'title' => get_lang('Images'), 'filetype' => 'folder', 'size' => 0],
['path' => '/images/gallery', 'title' => get_lang('Gallery'), 'filetype' => 'folder', 'size' => 0],
['path' => '/video', 'title' => get_lang('Video'), 'filetype' => 'folder', 'size' => 0],
];
$paths = [];
$courseInfo = ['real_id' => $course->getId(), 'code' => $course->getCode()];
$counter = 1;
foreach ($files as $file) {
$doc = self::insertDocument($courseInfo, $counter, $file, $authorId);
$paths[$file['path']] = $doc->getIid();
$counter++;
}
$finder = new Symfony\Component\Finder\Finder();
$defaultPath = api_get_path(SYS_PUBLIC_PATH).'img/document';
$finder->in($defaultPath);
/** @var SplFileInfo $file */
foreach ($finder as $file) {
$parentName = dirname(str_replace($defaultPath, '', $file->getRealPath()));
if ('/' === $parentName || '/certificates' === $parentName) {
continue;
}
$title = $file->getFilename();
$parentId = $paths[$parentName];
if ($file->isDir()) {
$realPath = str_replace($defaultPath, '', $file->getRealPath());
$document = DocumentManager::addDocument(
$courseInfo,
$realPath,
'folder',
null,
$title,
'',
null,
null,
null,
null,
null,
false,
null,
$parentId,
$file->getRealPath()
);
$paths[$realPath] = $document->getIid();
} else {
$realPath = str_replace($defaultPath, '', $file->getRealPath());
$document = DocumentManager::addDocument(
$courseInfo,
$realPath,
'file',
$file->getSize(),
$title,
'',
null,
null,
null,
null,
null,
false,
null,
$parentId,
$file->getRealPath()
);
if ($document && 'default.html' === $document->getTitle()) {
$certificateId = $document->getIid();
}
}
}
$agenda = new Agenda('course');
$agenda->set_course($courseInfo);
$agenda->addEvent(
$now,
$now,
0,
get_lang('Course creation'),
get_lang('This course was created at this time')
);
/* Links tool */
$link = new Link();
$link->setCourse($courseInfo);
$links = [
[
'c_id' => $course->getId(),
'url' => 'http://www.google.com',
'title' => 'Quick and powerful search engine',
'description' => get_lang('Quick and powerful search engine'),
'category_id' => 0,
'on_homepage' => 0,
'target' => '_self',
'session_id' => 0,
],
[
'c_id' => $course->getId(),
'url' => 'http://www.wikipedia.org',
'title' => 'Free online encyclopedia',
'description' => get_lang('Free online encyclopedia'),
'category_id' => 0,
'on_homepage' => 0,
'target' => '_self',
'session_id' => 0,
],
];
foreach ($links as $params) {
$link->save($params, false, false);
}
/* Announcement tool */
AnnouncementManager::add_announcement(
$courseInfo,
0,
get_lang('This is an announcement example'),
get_lang('This is an announcement example. Only trainers are allowed to publish announcements.'),
['everyone' => 'everyone'],
null,
null,
$now
);
/* Exercise tool */
$exercise = new Exercise($course->getId());
$exercise->exercise = get_lang('Sample test');
$html = '<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="220" valign="top" align="left">
<img src="'.api_get_path(WEB_PUBLIC_PATH).'img/document/images/mr_chamilo/doubts.png">
</td>
<td valign="top" align="left">'.get_lang('Irony').'</td></tr>
</table>';
$exercise->type = 1;
$exercise->setRandom(0);
$exercise->active = 1;
$exercise->results_disabled = 0;
$exercise->description = $html;
$exercise->save();
$question = new MultipleAnswer();
$question->course = $courseInfo;
$question->question = get_lang('Socratic irony is...');
$question->description = get_lang('(more than one answer can be true)');
$question->weighting = 10;
$question->position = 1;
$question->course = $courseInfo;
$question->save($exercise);
$questionId = $question->id;
$answer = new Answer($questionId, $courseInfo['real_id']);
$answer->createAnswer(get_lang('Ridiculise one\'s interlocutor in order to have him concede he is wrong.'), 0, get_lang('No. Socratic irony is not a matter of psychology, it concerns argumentation.'), -5, 1);
$answer->createAnswer(get_lang('Admit one\'s own errors to invite one\'s interlocutor to do the same.'), 0, get_lang('No. Socratic irony is not a seduction strategy or a method based on the example.'), -5, 2);
$answer->createAnswer(get_lang('Compell one\'s interlocutor, by a series of questions and sub-questions, to admit he doesn\'t know what he claims to know.'), 1, get_lang('Indeed'), 5, 3);
$answer->createAnswer(get_lang('Use the Principle of Non Contradiction to force one\'s interlocutor into a dead end.'), 1, get_lang('This answer is not false. It is true that the revelation of the interlocutor\'s ignorance means showing the contradictory conclusions where lead his premisses.'), 5, 4);
$answer->save();
// Forums.
$params = [
'forum_category_title' => get_lang('Example Forum Category'),
'forum_category_comment' => '',
];
$forumCategoryId = saveForumCategory($params, $courseInfo, false);
$params = [
'forum_category' => $forumCategoryId,
'forum_title' => get_lang('Example Forum'),
'forum_comment' => '',
'default_view_type_group' => ['default_view_type' => 'flat'],
];
$forumId = store_forum($params, $courseInfo, true);
$repo = Container::getForumRepository();
$forumEntity = $repo->find($forumId);
$params = [
'post_title' => get_lang('Example Thread'),
'forum_id' => $forumId,
'post_text' => get_lang('Example ThreadContent'),
'calification_notebook_title' => '',
'numeric_calification' => '',
'weight_calification' => '',
'forum_category' => $forumCategoryId,
'thread_peer_qualify' => 0,
];
saveThread($forumEntity, $params, $courseInfo, false);
self::createExampleGradebookContent($course, $gradebook, $exercise->id);
}
/**
* Creates the gradebook structure for a course.
*
* This method sets up the initial gradebook categories and links for a new course.
* It creates a parent gradebook category representing the course itself and a child
* gradebook category for course activities. It then creates a gradebook link associated
* with a specific course activity, identified by the $refId parameter.
*
* @param Course $course The course entity for which the gradebook structure will be created.
* @param int $refId The reference ID of the course activity to link in the gradebook.
*
* @return void
*/
private static function createExampleGradebookContent(Course $course, GradebookCategory $parentCategory, int $refId): void
{
$manager = Database::getManager();
/* Gradebook tool */
$courseCode = $course->getCode();
$childGradebookCategory = new GradebookCategory();
$childGradebookCategory->setTitle($courseCode);
$childGradebookCategory->setLocked(0);
$childGradebookCategory->setGenerateCertificates(false);
$childGradebookCategory->setDescription('');
$childGradebookCategory->setCourse($course);
$childGradebookCategory->setWeight(100);
$childGradebookCategory->setVisible(true);
$childGradebookCategory->setCertifMinScore(75);
$childGradebookCategory->setParent($parentCategory);
$childGradebookCategory->setUser(api_get_user_entity());
$manager->persist($childGradebookCategory);
$manager->flush();
$gradebookLink = new GradebookLink();
$gradebookLink->setType(1);
$gradebookLink->setRefId($refId);
$gradebookLink->setCourse($course);
$gradebookLink->setCategory($childGradebookCategory);
$gradebookLink->setCreatedAt(new \DateTime());
$gradebookLink->setWeight(100);
$gradebookLink->setVisible(1);
$gradebookLink->setLocked(0);
$manager->persist($gradebookLink);
$manager->flush();
}
/**
* Creates the basic gradebook structure for a course.
*
* This method sets up the initial gradebook categories and links for a new course.
* It creates a parent gradebook category representing the course itself.
*
* @param Course $course The course entity for which the gradebook structure will be created.
*
* @return GradebookCategory The created gradebook's ID
* @throws \Doctrine\ORM\Exception\ORMException
*/
private static function createRootGradebook(Course $course): GradebookCategory
{
$manager = Database::getManager();
/* Gradebook tool */
$courseCode = $course->getCode();
$parentGradebookCategory = new GradebookCategory();
$parentGradebookCategory->setTitle($courseCode);
$parentGradebookCategory->setLocked(0);
$parentGradebookCategory->setGenerateCertificates(false);
$parentGradebookCategory->setDescription('');
$parentGradebookCategory->setCourse($course);
$parentGradebookCategory->setWeight(100);
$parentGradebookCategory->setVisible(false);
$parentGradebookCategory->setCertifMinScore(75);
$parentGradebookCategory->setUser(api_get_user_entity());
$manager->persist($parentGradebookCategory);
$manager->flush();
return $parentGradebookCategory;
}
/**
* Installs plugins for a given course.
*
* This method takes a course ID and uses the AppPlugin service to install
* all necessary or default plugins for that specific course. These plugins
* can enhance the functionality of the course by adding new features or
* tools that are not part of the core Chamilo platform.
*
* @param int $courseId The ID of the course for which the plugins will be installed.
*
* @return void
*/
private static function installCoursePlugins(int $courseId): void
{
$app_plugin = new AppPlugin();
$app_plugin->install_course_plugins($courseId);
}
/**
* @param array $courseInfo
* @param int $counter
* @param array $file
* @param int $authorId
*/
public static function insertDocument($courseInfo, $counter, $file, $authorId = 0)
{
return DocumentManager::addDocument(
$courseInfo,
$file['path'],
$file['filetype'],
$file['size'],
$file['title'],
null,
0,
null,
0,
0,
0,
false
);
}
/**
* string2binary converts the string "true" or "false" to the boolean true false (0 or 1)
* This is used for the Chamilo Config Settings as these store true or false as string
* and the api_get_setting('course_create_active_tools') should be 0 or 1 (used for
* the visibility of the tool).
*
* @param string $variable
*
* @return bool
*
* @author Patrick Cool, patrick.cool@ugent.be
* @assert ('true') === true
* @assert ('false') === false
*/
public static function string2binary($variable)
{
if ('true' == $variable) {
return true;
}
if ('false' == $variable) {
return false;
}
}
/**
* Function register_course to create a record in the course table of the main database.
*
* @param array $params Course details (see code for details).
*
* @throws Exception
*
* @return Course|null
*/
public static function register_course(array $params): ?Course
{
global $error_msg;
$title = $params['title'];
// Fix amp
$title = str_replace('&', '&', $title);
$code = $params['code'];
$visual_code = $params['visual_code'];
$directory = $params['directory'];
$tutor_name = $params['tutor_name'] ?? null;
$course_language = !empty($params['course_language']) ? $params['course_language'] : api_get_setting(
'platformLanguage'
);
$department_name = $params['department_name'] ?? null;
$department_url = $params['department_url'] ?? null;
$disk_quota = $params['disk_quota'] ?? null;
if (!isset($params['visibility'])) {
$default_course_visibility = api_get_setting('courses_default_creation_visibility');
$visibility = $default_course_visibility ?? Course::OPEN_PLATFORM;
} else {
$visibility = $params['visibility'];
}
$subscribe = false;
if (isset($params['subscribe'])) {
$subscribe = 1 === (int) $params['subscribe'];
} elseif (Course::OPEN_PLATFORM == $visibility) {
$subscribe = true;
}
//$subscribe = isset($params['subscribe']) ? (int) $params['subscribe'] : COURSE_VISIBILITY_OPEN_PLATFORM == $visibility ? 1 : 0;
$unsubscribe = isset($params['unsubscribe']) ? (int) $params['unsubscribe'] : 0;
$expiration_date = $params['expiration_date'] ?? null;
$teachers = $params['teachers'] ?? null;
$categories = $params['course_categories'] ?? null;
$valid = true;
// Check whether all the needed parameters are present.
if (empty($code)) {
$error_msg[] = 'courseSysCode is missing';
$valid = false;
}
if (empty($visual_code)) {
$error_msg[] = 'courseScreenCode is missing';
$valid = false;
}
if (empty($directory)) {
$error_msg[] = 'courseRepository is missing';
$valid = false;
}
if (empty($title)) {
$error_msg[] = 'title is missing';
$valid = false;
}
if (empty($expiration_date)) {
$expiration_date = api_get_utc_datetime(
time() + self::FIRST_EXPIRATION_DATE
);
} else {
$expiration_date = api_get_utc_datetime($expiration_date);
}
if ($visibility < 0 || $visibility > 4) {
$error_msg[] = 'visibility is invalid';
$valid = false;
}
if (empty($disk_quota)) {
$disk_quota = api_get_setting('default_document_quotum');
}
if (false === stripos($department_url, 'http://') && false === stripos($department_url, 'https://')) {
$department_url = 'http://'.$department_url;
}
// just in case
if ('http://' === $department_url) {
$department_url = '';
}
$userId = empty($params['user_id']) ? api_get_user_id() : (int) $params['user_id'];
$user = api_get_user_entity($userId);
if (null === $user) {
error_log(sprintf('user_id "%s" is invalid', $userId));
return null;
}
$course = null;
if ($valid) {
$repo = Container::getCourseRepository();
$categoryRepo = Container::getCourseCategoryRepository();
$course = new Course();
$course
->setTitle($title)
->setCode($code)
->setCourseLanguage($course_language)
->setDescription(get_lang('Course Description'))
->setVisibility($visibility)
->setShowScore(1)
->setDiskQuota($disk_quota)
->setExpirationDate(new DateTime($expiration_date))
->setDepartmentName((string) $department_name)
->setDepartmentUrl($department_url)
->setSubscribe($subscribe)
->setSticky(1 === (int) ($params['sticky'] ?? 0))
->setVideoUrl($params['video_url'] ?? '')
->setUnsubscribe($unsubscribe)
->setVisualCode($visual_code)
->setCreator(api_get_user_entity())
;
if (isset($params['duration'])) {
$course->setDuration($params['duration']);
}
if (!empty($categories)) {
if (!is_array($categories)) {
$categories = [$categories];
}
foreach ($categories as $key) {
if (empty($key)) {
continue;
}
$category = $categoryRepo->find($key);
if (null !== $category) {
$course->addCategory($category);
}
}
}
$sort = api_max_sort_value('0', api_get_user_id());
// Default true
$addTeacher = $params['add_user_as_teacher'] ?? true;
if ($addTeacher) {
$iCourseSort = CourseManager::userCourseSort($userId, $code);
$courseRelTutor = (new CourseRelUser())
->setCourse($course)
->setUser($user)
->setStatus(1)
->setTutor(true)
->setSort($iCourseSort)
->setRelationType(0)
->setUserCourseCat(0)
;
$course->addSubscription($courseRelTutor);
}
if (!empty($teachers)) {
$sort = $user->getMaxSortValue();
if (!is_array($teachers)) {
$teachers = [$teachers];
}
foreach ($teachers as $key) {
// Just in case.
if ($key == $userId) {
continue;
}
if (empty($key)) {
continue;
}
$teacher = api_get_user_entity($key);
if (is_null($teacher)) {
continue;
}
$courseRelTeacher = (new CourseRelUser())
->setCourse($course)
->setUser($teacher)
->setStatus(1)
->setTutor(false)
->setSort($sort + 1)
->setRelationType(0)
->setUserCourseCat(0)
;
$course->addSubscription($courseRelTeacher);
}
}
$repo->create($course);
$course_id = $course->getId();
if ($course_id) {
// Add event to the system log.
Event::addEvent(
LOG_COURSE_CREATE,
LOG_COURSE_CODE,
$code,
api_get_utc_datetime(),
$userId,
$course_id
);
$send_mail_to_admin = api_get_setting('send_email_to_admin_when_create_course');
// @todo Improve code to send to all current portal administrators.
if ('true' === $send_mail_to_admin) {
$siteName = api_get_setting('siteName');
$recipient_email = api_get_setting('emailAdministrator');
$recipient_name = api_get_person_name(
api_get_setting('administratorName'),
api_get_setting('administratorSurname')
);
$iname = api_get_setting('Institution');
$subject = get_lang('NewCourseCreatedIn').' '.$siteName.' - '.$iname;
$message = get_lang('Dear').' '.$recipient_name.",\n\n".
get_lang('MessageOfNewCourseToAdmin').' '.$siteName.' - '.$iname."\n";
$message .= get_lang('Course name').' '.$title."\n";
if ($course->getCategories()->count() > 0) {
foreach ($course->getCategories() as $category) {
$message .= get_lang('Category').': '.$category->getCode()."\n";
}
}
$message .= get_lang('Coach').' '.$tutor_name."\n";
$message .= get_lang('Language').' '.$course_language;
api_mail_html(
$recipient_name,
$recipient_email,
$subject,
$message,
$siteName,
$recipient_email,
null,
null,
null
);
}
}
}
return $course;
}
/**
* Generate a new id for c_tool table.
*
* @param int $courseId The course id
*
* @return int the new id
*/
public static function generateToolId($courseId)
{
$newIdResultData = Database::select(
'id + 1 AS new_id',
Database::get_course_table(TABLE_TOOL_LIST),
[
'where' => ['c_id = ?' => intval($courseId)],
'order' => 'id',
'limit' => 1,
],
'first'
);
if (false === $newIdResultData) {
return 1;
}
return $newIdResultData['new_id'] > 0 ? $newIdResultData['new_id'] : 1;
}
}