/** * Update a course. * * Please note this functions does not verify any access control, * the calling code is responsible for all validation (usually it is the form definition). * * @param object $data - all the data needed for an entry in the 'course' table * @param array $editoroptions course description editor options * @return void */ function update_course($data, $editoroptions = NULL) { global $DB, $CFG; $data->timemodified = time(); // Prevent changes on front page course. if ($data->id == SITEID) { throw new moodle_exception('invalidcourse', 'error'); } $oldcourse = course_get_format($data->id)->get_course(); $context = context_course::instance($oldcourse->id); if ($editoroptions) { $data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course', 'summary', 0); } if ($overviewfilesoptions = course_overviewfiles_options($data->id)) { $data = file_postupdate_standard_filemanager($data, 'overviewfiles', $overviewfilesoptions, $context, 'course', 'overviewfiles', 0); } // Check we don't have a duplicate shortname. if (!empty($data->shortname) && $oldcourse->shortname != $data->shortname) { if ($DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data->shortname, $data->id))) { throw new moodle_exception('shortnametaken', '', '', $data->shortname); } } // Check we don't have a duplicate idnumber. if (!empty($data->idnumber) && $oldcourse->idnumber != $data->idnumber) { if ($DB->record_exists_sql('SELECT id from {course} WHERE idnumber = ? AND id <> ?', array($data->idnumber, $data->id))) { throw new moodle_exception('courseidnumbertaken', '', '', $data->idnumber); } } if ($errorcode = course_validate_dates((array) $data)) { throw new moodle_exception($errorcode); } if (!isset($data->category) or empty($data->category)) { // prevent nulls and 0 in category field unset($data->category); } $changesincoursecat = $movecat = (isset($data->category) and $oldcourse->category != $data->category); if (!isset($data->visible)) { // data not from form, add missing visibility info $data->visible = $oldcourse->visible; } if ($data->visible != $oldcourse->visible) { // reset the visibleold flag when manually hiding/unhiding course $data->visibleold = $data->visible; $changesincoursecat = true; } else { if ($movecat) { $newcategory = $DB->get_record('course_categories', array('id' => $data->category)); if (empty($newcategory->visible)) { // make sure when moving into hidden category the course is hidden automatically $data->visible = 0; } } } // Update with the new data $DB->update_record('course', $data); // make sure the modinfo cache is reset rebuild_course_cache($data->id); // update course format options with full course data course_get_format($data->id)->update_course_format_options($data, $oldcourse); $course = $DB->get_record('course', array('id' => $data->id)); if ($movecat) { $newparent = context_coursecat::instance($course->category); $context->update_moved($newparent); } $fixcoursesortorder = $movecat || isset($data->sortorder) && $oldcourse->sortorder != $data->sortorder; if ($fixcoursesortorder) { fix_course_sortorder(); } // purge appropriate caches in case fix_course_sortorder() did not change anything cache_helper::purge_by_event('changesincourse'); if ($changesincoursecat) { cache_helper::purge_by_event('changesincoursecat'); } // Test for and remove blocks which aren't appropriate anymore blocks_remove_inappropriate($course); // Save any custom role names. save_local_role_names($course->id, $data); // update enrol settings enrol_course_updated(false, $course, $data); // Update course tags. if (isset($data->tags)) { core_tag_tag::set_item_tags('core', 'course', $course->id, context_course::instance($course->id), $data->tags); } // Trigger a course updated event. $event = \core\event\course_updated::create(array('objectid' => $course->id, 'context' => context_course::instance($course->id), 'other' => array('shortname' => $course->shortname, 'fullname' => $course->fullname))); $event->set_legacy_logdata(array($course->id, 'course', 'update', 'edit.php?id=' . $course->id, $course->id)); $event->trigger(); if ($oldcourse->format !== $course->format) { // Remove all options stored for the previous format // We assume that new course format migrated everything it needed watching trigger // 'course_updated' and in method format_XXX::update_course_format_options() $DB->delete_records('course_format_options', array('courseid' => $course->id, 'format' => $oldcourse->format)); } }
/** * Validation. * * @param array $data * @param array $files * @return array the errors that were found */ public function validation($data, $files) { global $DB; $errors = parent::validation($data, $files); if ($errorcode = course_validate_dates($data['defaults'])) { $errors['defaults[enddate]'] = get_string($errorcode, 'error'); } return $errors; }
/** * Validates and prepares the data. * * @return bool false is any error occured. */ public function prepare() { global $DB, $SITE; $this->prepared = true; // Validate the shortname. if (!empty($this->shortname) || is_numeric($this->shortname)) { if ($this->shortname !== clean_param($this->shortname, PARAM_TEXT)) { $this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse')); return false; } } $exists = $this->exists(); // Do we want to delete the course? if ($this->options['delete']) { if (!$exists) { $this->error('cannotdeletecoursenotexist', new lang_string('cannotdeletecoursenotexist', 'tool_uploadcourse')); return false; } else { if (!$this->can_delete()) { $this->error('coursedeletionnotallowed', new lang_string('coursedeletionnotallowed', 'tool_uploadcourse')); return false; } } $this->do = self::DO_DELETE; return true; } // Can we create/update the course under those conditions? if ($exists) { if ($this->mode === tool_uploadcourse_processor::MODE_CREATE_NEW) { $this->error('courseexistsanduploadnotallowed', new lang_string('courseexistsanduploadnotallowed', 'tool_uploadcourse')); return false; } else { if ($this->can_update()) { // We can never allow for any front page changes! if ($this->shortname == $SITE->shortname) { $this->error('cannotupdatefrontpage', new lang_string('cannotupdatefrontpage', 'tool_uploadcourse')); return false; } } } } else { if (!$this->can_create()) { $this->error('coursedoesnotexistandcreatenotallowed', new lang_string('coursedoesnotexistandcreatenotallowed', 'tool_uploadcourse')); return false; } } // Basic data. $coursedata = array(); foreach ($this->rawdata as $field => $value) { if (!in_array($field, self::$validfields)) { continue; } else { if ($field == 'shortname') { // Let's leave it apart from now, use $this->shortname only. continue; } } $coursedata[$field] = $value; } $mode = $this->mode; $updatemode = $this->updatemode; $usedefaults = $this->can_use_defaults(); // Resolve the category, and fail if not found. $errors = array(); $catid = tool_uploadcourse_helper::resolve_category($this->rawdata, $errors); if (empty($errors)) { $coursedata['category'] = $catid; } else { foreach ($errors as $key => $message) { $this->error($key, $message); } return false; } // If the course does not exist, or will be forced created. if (!$exists || $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) { // Mandatory fields upon creation. $errors = array(); foreach (self::$mandatoryfields as $field) { if ((!isset($coursedata[$field]) || $coursedata[$field] === '') && (!isset($this->defaults[$field]) || $this->defaults[$field] === '')) { $errors[] = $field; } } if (!empty($errors)) { $this->error('missingmandatoryfields', new lang_string('missingmandatoryfields', 'tool_uploadcourse', implode(', ', $errors))); return false; } } // Should the course be renamed? if (!empty($this->options['rename']) || is_numeric($this->options['rename'])) { if (!$this->can_update()) { $this->error('canonlyrenameinupdatemode', new lang_string('canonlyrenameinupdatemode', 'tool_uploadcourse')); return false; } else { if (!$exists) { $this->error('cannotrenamecoursenotexist', new lang_string('cannotrenamecoursenotexist', 'tool_uploadcourse')); return false; } else { if (!$this->can_rename()) { $this->error('courserenamingnotallowed', new lang_string('courserenamingnotallowed', 'tool_uploadcourse')); return false; } else { if ($this->options['rename'] !== clean_param($this->options['rename'], PARAM_TEXT)) { $this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse')); return false; } else { if ($this->exists($this->options['rename'])) { $this->error('cannotrenameshortnamealreadyinuse', new lang_string('cannotrenameshortnamealreadyinuse', 'tool_uploadcourse')); return false; } else { if (isset($coursedata['idnumber']) && $DB->count_records_select('course', 'idnumber = :idn AND shortname != :sn', array('idn' => $coursedata['idnumber'], 'sn' => $this->shortname)) > 0) { $this->error('cannotrenameidnumberconflict', new lang_string('cannotrenameidnumberconflict', 'tool_uploadcourse')); return false; } } } } } } $coursedata['shortname'] = $this->options['rename']; $this->status('courserenamed', new lang_string('courserenamed', 'tool_uploadcourse', array('from' => $this->shortname, 'to' => $coursedata['shortname']))); } // Should we generate a shortname? if (empty($this->shortname) && !is_numeric($this->shortname)) { if (empty($this->importoptions['shortnametemplate'])) { $this->error('missingshortnamenotemplate', new lang_string('missingshortnamenotemplate', 'tool_uploadcourse')); return false; } else { if (!$this->can_only_create()) { $this->error('cannotgenerateshortnameupdatemode', new lang_string('cannotgenerateshortnameupdatemode', 'tool_uploadcourse')); return false; } else { $newshortname = tool_uploadcourse_helper::generate_shortname($coursedata, $this->importoptions['shortnametemplate']); if (is_null($newshortname)) { $this->error('generatedshortnameinvalid', new lang_string('generatedshortnameinvalid', 'tool_uploadcourse')); return false; } else { if ($this->exists($newshortname)) { if ($mode === tool_uploadcourse_processor::MODE_CREATE_NEW) { $this->error('generatedshortnamealreadyinuse', new lang_string('generatedshortnamealreadyinuse', 'tool_uploadcourse')); return false; } $exists = true; } } $this->status('courseshortnamegenerated', new lang_string('courseshortnamegenerated', 'tool_uploadcourse', $newshortname)); $this->shortname = $newshortname; } } } // If exists, but we only want to create courses, increment the shortname. if ($exists && $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) { $original = $this->shortname; $this->shortname = tool_uploadcourse_helper::increment_shortname($this->shortname); $exists = false; if ($this->shortname != $original) { $this->status('courseshortnameincremented', new lang_string('courseshortnameincremented', 'tool_uploadcourse', array('from' => $original, 'to' => $this->shortname))); if (isset($coursedata['idnumber'])) { $originalidn = $coursedata['idnumber']; $coursedata['idnumber'] = tool_uploadcourse_helper::increment_idnumber($coursedata['idnumber']); if ($originalidn != $coursedata['idnumber']) { $this->status('courseidnumberincremented', new lang_string('courseidnumberincremented', 'tool_uploadcourse', array('from' => $originalidn, 'to' => $coursedata['idnumber']))); } } } } // If the course does not exist, ensure that the ID number is not taken. if (!$exists && isset($coursedata['idnumber'])) { if ($DB->count_records_select('course', 'idnumber = :idn', array('idn' => $coursedata['idnumber'])) > 0) { $this->error('idnumberalreadyinuse', new lang_string('idnumberalreadyinuse', 'tool_uploadcourse')); return false; } } // Course start date. if (!empty($coursedata['startdate'])) { $coursedata['startdate'] = strtotime($coursedata['startdate']); } // Course end date. if (!empty($coursedata['enddate'])) { $coursedata['enddate'] = strtotime($coursedata['enddate']); } // Ultimate check mode vs. existence. switch ($mode) { case tool_uploadcourse_processor::MODE_CREATE_NEW: case tool_uploadcourse_processor::MODE_CREATE_ALL: if ($exists) { $this->error('courseexistsanduploadnotallowed', new lang_string('courseexistsanduploadnotallowed', 'tool_uploadcourse')); return false; } break; case tool_uploadcourse_processor::MODE_UPDATE_ONLY: if (!$exists) { $this->error('coursedoesnotexistandcreatenotallowed', new lang_string('coursedoesnotexistandcreatenotallowed', 'tool_uploadcourse')); return false; } // No break! // No break! case tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE: if ($exists) { if ($updatemode === tool_uploadcourse_processor::UPDATE_NOTHING) { $this->error('updatemodedoessettonothing', new lang_string('updatemodedoessettonothing', 'tool_uploadcourse')); return false; } } break; default: // O_o Huh?! This should really never happen here! $this->error('unknownimportmode', new lang_string('unknownimportmode', 'tool_uploadcourse')); return false; } // Get final data. if ($exists) { $missingonly = $updatemode === tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS; $coursedata = $this->get_final_update_data($coursedata, $usedefaults, $missingonly); // Make sure we are not trying to mess with the front page, though we should never get here! if ($coursedata['id'] == $SITE->id) { $this->error('cannotupdatefrontpage', new lang_string('cannotupdatefrontpage', 'tool_uploadcourse')); return false; } $this->do = self::DO_UPDATE; } else { $coursedata = $this->get_final_create_data($coursedata); $this->do = self::DO_CREATE; } // Validate course start and end dates. if ($exists) { // We also check existing start and end dates if we are updating an existing course. $existingdata = $DB->get_record('course', array('shortname' => $this->shortname)); if (empty($coursedata['startdate'])) { $coursedata['startdate'] = $existingdata->startdate; } if (empty($coursedata['enddate'])) { $coursedata['enddate'] = $existingdata->enddate; } } if ($errorcode = course_validate_dates($coursedata)) { $this->error($errorcode, new lang_string($errorcode, 'error')); return false; } // Add role renaming. $errors = array(); $rolenames = tool_uploadcourse_helper::get_role_names($this->rawdata, $errors); if (!empty($errors)) { foreach ($errors as $key => $message) { $this->error($key, $message); } return false; } foreach ($rolenames as $rolekey => $rolename) { $coursedata[$rolekey] = $rolename; } // Some validation. if (!empty($coursedata['format']) && !in_array($coursedata['format'], tool_uploadcourse_helper::get_course_formats())) { $this->error('invalidcourseformat', new lang_string('invalidcourseformat', 'tool_uploadcourse')); return false; } // Saving data. $this->data = $coursedata; $this->enrolmentdata = tool_uploadcourse_helper::get_enrolment_data($this->rawdata); if (isset($this->rawdata['tags']) && strval($this->rawdata['tags']) !== '') { $this->data['tags'] = preg_split('/\\s*,\\s*/', trim($this->rawdata['tags']), -1, PREG_SPLIT_NO_EMPTY); } // Restore data. // TODO Speed up things by not really extracting the backup just yet, but checking that // the backup file or shortname passed are valid. Extraction should happen in proceed(). $this->restoredata = $this->get_restore_content_dir(); if ($this->restoredata === false) { return false; } // We can only reset courses when allowed and we are updating the course. if ($this->importoptions['reset'] || $this->options['reset']) { if ($this->do !== self::DO_UPDATE) { $this->error('canonlyresetcourseinupdatemode', new lang_string('canonlyresetcourseinupdatemode', 'tool_uploadcourse')); return false; } else { if (!$this->can_reset()) { $this->error('courseresetnotallowed', new lang_string('courseresetnotallowed', 'tool_uploadcourse')); return false; } } } return true; }
/** * Validation. * * @param array $data * @param array $files * @return array the errors that were found */ function validation($data, $files) { global $DB; $errors = parent::validation($data, $files); // Add field validation check for duplicate shortname. if ($course = $DB->get_record('course', array('shortname' => $data['shortname']), '*', IGNORE_MULTIPLE)) { if (empty($data['id']) || $course->id != $data['id']) { $errors['shortname'] = get_string('shortnametaken', '', $course->fullname); } } // Add field validation check for duplicate idnumber. if (!empty($data['idnumber']) && (empty($data['id']) || $this->course->idnumber != $data['idnumber'])) { if ($course = $DB->get_record('course', array('idnumber' => $data['idnumber']), '*', IGNORE_MULTIPLE)) { if (empty($data['id']) || $course->id != $data['id']) { $errors['idnumber'] = get_string('courseidnumbertaken', 'error', $course->fullname); } } } if ($errorcode = course_validate_dates($data)) { $errors['enddate'] = get_string($errorcode, 'error'); } $errors = array_merge($errors, enrol_course_edit_validation($data, $this->context)); $courseformat = course_get_format((object) array('format' => $data['format'])); $formaterrors = $courseformat->edit_form_validation($data, $files, $errors); if (!empty($formaterrors) && is_array($formaterrors)) { $errors = array_merge($errors, $formaterrors); } return $errors; }
/** * Validation. * * @param array $data * @param array $files * @return array the errors that were found */ public function validation($data, $files) { global $DB; $course = get_course($data['id']); $errors = parent::validation($data, $files); // We check the values that would be used as start and end. if ($data['reset_start_date'] != 0) { $coursedata['startdate'] = $data['reset_start_date']; } else { $coursedata['startdate'] = $course->startdate; } if ($data['reset_end_date'] != 0) { // End date set by the user has preference. $coursedata['enddate'] = $data['reset_end_date']; } else { if ($data['reset_start_date'] > 0 && $course->enddate != 0) { // Otherwise, if the current course enddate is set, reset_course_userdata will add the start date time shift to it. $timeshift = $data['reset_start_date'] - usergetmidnight($course->startdate); $coursedata['enddate'] = $course->enddate + $timeshift; } else { $coursedata['enddate'] = $course->enddate; } } if ($errorcode = course_validate_dates($coursedata)) { $errors['reset_end_date'] = get_string($errorcode, 'error'); } return $errors; }