require_once($CFG->libdir.'/classes/component.php');
require_once($CFG->libdir.'/classes/text.php');
+require_once($CFG->libdir.'/classes/string_manager.php');
+require_once($CFG->libdir.'/classes/string_manager_install.php');
+require_once($CFG->libdir.'/classes/string_manager_standard.php');
require_once($CFG->libdir.'/installlib.php');
require_once($CFG->libdir.'/clilib.php');
require_once($CFG->libdir.'/setuplib.php');
require_once($CFG->libdir.'/adminlib.php');
$confirm = optional_param('confirm', 0, PARAM_BOOL);
+$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
-admin_externalpage_setup('purgecaches');
-
-require_login();
-require_capability('moodle/site:config', context_system::instance());
-
-if ($confirm) {
- require_sesskey();
+// If we have got here as a confirmed aciton, do it.
+if ($confirm && isloggedin() && confirm_sesskey()) {
+ require_capability('moodle/site:config', context_system::instance());
- // Valid request. Purge, and redisplay the form so it is easy to purge again
- // in the near future.
+ // Valid request. Purge, and redirect the user back to where they came from.
purge_all_caches();
- redirect(new moodle_url('/admin/purgecaches.php'), get_string('purgecachesfinished', 'admin'));
-
-} else {
- // Show a confirm form.
- echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('purgecaches', 'admin'));
-
- $url = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
- $button = new single_button($url, get_string('purgecaches','admin'), 'post');
-
- // Cancel button takes them back to the page the were on, if possible,
- // otherwise to the site home page.
- $return = new moodle_url('/');
- if (isset($_SERVER['HTTP_REFERER']) and !empty($_SERVER['HTTP_REFERER'])) {
- if ($_SERVER['HTTP_REFERER'] !== "$CFG->wwwroot/$CFG->admin/purgecaches.php") {
- $return = $_SERVER['HTTP_REFERER'];
- }
+
+ if ($returnurl) {
+ $returnurl = $CFG->wwwroot . $returnurl;
+ } else {
+ $returnurl = new moodle_url('/admin/purgecaches.php');
}
+ redirect($returnurl, get_string('purgecachesfinished', 'admin'));
+}
- echo $OUTPUT->confirm(get_string('purgecachesconfirm', 'admin'), $button, $return);
- echo $OUTPUT->footer();
+// Otherwise, show a button to actually purge the caches.
+admin_externalpage_setup('purgecaches');
+
+$actionurl = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
+if ($returnurl) {
+ $actionurl->param('returnurl', $returnurl);
}
+
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('purgecaches', 'admin'));
+
+echo $OUTPUT->box_start('generalbox', 'notice');
+echo html_writer::tag('p', get_string('purgecachesconfirm', 'admin'));
+echo $OUTPUT->single_button($actionurl, get_string('purgecaches', 'admin'), 'post');
+echo $OUTPUT->box_end();
+
+echo $OUTPUT->footer();
if (optional_param('submit', false, PARAM_BOOL) && data_submitted() && confirm_sesskey()) {
$controller->process_submission();
$syscontext->mark_dirty();
- add_to_log(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl), '', '', $USER->id);
+ $event = null;
+ // Create event depending on mode.
+ switch ($mode) {
+ case 'assign':
+ $event = \core\event\role_allow_assign_updated::create(array('context' => $syscontext));
+ break;
+ case 'override':
+ $event = \core\event\role_allow_override_updated::create(array('context' => $syscontext));
+ break;
+ case 'switch':
+ $event = \core\event\role_allow_switch_updated::create(array('context' => $syscontext));
+ break;
+ }
+ if ($event) {
+ $event->trigger();
+ }
redirect($baseurl);
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
- $rolename = $assignableroles[$roleid];
- add_to_log($course->id, 'role', 'assign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
// Counts have changed, so reload.
list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true);
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
- $rolename = $assignableroles[$roleid];
- add_to_log($course->id, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
// Counts have changed, so reload.
list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true);
}
// Process submission in necessary.
if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey() && $definitiontable->is_submission_valid()) {
$definitiontable->save_changes();
- add_to_log(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' .
- $definitiontable->get_role_id(), $definitiontable->get_role_name(), '', $USER->id);
+ $tableroleid = $definitiontable->get_role_id();
+ // Trigger event.
+ $event = \core\event\role_capabilities_updated::create(
+ array(
+ 'context' => $systemcontext,
+ 'objectid' => $roleid,
+ 'other' => array('name' => $definitiontable->get_role_name())
+ )
+ );
+ $event->set_legacy_logdata(array(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' . $tableroleid,
+ $definitiontable->get_role_name(), '', $USER->id));
+ if (!empty($role)) {
+ $event->add_record_snapshot('role', $role);
+ }
+ $event->trigger();
+
if ($action === 'add') {
redirect(new moodle_url('/admin/roles/define.php', array('action'=>'view', 'roleid'=>$definitiontable->get_role_id())));
} else {
}
// Deleted a role sitewide...
$systemcontext->mark_dirty();
- add_to_log(SITEID, 'role', 'delete', 'admin/roles/manage.php', $roles[$roleid]->localname, '', $USER->id);
redirect($baseurl);
break;
if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
$overridestable->save_changes();
$rolename = $overridableroles[$roleid];
- add_to_log($course->id, 'role', 'override', 'admin/roles/override.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
+ // Trigger event.
+ $event = \core\event\role_capabilities_updated::create(
+ array(
+ 'context' => $context,
+ 'objectid' => $roleid,
+ 'courseid' => $courseid,
+ 'other' => array('name' => $rolename)
+ )
+ );
+
+ $event->set_legacy_logdata(
+ array(
+ $course->id, 'role', 'override', 'admin/roles/override.php?contextid=' . $context->id . '&roleid=' . $roleid,
+ $rolename, '', $USER->id
+ )
+ );
+ $event->add_record_snapshot('role', $role);
+ $event->trigger();
+
redirect($returnurl);
}
// "performance" settingpage
$temp = new admin_settingpage('performance', new lang_string('performance', 'admin'));
+// Memory limit options for large administration tasks.
+$memoryoptions = array(
+ '64M' => '64M',
+ '128M' => '128M',
+ '256M' => '256M',
+ '512M' => '512M',
+ '1024M' => '1024M',
+ '2048M' => '2048M');
+
+// Allow larger memory usage for 64-bit sites only.
+if (PHP_INT_SIZE === 8) {
+ $memoryoptions['3072M'] = '3072M';
+ $memoryoptions['4096M'] = '4096M';
+}
+
$temp->add(new admin_setting_configselect('extramemorylimit', new lang_string('extramemorylimit', 'admin'),
new lang_string('configextramemorylimit', 'admin'), '512M',
- // if this option is set to 0, default 128M will be used
- array( '64M' => '64M',
- '128M' => '128M',
- '256M' => '256M',
- '512M' => '512M',
- '1024M' => '1024M',
- '2048M' => '2048M',
- )));
+ $memoryoptions));
+
$temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache', 'admin'),
new lang_string('configcurlcache', 'admin'), 120, PARAM_INT));
And I should see "Grouping 1"
And I should see "Grouping 2"
+ @javascript
+ Scenario: Role overrides
+ Given the following "users" exists:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@asd.com |
+ | student1 | Student | 1 | student1@asd.com |
+ And the following "categories" exists:
+ | name | category | idnumber |
+ | Cat 1 | 0 | CAT1 |
+ And the following "courses" exists:
+ | fullname | shortname |
+ | Course 1 | C1 |
+ And the following "course enrolments" exists:
+ | user | course | role |
+ | student1 | C1 | student |
+ | teacher1 | C1 | editingteacher |
+ And the following "permission overrides" exists:
+ | capability | permission | role | contextlevel | reference |
+ | mod/forum:editanypost | Allow | student | Course | C1 |
+ | mod/forum:replynews | Prevent | editingteacher | Course | C1 |
+ When I log in as "admin"
+ And I follow "Course 1"
+ And I expand "Users" node
+ And I follow "Permissions"
+ And I select "Student (1)" from "Advanced role override"
+ Then the "mod/forum:editanypost" field should match "1" value
+ And I press "Cancel"
+ And I select "Teacher (1)" from "Advanced role override"
+ And the "mod/forum:replynews" field should match "-1" value
+ And I press "Cancel"
+
Scenario: Add course enrolments
Given the following "users" exists:
| username | firstname | lastname | email |
$mform->addHelpButton('restrictedusers', 'restrictedusers', 'webservice');
$mform->setType('restrictedusers', PARAM_BOOL);
- //can users download files
+ // Can users download files?
$mform->addElement('advcheckbox', 'downloadfiles', get_string('downloadfiles', 'webservice'));
$mform->setAdvanced('downloadfiles');
$mform->addHelpButton('downloadfiles', 'downloadfiles', 'webservice');
$mform->setType('downloadfiles', PARAM_BOOL);
+ // Can users upload files?
+ $mform->addElement('advcheckbox', 'uploadfiles', get_string('uploadfiles', 'webservice'));
+ $mform->setAdvanced('uploadfiles');
+ $mform->addHelpButton('uploadfiles', 'uploadfiles', 'webservice');
+
/// needed to select automatically the 'No required capability" option
$currentcapabilityexist = false;
if (empty($service->requiredcapability)) {
return $errors;
}
-}
\ No newline at end of file
+}
print_error('unknownbackuptype');
}
+// Backup of large courses requires extra memory. Use the amount configured
+// in admin settings.
+raise_memory_limit(MEMORY_EXTRA);
+
if (!($bc = backup_ui::load_controller($backupid))) {
$bc = new backup_controller($type, $id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id);
require_login($course, null, $cm);
require_capability('moodle/restore:restorecourse', $context);
+// Restore of large courses requires extra memory. Use the amount configured
+// in admin settings.
+raise_memory_limit(MEMORY_EXTRA);
+
if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
$restore = restore_ui::engage_independent_stage($stage, $contextid);
} else {
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Local stuff for category enrolment plugin.
+ *
+ * @package core_badges
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Event observer for badges.
+ */
+class core_badges_observer {
+ /**
+ * Triggered when 'course_module_completion_updated' event is triggered.
+ *
+ * @param \core\event\course_module_completion_updated $event
+ */
+ public static function course_module_criteria_review(\core\event\course_module_completion_updated $event) {
+ global $DB, $CFG;
+
+ if (!empty($CFG->enablebadges)) {
+ require_once($CFG->dirroot.'/lib/badgeslib.php');
+
+ $eventdata = $event->get_record_snapshot('course_modules_completion', $event->objectid);
+ $userid = $event->other['relateduserid'];
+ $mod = $eventdata->coursemoduleid;
+
+ if ($eventdata->completionstate == COMPLETION_COMPLETE
+ || $eventdata->completionstate == COMPLETION_COMPLETE_PASS
+ || $eventdata->completionstate == COMPLETION_COMPLETE_FAIL) {
+ // Need to take into account that there can be more than one badge with the same activity in its criteria.
+ if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'module_' . $mod, 'value' => $mod))) {
+ foreach ($rs as $r) {
+ $bid = $DB->get_field('badge_criteria', 'badgeid', array('id' => $r->critid), MUST_EXIST);
+ $badge = new badge($bid);
+ if (!$badge->is_active() || $badge->is_issued($userid)) {
+ continue;
+ }
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->mark_complete($userid);
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
+ $badge->issue($userid);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Triggered when 'course_completed' event is triggered.
+ *
+ * @param \core\event\course_completed $event
+ */
+ public static function course_criteria_review(\core\event\course_completed $event) {
+ global $DB, $CFG;
+
+ if (!empty($CFG->enablebadges)) {
+ require_once($CFG->dirroot.'/lib/badgeslib.php');
+
+ $eventdata = $event->get_record_snapshot('course_completions', $event->objectid);
+ $userid = $event->other['relateduserid'];
+ $courseid = $event->courseid;
+
+ // Need to take into account that course can be a part of course_completion and courseset_completion criteria.
+ if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'course_' . $courseid, 'value' => $courseid))) {
+ foreach ($rs as $r) {
+ $crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
+ $badge = new badge($crit->badgeid);
+ if (!$badge->is_active() || $badge->is_issued($userid)) {
+ continue;
+ }
+
+ if ($badge->criteria[$crit->criteriatype]->review($userid)) {
+ $badge->criteria[$crit->criteriatype]->mark_complete($userid);
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
+ $badge->issue($userid);
+ }
+ }
+ }
+ }
+ }
+ }
+}
class core_badgeslib_testcase extends advanced_testcase {
protected $badgeid;
+ protected $course;
+ protected $user;
+ protected $module;
+ protected $coursebadge;
protected function setUp() {
- global $DB;
+ global $DB, $CFG;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$fordb->status = BADGE_STATUS_INACTIVE;
$this->badgeid = $DB->insert_record('badge', $fordb, true);
+
+ // Create a course with activity and auto completion tracking.
+ $this->course = $this->getDataGenerator()->create_course();
+ $this->user = $this->getDataGenerator()->create_user();
+ $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+ $this->assertNotEmpty($studentrole);
+
+ // Get manual enrolment plugin and enrol user.
+ require_once($CFG->dirroot.'/enrol/manual/locallib.php');
+ $manplugin = enrol_get_plugin('manual');
+ $maninstance = $DB->get_record('enrol', array('courseid' => $this->course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
+ $manplugin->enrol_user($maninstance, $this->user->id, $studentrole->id);
+ $this->assertEquals(1, $DB->count_records('user_enrolments'));
+
+ $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
+ $this->module = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+
+ // Build badge and criteria.
+ $fordb->type = BADGE_TYPE_COURSE;
+ $fordb->courseid = $this->course->id;
+ $fordb->status = BADGE_STATUS_ACTIVE;
+
+ $this->coursebadge = $DB->insert_record('badge', $fordb, true);
}
public function test_create_badge() {
$this->assertEquals(badge_message_from_template($message, $params), $result);
}
+ /**
+ * Test badges observer when course module completion event id fired.
+ */
+ public function test_badges_observer_course_module_criteria_review() {
+ $badge = new badge($this->coursebadge);
+ $this->assertFalse($badge->is_issued($this->user->id));
+
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'module_'.$this->module->id => $this->module->id));
+
+ // Set completion for forum activity.
+ $c = new completion_info($this->course);
+ $activities = $c->get_activities();
+ $this->assertEquals(1, count($activities));
+ $this->assertTrue(isset($activities[$this->module->cmid]));
+ $this->assertEquals($activities[$this->module->cmid]->name, $this->module->name);
+
+ $current = $c->get_data($activities[$this->module->cmid], false, $this->user->id);
+ $current->completionstate = COMPLETION_COMPLETE;
+ $current->timemodified = time();
+ $c->internal_set_data($activities[$this->module->cmid], $current);
+
+ // Check if badge is awarded.
+ $this->assertDebuggingCalled('Error baking badge image!');
+ $this->assertTrue($badge->is_issued($this->user->id));
+ }
+
+ /**
+ * Test badges observer when course_completed event is fired.
+ */
+ public function test_badges_observer_course_criteria_review() {
+ $badge = new badge($this->coursebadge);
+ $this->assertFalse($badge->is_issued($this->user->id));
+
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
+ $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COURSE, 'badgeid' => $badge->id));
+ $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'course_'.$this->course->id => $this->course->id));
+
+ $ccompletion = new completion_completion(array('course' => $this->course->id, 'userid' => $this->user->id));
+
+ // Mark course as complete.
+ $ccompletion->mark_complete();
+
+ // Check if badge is awarded.
+ $this->assertDebuggingCalled('Error baking badge image!');
+ $this->assertTrue($badge->is_issued($this->user->id));
+ }
}
$events = calendar_get_upcoming($courses, $group, $user, $lookahead, $maxevents);
if (!empty($this->instance)) {
- $this->content->text = calendar_get_block_upcoming($events, 'view.php?view=day&course='.$courseshown.'&');
+ $link = 'view.php?view=day&course='.$courseshown.'&';
+ $showcourselink = ($this->page->course->id == SITEID);
+ $this->content->text = calendar_get_block_upcoming($events, $link, $showcourselink);
}
if (empty($this->content->text)) {
$this->delete_attachments();
$this->remove_associations();
+ // Get record to pass onto the event.
+ $record = $DB->get_record('post', array('id' => $this->id));
$DB->delete_records('post', array('id' => $this->id));
tag_set('post', $this->id, array());
- add_to_log(SITEID, 'blog', 'delete', 'index.php?userid='. $this->userid, 'deleted blog entry with entry id# '. $this->id);
- events_trigger('blog_entry_deleted', $this);
+ $event = \core\event\blog_entry_deleted::create(array('objectid' => $this->id,
+ 'userid' => $this->userid,
+ 'other' => array("record" => (array)$record)
+ ));
+ $event->add_record_snapshot("post", $record);
+ $event->set_custom_data($this);
+ $event->trigger();
}
/**
* Test various blog related events.
*/
public function test_blog_entry_events() {
- global $USER;
+ global $USER, $DB;
$this->setAdminUser();
$this->resetAfterTest();
$this->assertEquals($blog->id, $event->objectid);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals("post", $event->objecttable);
+
+ // Delete a blog entry.
+ $record = $DB->get_record('post', array('id' => $blog->id));
+ $blog->delete();
+ $events = $sink->get_events();
+ $event = array_pop($events);
+
+ // Validate event data.
+ $this->assertInstanceOf('\core\event\blog_entry_deleted', $event);
+ $this->assertEquals(context_system::instance()->id, $event->contextid);
+ $this->assertEquals($blog->id, $event->objectid);
+ $this->assertEquals($USER->id, $event->userid);
+ $this->assertEquals("post", $event->objecttable);
+ $this->assertEquals($record, $event->get_record_snapshot("post", $blog->id));
+ $this->assertSame('blog_entry_deleted', $event->get_legacy_eventname());
+
}
}
}
$class = 'cachestore_'.$plugin;
if (!class_exists($class)) {
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid plugin name specified. The plugin does not exist or is not valid.');
}
}
$class = 'cachelock_'.$plugin;
if (!class_exists($class)) {
- $plugins = get_plugin_list_with_file('cachelock', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachelock', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid lock name specified. The plugin does not exist or is not valid.');
}
if (!array_key_exists($name, $this->configstores)) {
throw new cache_exception('The requested instance does not exist.');
}
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid plugin name specified. The plugin either does not exist or is not valid.');
}
if (!$coreonly) {
$plugintypes = core_component::get_plugin_types();
foreach ($plugintypes as $type => $location) {
- $plugins = get_plugin_list_with_file($type, 'db/caches.php');
+ $plugins = core_component::get_plugin_list_with_file($type, 'db/caches.php');
foreach ($plugins as $plugin => $filepath) {
$component = clean_param($type.'_'.$plugin, PARAM_COMPONENT); // Standardised plugin name.
$files[$component] = $filepath;
*/
public static function get_store_plugin_summaries() {
$return = array();
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php', true);
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php', true);
foreach ($plugins as $plugin => $path) {
$class = 'cachestore_'.$plugin;
$return[$plugin] = array(
$strtested = new lang_string('tested', 'cache');
$strnotready = new lang_string('storenotready', 'cache');
-foreach (get_plugin_list_with_file('cachestore', 'lib.php', true) as $plugin => $path) {
+foreach (core_component::get_plugin_list_with_file('cachestore', 'lib.php', true) as $plugin => $path) {
$class = 'cachestore_'.$plugin;
$plugin = get_string('pluginname', 'cachestore_'.$plugin);
return $output;
}
+
+/**
+ * Get a HTML link to a course.
+ *
+ * @param int $courseid the course id
+ * @return string a link to the course (as HTML); empty if the course id is invalid
+ */
+function calendar_get_courselink($courseid) {
+
+ if (!$courseid) {
+ return '';
+ }
+
+ calendar_get_course_cached($coursecache, $courseid);
+ $context = context_course::instance($courseid);
+ $fullname = format_string($coursecache[$courseid]->fullname, true, array('context' => $context));
+ $url = new moodle_url('/course/view.php', array('id' => $courseid));
+ $link = html_writer::link($url, $fullname);
+
+ return $link;
+}
+
+
/**
* Add calendar event metadata
*
}
$icon = $OUTPUT->pix_url('icon', $event->modulename) . '';
- $context = context_course::instance($module->course);
- $fullname = format_string($coursecache[$module->course]->fullname, true, array('context' => $context));
-
$event->icon = '<img src="'.$icon.'" alt="'.$eventtype.'" title="'.$modulename.'" class="icon" />';
$event->referer = '<a href="'.$CFG->wwwroot.'/mod/'.$event->modulename.'/view.php?id='.$module->id.'">'.$event->name.'</a>';
- $event->courselink = '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$module->course.'">'.$fullname.'</a>';
+ $event->courselink = calendar_get_courselink($module->course);
$event->cmid = $module->id;
-
} else if($event->courseid == SITEID) { // Site event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/siteevent') . '" alt="'.get_string('globalevent', 'calendar').'" class="icon" />';
$event->cssclass = 'calendar_event_global';
} else if($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event
- calendar_get_course_cached($coursecache, $event->courseid);
-
- $context = context_course::instance($event->courseid);
- $fullname = format_string($coursecache[$event->courseid]->fullname, true, array('context' => $context));
-
$event->icon = '<img src="'.$OUTPUT->pix_url('i/courseevent') . '" alt="'.get_string('courseevent', 'calendar').'" class="icon" />';
- $event->courselink = '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$event->courseid.'">'.$fullname.'</a>';
+ $event->courselink = calendar_get_courselink($event->courseid);
$event->cssclass = 'calendar_event_course';
} else if ($event->groupid) { // Group event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/groupevent') . '" alt="'.get_string('groupevent', 'calendar').'" class="icon" />';
+ $event->courselink = calendar_get_courselink($event->courseid);
$event->cssclass = 'calendar_event_group';
} else if($event->userid) { // User event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/userevent') . '" alt="'.get_string('userevent', 'calendar').'" class="icon" />';
*
* @param array $events list of events
* @param moodle_url|string $linkhref link to event referer
+ * @param boolean $showcourselink whether links to courses should be shown
* @return string|null $content html block content
*/
-function calendar_get_block_upcoming($events, $linkhref = NULL) {
+function calendar_get_block_upcoming($events, $linkhref = NULL, $showcourselink = false) {
$content = '';
$lines = count($events);
if (!$lines) {
}
}
$events[$i]->time = str_replace('»', '<br />»', $events[$i]->time);
+ if ($showcourselink && !empty($events[$i]->courselink)) {
+ $content .= html_writer::div($events[$i]->courselink, 'course');
+ }
$content .= '<div class="date">'.$events[$i]->time.'</div></div>';
if ($i < $lines - 1) $content .= '<hr />';
}
* @return void
*/
public function mark_complete($timecomplete = null) {
+ global $USER;
- // Never change a completion time
+ // Never change a completion time.
if ($this->timecompleted) {
return;
}
- // Use current time if nothing supplied
+ // Use current time if nothing supplied.
if (!$timecomplete) {
$timecomplete = time();
}
- // Set time complete
+ // Set time complete.
$this->timecompleted = $timecomplete;
- // Save record
+ // Save record.
if ($result = $this->_save()) {
- events_trigger('course_completed', $this->get_record_data());
+ $data = $this->get_record_data();
+ $event = \core\event\course_completed::create(
+ array(
+ 'objectid' => $data->id,
+ 'userid' => $USER->id,
+ 'context' => context_course::instance($data->course),
+ 'courseid' => $data->course,
+ 'other' => array('relateduserid' => $data->userid)
+ )
+ );
+ $event->add_record_snapshot('course_completions', $data);
+ $event->trigger();
}
return $result;
// Locking resolves race conditions and is strongly recommended for production servers.
// $CFG->preventfilelocking = false;
//
-// If $CFG->langstringcache is enabled (which should always be in production
-// environment), Moodle keeps aggregated strings in its own internal format
-// optimised for performance. By default, this on-disk cache is created in
-// $CFG->cachedir/lang. In cluster environment, you may wish to specify
-// an alternative location of this cache so that each web server in the cluster
-// uses its own local cache and does not need to access the shared dataroot.
-// Make sure that the web server process has write permission to this location
-// and that it has permission to remove the folder, too (so that the cache can
-// be pruned).
-//
-// $CFG->langcacheroot = '/var/www/moodle/htdocs/altcache/lang';
-//
-// If $CFG->langcache is enabled (which should always be in production
-// environment), Moodle stores the list of available languages in a cache file.
-// By default, the file $CFG->dataroot/languages is used. You may wish to
-// specify an alternative location of this cache file.
-//
-// $CFG->langmenucachefile = '/var/www/moodle/htdocs/altcache/languages';
-//
// Site default language can be set via standard administration interface. If you
// want to have initial error messages for eventual database connection problems
// localized too, you have to set your language code here.
// Prevent JS caching
// $CFG->jsrev = -1; // NOT FOR PRODUCTION SERVERS!
//
-// Prevent core_string_manager on-disk cache
+// Prevent core_string_manager application caching
// $CFG->langstringcache = false; // NOT FOR PRODUCTION SERVERS!
//
// When working with production data on test servers, no emails or other messages
function make_categories_options() {
global $CFG;
require_once($CFG->libdir. '/coursecatlib.php');
- $cats = coursecat::make_categories_list();
+ $cats = coursecat::make_categories_list('', 0, ' / ');
foreach ($cats as $key => $value) {
- $cats[$key] = str_repeat(' ', coursecat::get($key)->depth - 1). $value;
+ // Prefix the value with the number of spaces equal to category depth (number of separators in the value).
+ $cats[$key] = str_repeat(' ', substr_count($value, ' / ')). $value;
}
return $cats;
}
*
* Updates both tables {course_sections} and {course_modules}
*
+ * Note: This function does not use modinfo PROVIDED that the section you are
+ * adding the module to already exists. If the section does not exist, it will
+ * build modinfo if necessary and create the section.
+ *
* @param int|stdClass $courseorid course id or course object
* @param int $cmid id of the module already existing in course_modules table
* @param int $sectionnum relative number of the section (field course_sections.section)
} else {
$courseid = $courseorid;
}
- course_create_sections_if_missing($courseorid, $sectionnum);
// Do not try to use modinfo here, there is no guarantee it is valid!
- $section = $DB->get_record('course_sections', array('course'=>$courseid, 'section'=>$sectionnum), '*', MUST_EXIST);
+ $section = $DB->get_record('course_sections',
+ array('course' => $courseid, 'section' => $sectionnum), '*', IGNORE_MISSING);
+ if (!$section) {
+ // This function call requires modinfo.
+ course_create_sections_if_missing($courseorid, $sectionnum);
+ $section = $DB->get_record('course_sections',
+ array('course' => $courseid, 'section' => $sectionnum), '*', MUST_EXIST);
+ }
+
$modarray = explode(",", trim($section->sequence));
if (empty($section->sequence)) {
$newsequence = "$cmid";
'markedthistopic',
'move',
'movesection',
+ 'movecontent',
+ 'aftercontent',
+ 'emptydragdropregion'
), 'moodle');
// Include format-specific strings
$this->assertEquals(range(0, $course->numsections + 1), $sectionscreated);
}
+ public function test_course_add_cm_to_section() {
+ global $DB;
+ $this->resetAfterTest(true);
+
+ // Create course with 1 section.
+ $course = $this->getDataGenerator()->create_course(
+ array('shortname' => 'GrowingCourse',
+ 'fullname' => 'Growing Course',
+ 'numsections' => 1),
+ array('createsections' => true));
+
+ // Trash modinfo.
+ rebuild_course_cache($course->id, true);
+
+ // Create some cms for testing.
+ $cmids = array();
+ for ($i=0; $i<4; $i++) {
+ $cmids[$i] = $DB->insert_record('course_modules', array('course' => $course->id));
+ }
+
+ // Add it to section that exists.
+ course_add_cm_to_section($course, $cmids[0], 1);
+
+ // Check it got added to sequence.
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1));
+ $this->assertEquals($cmids[0], $sequence);
+
+ // Add a second, this time using courseid variant of parameters.
+ course_add_cm_to_section($course->id, $cmids[1], 1);
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1));
+ $this->assertEquals($cmids[0] . ',' . $cmids[1], $sequence);
+
+ // Check modinfo was not rebuilt (important for performance if calling
+ // repeatedly).
+ $this->assertNull($DB->get_field('course', 'modinfo', array('id' => $course->id)));
+
+ // Add one to section that doesn't exist (this might rebuild modinfo).
+ course_add_cm_to_section($course, $cmids[2], 2);
+ $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id)));
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2));
+ $this->assertEquals($cmids[2], $sequence);
+
+ // Add using the 'before' option.
+ course_add_cm_to_section($course, $cmids[3], 2, $cmids[2]);
+ $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id)));
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2));
+ $this->assertEquals($cmids[3] . ',' . $cmids[2], $sequence);
+ }
+
public function test_reorder_sections() {
global $DB;
$this->resetAfterTest(true);
resources.addClass(CSS.SECTION);
sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
}
+ resources.setAttribute('data-draggroups', this.groups.join(' '));
// Define empty ul as droptarget, so that item could be moved to empty list
var tar = new Y.DD.Drop({
node: resources,
$filepath = '/';
}
+ // Only allow uploads to draft or private areas (private is deprecated but still supported)
+ if (!($fileinfo['component'] == 'user' and in_array($fileinfo['filearea'], array('private', 'draft')))) {
+ throw new coding_exception('File can be uploaded to user private or draft areas only');
+ } else {
+ $component = 'user';
+ $filearea = $fileinfo['filearea'];
+ }
+
+ $itemid = 0;
if (isset($fileinfo['itemid'])) {
+ $itemid = $fileinfo['itemid'];
+ }
+ if ($filearea == 'draft' && $itemid <= 0) {
+ // Generate a draft area for the files.
+ $itemid = file_get_unused_draft_itemid();
+ } else if ($filearea == 'private') {
// TODO MDL-31116 in user private area, itemid is always 0.
$itemid = 0;
- } else {
- throw new coding_exception('itemid cannot be empty');
}
// We need to preserve backword compatibility. Context id is no more a required.
// Get and validate context.
$context = self::get_context_from_params($fileinfo);
self::validate_context($context);
-
- if (!($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'private')) {
- throw new coding_exception('File can be uploaded to user private area only');
- } else {
- // TODO MDL-31116 hard-coded to use user_private area.
- $component = 'user';
- $filearea = 'private';
+ if (($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'private')) {
+ debugging('Uploading directly to user private files area is deprecated. Upload to a draft area and then move the files with core_user::add_user_private_files');
}
$browser = get_file_browser();
$module = array(
'name'=>'form_filemanager',
'fullpath'=>'/lib/form/filemanager.js',
- 'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+ 'requires' => array('moodle-core-notification-dialogue', 'core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
'strings' => array(
array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
- array('confirmrenamefile', 'repository'), array('newfolder', 'repository')
+ array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle')
)
);
if (empty($filemanagertemplateloaded)) {
<li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" alt="'. get_string('repositoryicon', 'repository') .'" width="16" height="16" /> <span class="{!}fp-repo-name"></span></a></li>
</ul>
</div>
- <div class="fp-repo-items">
+ <div class="fp-repo-items" tabindex="0">
<div class="fp-navbar">
<div>
<div class="{!}fp-toolbar">
$context = context_user::instance($USER->id);
$contextid = $context->id;
$component = "user";
- $filearea = "private";
+ $filearea = "draft";
$itemid = 0;
$filepath = "/";
$filename = "Simple.txt";
$this->assertEmpty($file);
// Call the api to create a file.
- core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
+ $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
$filename, $filecontent, $contextlevel, $instanceid);
+ // Get the created draft item id.
+ $itemid = $fileinfo['itemid'];
// Make sure the file was created.
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertNotEmpty($file);
// Make sure no file exists.
- $itemid = 2;
$filename = "Simple2.txt";
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertEmpty($file);
// Call the api to create a file.
$fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid,
$filepath, $filename, $filecontent, $contextlevel, $instanceid);
-
- // Make sure itemid is always set to 0.
- $this->assertEquals(0, $fileinfo['itemid']);
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
// Let us try creating a file using contextlevel and instance id.
- $itemid = 0;
$filename = "Simple5.txt";
$contextid = 0;
$contextlevel = "user";
$this->assertEmpty($file);
$fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
$filename, $filecontent, $contextlevel, $instanceid);
- $this->assertEmpty($file);
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
// Make sure the same file cannot be created again.
$this->setExpectedException("moodle_exception");
}
/*
- * Make sure only private area is allowed in core_files_external::upload().
+ * Make sure only private or draft areas are allowed in core_files_external::upload().
*/
public function test_upload_param_area() {
global $USER;
$contextid = $context->id;
$component = "user";
$filearea = "draft";
- $itemid = 0;
+ $itemid = file_get_unused_draft_itemid();
$filepath = "/";
$filename = "Simple4.txt";
$filecontent = base64_encode("Let us create a nice simple file");
$contextlevel = null;
$instanceid = null;
- // Make sure exception is thrown.
- $this->setExpectedException("coding_exception");
- core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
- $filename, $filecontent, $contextlevel, $instanceid);
+ // Make sure the file is created.
+ @core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+ $browser = get_file_browser();
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
}
/*
$filename = "Simple4.txt";
$filecontent = base64_encode("Let us create a nice simple file");
- // Make sure the file is created.
@core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+
+ // Assert debugging called (deprecation warning).
+ $this->assertDebuggingCalled();
+
+ // Make sure the file is created.
$browser = get_file_browser();
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertNotEmpty($file);
}
-}
\ No newline at end of file
+}
if ($type == 'grade' and empty($object->id)) {
$object->insert();
}
+ if (!$object->can_control_visibility()) {
+ print_error('componentcontrolsvisibility', 'grades', $returnurl);
+ }
$object->set_hidden(1, true);
}
break;
if ($type == 'grade' and empty($object->id)) {
$object->insert();
}
+ if (!$object->can_control_visibility()) {
+ print_error('componentcontrolsvisibility', 'grades', $returnurl);
+ }
$object->set_hidden(0, true);
}
break;
public $columns = array();
/**
- * @var object $gtree @see grade/lib.php
+ * @var grade_tree $gtree @see grade/lib.php
*/
public $gtree;
public function get_hiding_icon($element, $gpr) {
global $CFG, $OUTPUT;
+ if (!$element['object']->can_control_visibility()) {
+ return '';
+ }
+
if (!has_capability('moodle/grade:manage', $this->context) and
!has_capability('moodle/grade:hide', $this->context)) {
return '';
// Continue with lib loading
require_once($CFG->libdir.'/classes/text.php');
+require_once($CFG->libdir.'/classes/string_manager.php');
+require_once($CFG->libdir.'/classes/string_manager_install.php');
+require_once($CFG->libdir.'/classes/string_manager_standard.php');
require_once($CFG->libdir.'/weblib.php');
require_once($CFG->libdir.'/outputlib.php');
require_once($CFG->libdir.'/dmllib.php');
defined('MOODLE_INTERNAL') || die();
+$string['cannotcreatedboninstall'] = '<p>Die Datenbank konnte nicht angelegt werden.</p><p>Die angegebene Datenbank existiert nicht und das genannten Nutzerkonto hat keine Rechte, die Datenbank neu anzulegen. Die Datenbank-Konfiguration muss überprüft werden.</p>';
$string['cannotcreatelangdir'] = 'Verzeichnis \'lang\' wurde nicht angelegt';
$string['cannotcreatetempdir'] = 'Das Verzeichnis \'temp\' wurde nicht angelegt';
$string['cannotdownloadcomponents'] = 'Einige Komponenten können nicht geladen werden.';
$string['cannotsavezipfile'] = 'Die ZIP-Datei wurde nicht gespeichert';
$string['cannotunzipfile'] = 'Die Datei kann nicht entpackt werden';
$string['componentisuptodate'] = 'Die Komponente ist aktuell.';
+$string['dmlexceptiononinstall'] = '<p>Ein Datenbankfehler ist aufgetreten [{$a->errorcode}]. <br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Die Überprüfung der heruntergeladenen Datei ist gescheitert';
$string['invalidmd5'] = 'Der Prüfwert ist ungültig. Versuchen Sie es bitte nochmal!';
$string['missingrequiredfield'] = 'Einige erforderliche Felder sind nicht ausgefüllt.';
defined('MOODLE_INTERNAL') || die();
+$string['cannotcreatedboninstall'] = '<p>Az adatbázis nem hozható létre.</p> <p>A megadott adatbázis nem létezik, a felhasználó pedig nem jogosult létrehozni egyet.</p> <p>A portál rendszergazdájának ellenőrizni kell az adatbázis-beállításokat.</p>';
$string['cannotcreatelangdir'] = 'Nem hozható létre a lang könyvtár.';
$string['cannotcreatetempdir'] = 'Nem hozható létre a temp könyvtár.';
$string['cannotdownloadcomponents'] = 'Az összetevőket nem lehet letölteni.';
$string['cannotsavezipfile'] = 'A tömörített állományt nem lehet elmenteni.';
$string['cannotunzipfile'] = 'A tömörített állományt nem lehet kicsomagolni.';
$string['componentisuptodate'] = 'Az összetevő a legújabb.';
+$string['dmlexceptiononinstall'] = '<p>Adatbázishiba történt [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'A letöltött állomány ellenőrzése nem sikerült.';
$string['invalidmd5'] = 'Az ellenőrző változó hibás volt – próbálkozzék ismét';
$string['missingrequiredfield'] = 'Egy szükséges mező hiányzik.';
$string['clialreadyconfigured'] = 'Il file config.php esiste già, per favore utilizza admin/cli/install_database.php se desideri installare questo sito.';
$string['clialreadyinstalled'] = 'Il file config.php è già presente, se desideri aggiornare il sito per favore utilizza admin/cli/upgrade.php.';
$string['cliinstallheader'] = 'Programma di installazione Moodle {$a} via linea di comando';
-$string['databasehost'] = 'Database host:';
-$string['databasename'] = 'Nome del Database';
+$string['databasehost'] = 'Host database';
+$string['databasename'] = 'Nome database';
$string['databasetypehead'] = 'Scegli un database driver';
-$string['dataroot'] = 'Cartella dei dati';
-$string['datarootpermission'] = 'Permessi cartella dei dati';
+$string['dataroot'] = 'Cartella dati';
+$string['datarootpermission'] = 'Permessi cartella dati';
$string['dbprefix'] = 'Prefisso tabelle';
$string['dirroot'] = 'Cartella di Moodle';
-$string['environmenthead'] = 'Verifica del vostro ambiente...';
+$string['environmenthead'] = 'Verifica dell\'ambiente...';
$string['environmentsub2'] = 'Ciascuna release di Moodle prevede come requisito minimo una data versione del PHP ed una serie di estensioni. Prima di una installazione o di un aggiornamento viene eseguita la verifica dei requisiti minimi. Se non sai come installare nuove versioni del PHP o le sue estensioni, contatta l\'amministratore del tuo server.';
$string['errorsinenvironment'] = 'Ci sono problemi nel vostro ambiente';
$string['installation'] = 'Installazione';
$string['paths'] = 'Percorsi';
$string['pathserrcreatedataroot'] = 'Lo script di installazione non ha potuto creare la Cartella dei dati ({$a->dataroot}).';
$string['pathshead'] = 'Conferma percorsi';
-$string['pathsrodataroot'] = 'La Cartella dei dati non è scrivibile.';
-$string['pathsroparentdataroot'] = 'La cartella superiore ({$a->parent}) non è scrivibile. Lo script di installazione non può creare la Cartella dei dati ({$a->dataroot}).';
+$string['pathsrodataroot'] = 'Non è possibile scrivere nella Cartella dati.';
+$string['pathsroparentdataroot'] = 'La cartella genitore ({$a->parent}) non è scrivibile. Lo script di installazione non può creare la Cartella dati ({$a->dataroot}).';
$string['pathssubadmindir'] = 'Alcuni web host utilizzano la cartella /admin come URL di accesso a pannelli di controllo od altre funzioni particolari. Tuttavia questo nome coincide con il nome della cartella che Moodle utilizza per i propri file di amministrazione. Per evitare conflitti, è possibile specificare un nome alternativo per la cartella Admin di Moodle. Ad esempio:<p><b>moodleadmin</b></p>
Tutti i link che puntano ai file di amministrazione di Moodle terranno conto di questa variazione.';
$string['pathssubdataroot'] = 'E\' necessario specificare una cartella dove Moodle inserirà i file caricati dagli utenti. Il web server (in genere \'nobody\' o \'apache\') DEVE avere i permessi di lettura e di scrittura su questa cartella. In aggiunta, la cartella dei dati NON DEVE essere direttamente accessibile via web. Se la Cartella dei dati non esiste, lo script di installazione tenterà di crearla.';
$string['pathssubwwwroot'] = 'Indirizzo web per accedere a Moodle. Non è possibile accedere alla stessa installazione Moodle usando più di un indirizzi web. Se il tuo sito usa più indirizzi web, devi configurare dei re-indirizzamenti permanenti per tutti gli altri indirizzi.
Se il tuo sito è raggiungibile sia dalla Internet che dalla Intranet, allora usa l\'indirizzo Internet pubblico ed imposta il DNS in modo che anche gli utenti della Intranet possano accedere usando l\'indirizzo pubblico.
Se l\'indirizzo è errato per favore correggilo nella barra degli indirizzi del browser per avviare nuovamente l\'installazione.';
-$string['pathsunsecuredataroot'] = 'La posizione della Cartella dei dati non è sicura';
+$string['pathsunsecuredataroot'] = 'La posizione della Cartella dati non è sicura';
$string['pathswrongadmindir'] = 'La cartella Admin non esiste';
$string['phpextension'] = '{$a} estensioni PHP';
$string['phpversion'] = 'Versione PHP';
$string['welcomep40'] = 'Il pacchetto include anche <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'L\'utilizzo delle applicazioni incluse in questo pacchetto è regolato dalle rispettive licenze. L\'intero pacchetto <strong>{$a->installername}</strong> è <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> ed è distribuito in accordo alla licenza <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Le prossime pagine ti guideranno attraverso semplici passi per installare e configurare <strong>Moodle</strong> nel tuo computer. Puoi utilizzare le impostazioni di default oppure modificarle per adeguarle alle tue esigenze.';
-$string['welcomep70'] = 'Fate click sul pulsante "Avanti" per continuare l\'installazione di <strong>Moodle</strong>.';
+$string['welcomep70'] = 'Fai click sul pulsante "Avanti" per continuare l\'installazione di <strong>Moodle</strong>.';
$string['wwwroot'] = 'Indirizzo web';
$string['admindirname'] = 'Katalog admin';
$string['availablelangs'] = 'Dostępne paczki językowe';
$string['chooselanguagehead'] = 'Wybierz język';
-$string['chooselanguagesub'] = 'Proszę wybrać język do instalacji. Ten język będą również użyty jako domyślny język witryny, przy czym może być później zmieniony.';
+$string['chooselanguagesub'] = 'Proszę wybrać język do instalacji. Ten język będzie również użyty jako domyślny język witryny, przy czym może być później zmieniony.';
$string['clialreadyconfigured'] = 'Plik config.php już istnieje, użyj admin/cli/install_database.php jeśli chcesz zainstalować tę witrynę.';
$string['clialreadyinstalled'] = 'Plik config.php już istnieje, użyj admin/cli/upgrade.php, jeśli chcesz uaktualnić witrynę.';
$string['cliinstallheader'] = 'Program instalacyjny Moodle {$a} z linii poleceń';
defined('MOODLE_INTERNAL') || die();
+$string['cannotcreatedboninstall'] = '<p> Невозможно создать базу данных. </p><p> Указанная база данных не существует, и данный пользователь не имеет разрешения на создание базы данных. </p><p> Администратор сайта должен проверить конфигурацию базы данных. </p>';
$string['cannotcreatelangdir'] = 'Не удается создать каталог языка';
$string['cannotcreatetempdir'] = 'Не удается создать временный каталог';
$string['cannotdownloadcomponents'] = 'Невозможно загрузить компоненты.';
$string['cannotsavezipfile'] = 'Не удалось сохранить ZIP-файл';
$string['cannotunzipfile'] = 'Не удалось распаковать файл';
$string['componentisuptodate'] = 'Компонент не нуждается в обновлении';
+$string['dmlexceptiononinstall'] = '<p>Произошла ошибка базы данных [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Ошибка проверки загруженного файла';
$string['invalidmd5'] = 'Некорректная md5';
$string['missingrequiredfield'] = 'Отсутствуют некоторые обязательные поля';
$string['entrytitle'] = 'Entry title';
$string['entryupdated'] = 'Blog entry updated';
$string['evententryadded'] = 'Blog entry added';
+$string['evententrydeleted'] = 'Blog entry deleted';
$string['externalblogcrontime'] = 'External blog cron schedule';
$string['externalblogdeleteconfirm'] = 'Unregister this external blog?';
$string['externalblogdeleted'] = 'External blog unregistered';
$string['cachedef_eventinvalidation'] = 'Event invalidation';
$string['cachedef_groupdata'] = 'Course group information';
$string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
+$string['cachedef_langmenu'] = 'List of available languages';
$string['cachedef_locking'] = 'Locking';
$string['cachedef_observers'] = 'Event observers';
$string['cachedef_plugininfo_base'] = 'Plugin info - base';
$string['err_nousers'] = 'There are no students on this course or group for whom completion information is displayed. (By default, completion information is displayed only for students, so if there are no students, you will see this error. Administrators can alter this option via the admin screens.)';
$string['err_settingslocked'] = 'One or more students have already completed a criteria so the settings have been locked. Unlocking the completion criteria settings will delete any existing user data and may cause confusion.';
$string['err_system'] = 'An internal error occurred in the completion system. (System administrators can enable debugging information to see more detail.)';
+$string['eventcoursecompleted'] = 'Course completed';
+$string['eventcoursemodulecompletionupdated'] = 'Course module completion updated';
$string['excelcsvdownload'] = 'Download in Excel-compatible format (.csv)';
$string['fraction'] = 'Fraction';
$string['graderequired'] = 'Required course grade';
$string['advanced'] = 'Advanced';
$string['advancedfilter'] = 'Advanced search';
$string['advancedsettings'] = 'Advanced settings';
+$string['aftercontent'] = 'After {$a}';
$string['again'] = 'again';
$string['aimid'] = 'AIM ID';
$string['ajaxuse'] = 'AJAX and Javascript';
An email containing your new password has been sent to your address at<br /><b>{$a->email}</b>.<br />
The new password was automatically generated - you might like to
<a href="{$a->link}">change your password</a> to something easier to remember.';
+$string['emptydragdropregion'] = 'empty region';
$string['enable'] = 'Enable';
$string['encryptedcode'] = 'Encrypted code';
$string['english'] = 'English';
$string['moreprofileinfoneeded'] = 'Please tell us more about yourself';
$string['mostrecently'] = 'most recently';
$string['move'] = 'Move';
+$string['movecontent'] = 'Move {$a}';
$string['movecategorycontentto'] = 'Move into';
$string['movecategoryto'] = 'Move category to:';
$string['movecontentstoanothercategory'] = 'Move contents to another category';
$string['errorbadroleshortname'] = 'Incorrect role short name';
$string['errorexistsrolename'] = 'Role name already exists';
$string['errorexistsroleshortname'] = 'Role name already exists';
+$string['eventroleallowassignupdated'] = 'Allow role assignment';
+$string['eventroleallowoverrideupdated'] = 'Allow role override';
+$string['eventroleallowswitchupdated'] = 'Allow role switch';
$string['eventroleassigned'] = 'Role assigned';
+$string['eventrolecapabilitiesupdated'] = 'Role capabilities updated';
+$string['eventroledeleted'] = 'Role deleted';
$string['eventroleunassigned'] = 'Role unassigned';
$string['existingadmins'] = 'Current site administrators';
$string['existingusers'] = '{$a} existing users';
$string['unknownoptionkey'] = 'Unknown option key ({$a})';
$string['unnamedstringparam'] = 'A string parameter is unnamed.';
$string['updateusersettings'] = 'Update';
+$string['uploadfiles'] = 'Can upload files';
+$string['uploadfiles_help'] = 'If enabled, any user can upload files with their security keys to their own private files area or a draft file area. Any user file quotas apply.';
$string['userasclients'] = 'Users as clients with token';
$string['userasclientsdescription'] = 'The following steps help you to set up the Moodle web service for users as clients. These steps also help to set up the recommended token (security keys) authentication method. In this use case, the user will generate his token from the security keys page via My profile settings.';
$string['usermissingcaps'] = 'Missing capabilities: {$a}';
$DB->delete_records('role_names', array('roleid'=>$roleid));
$DB->delete_records('role_context_levels', array('roleid'=>$roleid));
- // finally delete the role itself
- // get this before the name is gone for logging
- $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
+ // Get role record before it's deleted.
+ $role = $DB->get_record('role', array('id'=>$roleid));
+ // Finally delete the role itself.
$DB->delete_records('role', array('id'=>$roleid));
- add_to_log(SITEID, 'role', 'delete', 'admin/roles/action=delete&roleid='.$roleid, $rolename, '');
+ // Trigger event.
+ $event = \core\event\role_deleted::create(
+ array(
+ 'context' => context_system::instance(),
+ 'objectid' => $roleid,
+ 'other' =>
+ array(
+ 'name' => $role->name,
+ 'shortname' => $role->shortname,
+ 'description' => $role->description,
+ 'archetype' => $role->archetype
+ )
+ )
+ );
+ $event->add_record_snapshot('role', $role);
+ $event->trigger();
return true;
}
}
}
-/**
- * Triggered when 'course_completed' event happens.
- *
- * @param object $eventdata
- * @return boolean
- */
-function badges_award_handle_course_criteria_review(stdClass $eventdata) {
- global $DB, $CFG;
-
- if (!empty($CFG->enablebadges)) {
- $userid = $eventdata->userid;
- $courseid = $eventdata->course;
-
- // Need to take into account that course can be a part of course_completion and courseset_completion criteria.
- if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'course_' . $courseid, 'value' => $courseid))) {
- foreach ($rs as $r) {
- $crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
- $badge = new badge($crit->badgeid);
- if (!$badge->is_active() || $badge->is_issued($userid)) {
- continue;
- }
-
- if ($badge->criteria[$crit->criteriatype]->review($userid)) {
- $badge->criteria[$crit->criteriatype]->mark_complete($userid);
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
- $badge->issue($userid);
- }
- }
- }
- }
- }
-
- return true;
-}
-
-/**
- * Triggered when 'activity_completed' event happens.
- *
- * @param object $eventdata
- * @return boolean
- */
-function badges_award_handle_activity_criteria_review(stdClass $eventdata) {
- global $DB, $CFG;
-
- if (!empty($CFG->enablebadges)) {
- $userid = $eventdata->userid;
- $mod = $eventdata->coursemoduleid;
-
- if ($eventdata->completionstate == COMPLETION_COMPLETE
- || $eventdata->completionstate == COMPLETION_COMPLETE_PASS
- || $eventdata->completionstate == COMPLETION_COMPLETE_FAIL) {
- // Need to take into account that there can be more than one badge with the same activity in its criteria.
- if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'module_' . $mod, 'value' => $mod))) {
- foreach ($rs as $r) {
- $bid = $DB->get_field('badge_criteria', 'badgeid', array('id' => $r->critid), MUST_EXIST);
- $badge = new badge($bid);
- if (!$badge->is_active() || $badge->is_issued($userid)) {
- continue;
- }
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->mark_complete($userid);
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
- $badge->issue($userid);
- }
- }
- }
- }
- }
- }
-
- return true;
-}
-
/**
* Triggered when 'user_updated' event happens.
*
protected static $subsystems = null;
/** @var null list of all known classes that can be autoloaded */
protected static $classmap = null;
+ /** @var null list of some known files that can be included. */
+ protected static $filemap = null;
+ /** @var array list of the files to map. */
+ protected static $filestomap = array('lib.php', 'settings.php');
/**
* Class loader for Frankenstyle named classes in standard locations.
self::$plugins = $cache['plugins'];
self::$subsystems = $cache['subsystems'];
self::$classmap = $cache['classmap'];
+ self::$filemap = $cache['filemap'];
return;
}
self::$plugins = $cache['plugins'];
self::$subsystems = $cache['subsystems'];
self::$classmap = $cache['classmap'];
+ self::$filemap = $cache['filemap'];
return;
}
// Note: we do not verify $CFG->admin here intentionally,
'plugintypes' => self::$plugintypes,
'plugins' => self::$plugins,
'classmap' => self::$classmap,
+ 'filemap' => self::$filemap,
);
return '<?php
}
self::fill_classmap_cache();
+ self::fill_filemap_cache();
}
/**
self::$classmap['collatorlib'] = "$CFG->dirroot/lib/classes/collator.php";
}
+
+ /**
+ * Fills up the cache defining what plugins have certain files.
+ *
+ * @see self::get_plugin_list_with_file
+ * @return void
+ */
+ protected static function fill_filemap_cache() {
+ global $CFG;
+
+ self::$filemap = array();
+
+ foreach (self::$filestomap as $file) {
+ if (!isset(self::$filemap[$file])) {
+ self::$filemap[$file] = array();
+ }
+ foreach (self::$plugins as $plugintype => $plugins) {
+ if (!isset(self::$filemap[$file][$plugintype])) {
+ self::$filemap[$file][$plugintype] = array();
+ }
+ foreach ($plugins as $pluginname => $fulldir) {
+ if (file_exists("$fulldir/$file")) {
+ self::$filemap[$file][$plugintype][$pluginname] = "$fulldir/$file";
+ }
+ }
+ }
+ }
+ }
+
/**
* Find classes in directory and recurse to subdirs.
* @param string $component
return $pluginclasses;
}
+ /**
+ * Get a list of all the plugins of a given type that contain a particular file.
+ *
+ * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
+ * @param string $file the name of file that must be present in the plugin.
+ * (e.g. 'view.php', 'db/install.xml').
+ * @param bool $include if true (default false), the file will be include_once-ed if found.
+ * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
+ * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
+ */
+ public static function get_plugin_list_with_file($plugintype, $file, $include = false) {
+ global $CFG; // Necessary in case it is referenced by included PHP scripts.
+ $pluginfiles = array();
+
+ if (isset(self::$filemap[$file])) {
+ // If the file was supposed to be mapped, then it should have been set in the array.
+ if (isset(self::$filemap[$file][$plugintype])) {
+ $pluginfiles = self::$filemap[$file][$plugintype];
+ }
+ } else {
+ // Old-style search for non-cached files.
+ $plugins = self::get_plugin_list($plugintype);
+ foreach ($plugins as $plugin => $fulldir) {
+ $path = $fulldir . '/' . $file;
+ if (file_exists($path)) {
+ $pluginfiles[$plugin] = $path;
+ }
+ }
+ }
+
+ if ($include) {
+ foreach ($pluginfiles as $path) {
+ include_once($path);
+ }
+ }
+
+ return $pluginfiles;
+ }
+
/**
* Returns the exact absolute path to plugin directory.
*
return $return;
}
+ /**
+ * Returns hash of all versions including core and all plugins.
+ *
+ * This is relatively slow and not fully cached, use with care!
+ *
+ * @return string sha1 hash
+ */
+ public static function get_all_versions_hash() {
+ global $CFG;
+
+ self::init();
+
+ $versions = array();
+
+ // Main version first.
+ $version = null;
+ include($CFG->dirroot.'/version.php');
+ $versions['core'] = $version;
+
+ // The problem here is tha the component cache might be stable,
+ // we want this to work also on frontpage without resetting the component cache.
+ $usecache = false;
+ if (CACHE_DISABLE_ALL or (defined('IGNORE_COMPONENT_CACHE') and IGNORE_COMPONENT_CACHE)) {
+ $usecache = true;
+ }
+
+ // Now all plugins.
+ $plugintypes = core_component::get_plugin_types();
+ foreach ($plugintypes as $type => $typedir) {
+ if ($usecache) {
+ $plugs = core_component::get_plugin_list($type);
+ } else {
+ $plugs = self::fetch_plugins($type, $typedir);
+ }
+ foreach ($plugs as $plug => $fullplug) {
+ if ($type === 'mod') {
+ $module = new stdClass();
+ $module->version = null;
+ include($fullplug.'/version.php');
+ $versions[$plug] = $module->version;
+ } else {
+ $plugin = new stdClass();
+ $plugin->version = null;
+ @include($fullplug.'/version.php');
+ $versions[$plug] = $plugin->version;
+ }
+ }
+ }
+
+ return sha1(serialize($versions));
+ }
+
/**
* Invalidate opcode cache for given file, this is intended for
* php files that are stored in dataroot.
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Event for when a new blog entry is deleted.
+ *
+ * @package core_blog
+ * @copyright 2013 Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace core\event;
+
+/**
+ * class blog_entry_deleted
+ *
+ * Event for when a new blog entry is deleted.
+ *
+ * @package core_blog
+ * @copyright 2013 Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class blog_entry_deleted extends \core\event\base {
+
+ /** @var \blog_entry A reference to the active blog_entry object. */
+ protected $customobject;
+
+ /**
+ * Set basic event properties.
+ */
+ protected function init() {
+ $this->context = \context_system::instance();
+ $this->data['objecttable'] = 'post';
+ $this->data['crud'] = 'd';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised general event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string("evententrydeleted", "core_blog");
+ }
+
+ /**
+ * Set custom data of the event.
+ *
+ * @param \blog_entry $data A reference to the active blog_entry object.
+ */
+ public function set_custom_data($data) {
+ $this->customobject = $data;
+ }
+
+ /**
+ * Returns non-localised description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return "Blog entry ".$this->other['record']['subject']." was deleted by user with id ".$this->userid;
+ }
+
+ /**
+ * Does this event replace legacy event?
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'blog_entry_deleted';
+ }
+
+ /**
+ * Legacy event data if get_legacy_eventname() is not empty.
+ *
+ * @return \blog_entry
+ */
+ protected function get_legacy_eventdata() {
+ return $this->customobject;
+ }
+
+ /**
+ * replace add_to_log() statement.
+ *
+ * @return array of parameters to be passed to legacy add_to_log() function.
+ */
+ protected function get_legacy_logdata() {
+ return array (SITEID, 'blog', 'delete', 'index.php?userid='.$this->userid, 'deleted blog entry with entry id# '. $this->objectid);
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when course completed.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_completed extends base {
+
+ /**
+ * Initialise required event data properties.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'course_completions';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return new get_string('eventcoursecompleted', 'core_completion');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Course completed by user '.$this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new moodle_url('/report/completion/index.php', array('course' => $this->courseid));
+ }
+
+ /**
+ * Return name of the legacy event, which is replaced by this event.
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'course_completed';
+ }
+
+ /**
+ * Return course_completed legacy event data.
+ *
+ * @return \stdClass completion data.
+ */
+ protected function get_legacy_eventdata() {
+ return $this->get_record_snapshot('course_completions', $this->objectid);
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when course module completion is updated.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_module_completion_updated extends base {
+
+ /**
+ * Initialise required event data properties.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'course_modules_completion';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return new get_string('eventcoursemodulecompletionupdated', 'core_completion');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Course module completion updated for user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new moodle_url('/report/completion/index.php', array('course' => $this->courseid));
+ }
+
+ /**
+ * Return name of the legacy event, which is replaced by this event.
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'activity_completion_changed';
+ }
+
+ /**
+ * Return course module completion legacy event data.
+ *
+ * @return \stdClass completion data.
+ */
+ protected function get_legacy_eventdata() {
+ return $this->get_record_snapshot('course_modules_completion', $this->objectid);
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow assignments is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_assign_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowassignupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role assignments updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'assign'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow assign', 'admin/roles/allow.php?mode=assign');
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow override is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_override_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowoverrideupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role override updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'override'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow override', 'admin/roles/allow.php?mode=override');
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow switch is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_switch_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowswitchupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role switch updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'switch'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow switch', 'admin/roles/allow.php?mode=switch');
+ }
+}
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('role_assignments', $this->data['other']['id']);
}
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $this->get_context(), ROLENAME_ORIGINAL, true);
+ return array($this->courseid, 'role', 'assign', 'admin/roles/assign.php?contextid='.$this->contextid.'&roleid='.$this->objectid,
+ $rolenames[$this->objectid], '', $this->userid);
+ }
}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Role updated event.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_capabilities_updated extends base {
+ /** @var array Legacy log data */
+ protected $legacylogdata = null;
+
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'role';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventrolecapabilitiesupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Capabilities for role ' . $this->objectid . ' are updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ if ($this->contextlevel === CONTEXT_SYSTEM) {
+ return new \moodle_url('admin/roles/define.php', array('action' => 'view', 'roleid' => $this->objectid));
+ } else {
+ return new \moodle_url('/admin/roles/override.php', array('contextid' => $this->contextid, 'roleid' => $this->objectid));
+ }
+ }
+
+ /**
+ * Sets legacy log data.
+ *
+ * @param array $legacylogdata
+ * @return void
+ */
+ public function set_legacy_logdata($legacylogdata) {
+ $this->legacylogdata = $legacylogdata;
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return null|array
+ */
+ protected function get_legacy_logdata() {
+ return $this->legacylogdata;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Role assigned event.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_deleted extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'role';
+ $this->data['crud'] = 'd';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroledeleted', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Role ' . $this->objectid . ' is deleted by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/manage.php');
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$this->objectid, $this->other['shortname'], '');
+ }
+}
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('role_assignments', $this->data['other']['id']);
}
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $this->get_context(), ROLENAME_ORIGINAL, true);
+ return array($this->courseid, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$this->contextid.'&roleid='.$this->objectid,
+ $rolenames[$this->objectid], '', $this->userid);
+ }
}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * String manager interface.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Interface for string manager
+ *
+ * Interface describing class which is responsible for getting
+ * of localised strings from language packs.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+interface core_string_manager {
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null);
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ *
+ * Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return bool true if exists
+ */
+ public function string_exists($identifier, $component);
+
+ /**
+ * Returns a localised list of all country names, sorted by country keys.
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null);
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * iso6392: three-letter language code (ISO 639-2/T) => translated name.
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6392');
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true);
+
+ /**
+ * Returns localised list of installed translations
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false);
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null);
+
+ /**
+ * Load all strings for one component
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false);
+
+ /**
+ * Invalidates all caches, should the implementation use any
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false);
+
+ /**
+ * Returns string revision counter, this is incremented after any
+ * string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision();
+}
+
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Installation time string manager.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Fetches minimum strings for installation
+ *
+ * Minimalistic string fetching implementation
+ * that is used in installer before we fetch the wanted
+ * language pack from moodle.org lang download site.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda (http://skodak.org)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_string_manager_install implements core_string_manager {
+ /** @var string location of pre-install packs for all langs */
+ protected $installroot;
+
+ /**
+ * Crate new instance of install string manager
+ */
+ public function __construct() {
+ global $CFG;
+ $this->installroot = "$CFG->dirroot/install/lang";
+ }
+
+ /**
+ * Load all strings for one component
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache = false, $disablelocal = false) {
+ // Not needed in installer.
+ return array();
+ }
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ *
+ * Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return boot true if exists
+ */
+ public function string_exists($identifier, $component) {
+ // Simple old style hack ;).
+ $str = get_string($identifier, $component);
+ return (strpos($str, '[[') === false);
+ }
+
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null) {
+ if (!$component) {
+ $component = 'moodle';
+ }
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ // Get parent lang.
+ $parent = '';
+ if ($lang !== 'en' and $identifier !== 'parentlanguage' and $component !== 'langconfig') {
+ if (file_exists("$this->installroot/$lang/langconfig.php")) {
+ $string = array();
+ include("$this->installroot/$lang/langconfig.php");
+ if (isset($string['parentlanguage'])) {
+ $parent = $string['parentlanguage'];
+ }
+ }
+ }
+
+ // Include en string first.
+ if (!file_exists("$this->installroot/en/$component.php")) {
+ return "[[$identifier]]";
+ }
+ $string = array();
+ include("$this->installroot/en/$component.php");
+
+ // Now override en with parent if defined.
+ if ($parent and $parent !== 'en' and file_exists("$this->installroot/$parent/$component.php")) {
+ include("$this->installroot/$parent/$component.php");
+ }
+
+ // Finally override with requested language.
+ if ($lang !== 'en' and file_exists("$this->installroot/$lang/$component.php")) {
+ include("$this->installroot/$lang/$component.php");
+ }
+
+ if (!isset($string[$identifier])) {
+ return "[[$identifier]]";
+ }
+
+ $string = $string[$identifier];
+
+ if ($a !== null) {
+ if (is_object($a) or is_array($a)) {
+ $a = (array)$a;
+ $search = array();
+ $replace = array();
+ foreach ($a as $key => $value) {
+ if (is_int($key)) {
+ // We do not support numeric keys - sorry!
+ continue;
+ }
+ $search[] = '{$a->' . $key . '}';
+ $replace[] = (string)$value;
+ }
+ if ($search) {
+ $string = str_replace($search, $replace, $string);
+ }
+ } else {
+ $string = str_replace('{$a}', (string)$a, $string);
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a localised list of all country names, sorted by country keys.
+ *
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null) {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * iso6392: three-letter language code (ISO 639-2/T) => translated name.
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6392') {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true) {
+ return file_exists($this->installroot . '/' . $lang . '/langconfig.php');
+ }
+
+ /**
+ * Returns localised list of installed translations
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false) {
+ // Return all is ignored here - we need to know all langs in installer.
+ $languages = array();
+ // Get raw list of lang directories.
+ $langdirs = get_list_of_plugins('install/lang');
+ asort($langdirs);
+ // Get some info from each lang.
+ foreach ($langdirs as $lang) {
+ if (file_exists($this->installroot . '/' . $lang . '/langconfig.php')) {
+ $string = array();
+ include($this->installroot . '/' . $lang . '/langconfig.php');
+ if (!empty($string['thislanguage'])) {
+ $languages[$lang] = $string['thislanguage'] . ' (' . $lang . ')';
+ }
+ }
+ }
+ // Return array.
+ return $languages;
+ }
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null) {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * This implementation does not use any caches.
+ *
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false) {
+ // Nothing to do.
+ }
+
+ /**
+ * Returns string revision counter, this is incremented after any string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision() {
+ return -1;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Standard string manager.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Standard string_manager implementation
+ *
+ * Implements string_manager with getting and printing localised strings
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_string_manager_standard implements core_string_manager {
+ /** @var string location of all packs except 'en' */
+ protected $otherroot;
+ /** @var string location of all lang pack local modifications */
+ protected $localroot;
+ /** @var cache lang string cache - it will be optimised more later */
+ protected $cache;
+ /** @var int get_string() counter */
+ protected $countgetstring = 0;
+ /** @var bool use disk cache */
+ protected $translist;
+ /** @var cache stores list of available translations */
+ protected $menucache;
+
+ /**
+ * Create new instance of string manager
+ *
+ * @param string $otherroot location of downloaded lang packs - usually $CFG->dataroot/lang
+ * @param string $localroot usually the same as $otherroot
+ * @param array $translist limit list of visible translations
+ */
+ public function __construct($otherroot, $localroot, $translist) {
+ $this->otherroot = $otherroot;
+ $this->localroot = $localroot;
+ if ($translist) {
+ $this->translist = array_combine($translist, $translist);
+ } else {
+ $this->translist = array();
+ }
+
+ if ($this->get_revision() > 0) {
+ // We can use a proper cache, establish the cache using the 'String cache' definition.
+ $this->cache = cache::make('core', 'string');
+ $this->menucache = cache::make('core', 'langmenu');
+ } else {
+ // We only want a cache for the length of the request, create a static cache.
+ $options = array(
+ 'simplekeys' => true,
+ 'simpledata' => true
+ );
+ $this->cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'string', array(), $options);
+ $this->menucache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'langmenu', array(), $options);
+ }
+ }
+
+ /**
+ * Returns list of all explicit parent languages for the given language.
+ *
+ * English (en) is considered as the top implicit parent of all language packs
+ * and is not included in the returned list. The language itself is appended to the
+ * end of the list. The method is aware of circular dependency risk.
+ *
+ * @see self::populate_parent_languages()
+ * @param string $lang the code of the language
+ * @return array all explicit parent languages with the lang itself appended
+ */
+ public function get_language_dependencies($lang) {
+ return $this->populate_parent_languages($lang);
+ }
+
+ /**
+ * Load all strings for one component
+ *
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache = false, $disablelocal = false) {
+ global $CFG;
+
+ list($plugintype, $pluginname) = core_component::normalize_component($component);
+ if ($plugintype === 'core' and is_null($pluginname)) {
+ $component = 'core';
+ } else {
+ $component = $plugintype . '_' . $pluginname;
+ }
+
+ $cachekey = $lang.'_'.$component.'_'.$this->get_key_suffix();
+
+ $cachedstring = $this->cache->get($cachekey);
+ if (!$disablecache and !$disablelocal) {
+ if ($cachedstring !== false) {
+ return $cachedstring;
+ }
+ }
+
+ // No cache found - let us merge all possible sources of the strings.
+ if ($plugintype === 'core') {
+ $file = $pluginname;
+ if ($file === null) {
+ $file = 'moodle';
+ }
+ $string = array();
+ // First load english pack.
+ if (!file_exists("$CFG->dirroot/lang/en/$file.php")) {
+ return array();
+ }
+ include("$CFG->dirroot/lang/en/$file.php");
+ $enstring = $string;
+
+ // And then corresponding local if present and allowed.
+ if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
+ include("$this->localroot/en_local/$file.php");
+ }
+ // Now loop through all langs in correct order.
+ $deps = $this->get_language_dependencies($lang);
+ foreach ($deps as $dep) {
+ // The main lang string location.
+ if (file_exists("$this->otherroot/$dep/$file.php")) {
+ include("$this->otherroot/$dep/$file.php");
+ }
+ if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
+ include("$this->localroot/{$dep}_local/$file.php");
+ }
+ }
+
+ } else {
+ if (!$location = core_component::get_plugin_directory($plugintype, $pluginname) or !is_dir($location)) {
+ return array();
+ }
+ if ($plugintype === 'mod') {
+ // Bloody mod hack.
+ $file = $pluginname;
+ } else {
+ $file = $plugintype . '_' . $pluginname;
+ }
+ $string = array();
+ // First load English pack.
+ if (!file_exists("$location/lang/en/$file.php")) {
+ // English pack does not exist, so do not try to load anything else.
+ return array();
+ }
+ include("$location/lang/en/$file.php");
+ $enstring = $string;
+ // And then corresponding local english if present.
+ if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
+ include("$this->localroot/en_local/$file.php");
+ }
+
+ // Now loop through all langs in correct order.
+ $deps = $this->get_language_dependencies($lang);
+ foreach ($deps as $dep) {
+ // Legacy location - used by contrib only.
+ if (file_exists("$location/lang/$dep/$file.php")) {
+ include("$location/lang/$dep/$file.php");
+ }
+ // The main lang string location.
+ if (file_exists("$this->otherroot/$dep/$file.php")) {
+ include("$this->otherroot/$dep/$file.php");
+ }
+ // Local customisations.
+ if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
+ include("$this->localroot/{$dep}_local/$file.php");
+ }
+ }
+ }
+
+ // We do not want any extra strings from other languages - everything must be in en lang pack.
+ $string = array_intersect_key($string, $enstring);
+
+ if (!$disablelocal) {
+ // Now we have a list of strings from all possible sources,
+ // cache it in MUC cache if not already there.
+ if ($cachedstring === false) {
+ $this->cache->set($cachekey, $string);
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ * Note: Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return boot true if exists
+ */
+ public function string_exists($identifier, $component) {
+ $lang = current_language();
+ $string = $this->load_component_strings($component, $lang);
+ return isset($string[$identifier]);
+ }
+
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null) {
+ $this->countgetstring++;
+ // There are very many uses of these time formatting strings without the 'langconfig' component,
+ // it would not be reasonable to expect that all of them would be converted during 2.0 migration.
+ static $langconfigstrs = array(
+ 'strftimedate' => 1,
+ 'strftimedatefullshort' => 1,
+ 'strftimedateshort' => 1,
+ 'strftimedatetime' => 1,
+ 'strftimedatetimeshort' => 1,
+ 'strftimedaydate' => 1,
+ 'strftimedaydatetime' => 1,
+ 'strftimedayshort' => 1,
+ 'strftimedaytime' => 1,
+ 'strftimemonthyear' => 1,
+ 'strftimerecent' => 1,
+ 'strftimerecentfull' => 1,
+ 'strftimetime' => 1);
+
+ if (empty($component)) {
+ if (isset($langconfigstrs[$identifier])) {
+ $component = 'langconfig';
+ } else {
+ $component = 'moodle';
+ }
+ }
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $string = $this->load_component_strings($component, $lang);
+
+ if (!isset($string[$identifier])) {
+ if ($component === 'pix' or $component === 'core_pix') {
+ // This component contains only alt tags for emoticons, not all of them are supposed to be defined.
+ return '';
+ }
+ if ($identifier === 'parentlanguage' and ($component === 'langconfig' or $component === 'core_langconfig')) {
+ // Identifier parentlanguage is a special string, undefined means use English if not defined.
+ return 'en';
+ }
+ // Do not rebuild caches here!
+ // Devs need to learn to purge all caches after any change or disable $CFG->langstringcache.
+ if (!isset($string[$identifier])) {
+ // The string is still missing - should be fixed by developer.
+ if (debugging('', DEBUG_DEVELOPER)) {
+ list($plugintype, $pluginname) = core_component::normalize_component($component);
+ if ($plugintype === 'core') {
+ $file = "lang/en/{$component}.php";
+ } else if ($plugintype == 'mod') {
+ $file = "mod/{$pluginname}/lang/en/{$pluginname}.php";
+ } else {
+ $path = core_component::get_plugin_directory($plugintype, $pluginname);
+ $file = "{$path}/lang/en/{$plugintype}_{$pluginname}.php";
+ }
+ debugging("Invalid get_string() identifier: '{$identifier}' or component '{$component}'. " .
+ "Perhaps you are missing \$string['{$identifier}'] = ''; in {$file}?", DEBUG_DEVELOPER);
+ }
+ return "[[$identifier]]";
+ }
+ }
+
+ $string = $string[$identifier];
+
+ if ($a !== null) {
+ // Process array's and objects (except lang_strings).
+ if (is_array($a) or (is_object($a) && !($a instanceof lang_string))) {
+ $a = (array)$a;
+ $search = array();
+ $replace = array();
+ foreach ($a as $key => $value) {
+ if (is_int($key)) {
+ // We do not support numeric keys - sorry!
+ continue;
+ }
+ if (is_array($value) or (is_object($value) && !($value instanceof lang_string))) {
+ // We support just string or lang_string as value.
+ continue;
+ }
+ $search[] = '{$a->'.$key.'}';
+ $replace[] = (string)$value;
+ }
+ if ($search) {
+ $string = str_replace($search, $replace, $string);
+ }
+ } else {
+ $string = str_replace('{$a}', (string)$a, $string);
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns information about the core_string_manager performance.
+ *
+ * @return array
+ */
+ public function get_performance_summary() {
+ return array(array(
+ 'langcountgetstring' => $this->countgetstring,
+ ), array(
+ 'langcountgetstring' => 'get_string calls',
+ ));
+ }
+
+ /**
+ * Returns a localised list of all country names, sorted by localised name.
+ *
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null) {
+ global $CFG;
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $countries = $this->load_component_strings('core_countries', $lang);
+ core_collator::asort($countries);
+ if (!$returnall and !empty($CFG->allcountrycodes)) {
+ $enabled = explode(',', $CFG->allcountrycodes);
+ $return = array();
+ foreach ($enabled as $c) {
+ if (isset($countries[$c])) {
+ $return[$c] = $countries[$c];
+ }
+ }
+ return $return;
+ }
+
+ return $countries;
+ }
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * - iso6392: three-letter language code (ISO 639-2/T) => translated name
+ * - iso6391: two-letter language code (ISO 639-1) => translated name
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6391') {
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ if ($standard === 'iso6392') {
+ $langs = $this->load_component_strings('core_iso6392', $lang);
+ ksort($langs);
+ return $langs;
+
+ } else if ($standard === 'iso6391') {
+ $langs2 = $this->load_component_strings('core_iso6392', $lang);
+ static $mapping = array('aar' => 'aa', 'abk' => 'ab', 'afr' => 'af', 'aka' => 'ak', 'sqi' => 'sq', 'amh' => 'am', 'ara' => 'ar', 'arg' => 'an', 'hye' => 'hy',
+ 'asm' => 'as', 'ava' => 'av', 'ave' => 'ae', 'aym' => 'ay', 'aze' => 'az', 'bak' => 'ba', 'bam' => 'bm', 'eus' => 'eu', 'bel' => 'be', 'ben' => 'bn', 'bih' => 'bh',
+ 'bis' => 'bi', 'bos' => 'bs', 'bre' => 'br', 'bul' => 'bg', 'mya' => 'my', 'cat' => 'ca', 'cha' => 'ch', 'che' => 'ce', 'zho' => 'zh', 'chu' => 'cu', 'chv' => 'cv',
+ 'cor' => 'kw', 'cos' => 'co', 'cre' => 'cr', 'ces' => 'cs', 'dan' => 'da', 'div' => 'dv', 'nld' => 'nl', 'dzo' => 'dz', 'eng' => 'en', 'epo' => 'eo', 'est' => 'et',
+ 'ewe' => 'ee', 'fao' => 'fo', 'fij' => 'fj', 'fin' => 'fi', 'fra' => 'fr', 'fry' => 'fy', 'ful' => 'ff', 'kat' => 'ka', 'deu' => 'de', 'gla' => 'gd', 'gle' => 'ga',
+ 'glg' => 'gl', 'glv' => 'gv', 'ell' => 'el', 'grn' => 'gn', 'guj' => 'gu', 'hat' => 'ht', 'hau' => 'ha', 'heb' => 'he', 'her' => 'hz', 'hin' => 'hi', 'hmo' => 'ho',
+ 'hrv' => 'hr', 'hun' => 'hu', 'ibo' => 'ig', 'isl' => 'is', 'ido' => 'io', 'iii' => 'ii', 'iku' => 'iu', 'ile' => 'ie', 'ina' => 'ia', 'ind' => 'id', 'ipk' => 'ik',
+ 'ita' => 'it', 'jav' => 'jv', 'jpn' => 'ja', 'kal' => 'kl', 'kan' => 'kn', 'kas' => 'ks', 'kau' => 'kr', 'kaz' => 'kk', 'khm' => 'km', 'kik' => 'ki', 'kin' => 'rw',
+ 'kir' => 'ky', 'kom' => 'kv', 'kon' => 'kg', 'kor' => 'ko', 'kua' => 'kj', 'kur' => 'ku', 'lao' => 'lo', 'lat' => 'la', 'lav' => 'lv', 'lim' => 'li', 'lin' => 'ln',
+ 'lit' => 'lt', 'ltz' => 'lb', 'lub' => 'lu', 'lug' => 'lg', 'mkd' => 'mk', 'mah' => 'mh', 'mal' => 'ml', 'mri' => 'mi', 'mar' => 'mr', 'msa' => 'ms', 'mlg' => 'mg',
+ 'mlt' => 'mt', 'mon' => 'mn', 'nau' => 'na', 'nav' => 'nv', 'nbl' => 'nr', 'nde' => 'nd', 'ndo' => 'ng', 'nep' => 'ne', 'nno' => 'nn', 'nob' => 'nb', 'nor' => 'no',
+ 'nya' => 'ny', 'oci' => 'oc', 'oji' => 'oj', 'ori' => 'or', 'orm' => 'om', 'oss' => 'os', 'pan' => 'pa', 'fas' => 'fa', 'pli' => 'pi', 'pol' => 'pl', 'por' => 'pt',
+ 'pus' => 'ps', 'que' => 'qu', 'roh' => 'rm', 'ron' => 'ro', 'run' => 'rn', 'rus' => 'ru', 'sag' => 'sg', 'san' => 'sa', 'sin' => 'si', 'slk' => 'sk', 'slv' => 'sl',
+ 'sme' => 'se', 'smo' => 'sm', 'sna' => 'sn', 'snd' => 'sd', 'som' => 'so', 'sot' => 'st', 'spa' => 'es', 'srd' => 'sc', 'srp' => 'sr', 'ssw' => 'ss', 'sun' => 'su',
+ 'swa' => 'sw', 'swe' => 'sv', 'tah' => 'ty', 'tam' => 'ta', 'tat' => 'tt', 'tel' => 'te', 'tgk' => 'tg', 'tgl' => 'tl', 'tha' => 'th', 'bod' => 'bo', 'tir' => 'ti',
+ 'ton' => 'to', 'tsn' => 'tn', 'tso' => 'ts', 'tuk' => 'tk', 'tur' => 'tr', 'twi' => 'tw', 'uig' => 'ug', 'ukr' => 'uk', 'urd' => 'ur', 'uzb' => 'uz', 'ven' => 've',
+ 'vie' => 'vi', 'vol' => 'vo', 'cym' => 'cy', 'wln' => 'wa', 'wol' => 'wo', 'xho' => 'xh', 'yid' => 'yi', 'yor' => 'yo', 'zha' => 'za', 'zul' => 'zu');
+ $langs1 = array();
+ foreach ($mapping as $c2 => $c1) {
+ $langs1[$c1] = $langs2[$c2];
+ }
+ ksort($langs1);
+ return $langs1;
+
+ } else {
+ debugging('Unsupported $standard parameter in get_list_of_languages() method: '.$standard);
+ }
+
+ return array();
+ }
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true) {
+ $translations = $this->get_list_of_translations($includeall);
+ return isset($translations[$lang]);
+ }
+
+ /**
+ * Returns localised list of installed translations
+ *
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false) {
+ global $CFG;
+
+ $languages = array();
+
+ $cachekey = 'list_'.$this->get_key_suffix();
+ $cachedlist = $this->menucache->get($cachekey);
+ if ($cachedlist !== false) {
+ // The cache content is invalid.
+ if ($returnall or empty($this->translist)) {
+ return $cachedlist;
+ }
+ // Return only enabled translations.
+ foreach ($cachedlist as $langcode => $langname) {
+ if (isset($this->translist[$langcode])) {
+ $languages[$langcode] = $langname;
+ }
+ }
+ return $languages;
+ }
+
+ // Get all languages available in system.
+ $langdirs = get_list_of_plugins('', 'en', $this->otherroot);
+ $langdirs["$CFG->dirroot/lang/en"] = 'en';
+
+ // Loop through all langs and get info.
+ foreach ($langdirs as $lang) {
+ if (strrpos($lang, '_local') !== false) {
+ // Just a local tweak of some other lang pack.
+ continue;
+ }
+ if (strrpos($lang, '_utf8') !== false) {
+ // Legacy 1.x lang pack.
+ continue;
+ }
+ if ($lang !== clean_param($lang, PARAM_SAFEDIR)) {
+ // Invalid lang pack name!
+ continue;
+ }
+ $string = $this->load_component_strings('langconfig', $lang);
+ if (!empty($string['thislanguage'])) {
+ $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
+ }
+ }
+
+ core_collator::asort($languages);
+
+ // Cache the list so that it can be used next time.
+ $this->menucache->set($cachekey, $languages);
+
+ if ($returnall or empty($this->translist)) {
+ return $languages;
+ }
+
+ $cachedlist = $languages;
+
+ // Return only enabled translations.
+ $languages = array();
+ foreach ($cachedlist as $langcode => $langname) {
+ if (isset($this->translist[$langcode])) {
+ $languages[$langcode] = $langname;
+ }
+ }
+
+ return $languages;
+ }
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null) {
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $currencies = $this->load_component_strings('core_currencies', $lang);
+ asort($currencies);
+
+ return $currencies;
+ }
+
+ /**
+ * Clears both in-memory and on-disk caches
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false) {
+ // Clear the on-disk disk with aggregated string files.
+ $this->cache->purge();
+ $this->menucache->purge();
+
+ if (!$phpunitreset) {
+ // Increment the revision counter.
+ $langrev = get_config('core', 'langrev');
+ $next = time();
+ if ($langrev !== false and $next <= $langrev and $langrev - $next < 60*60) {
+ // This resolves problems when reset is requested repeatedly within 1s,
+ // the < 1h condition prevents accidental switching to future dates
+ // because we might not recover from it.
+ $next = $langrev+1;
+ }
+ set_config('langrev', $next);
+ }
+
+ // Lang packs use PHP files in dataroot, it is better to invalidate opcode caches.
+ if (function_exists('opcache_reset')) {
+ opcache_reset();
+ }
+ }
+
+ /**
+ * Returns cache key suffix, this enables us to store string + lang menu
+ * caches in local caches on cluster nodes. We can not use prefix because
+ * it would cause problems when creating subdirs in cache file store.
+ * @return string
+ */
+ protected function get_key_suffix() {
+ $rev = $this->get_revision();
+ if ($rev < 0) {
+ // Simple keys do not like minus char.
+ $rev = 0;
+ }
+
+ return $rev;
+ }
+
+ /**
+ * Returns string revision counter, this is incremented after any string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision() {
+ global $CFG;
+ if (empty($CFG->langstringcache)) {
+ return -1;
+ }
+ if (isset($CFG->langrev)) {
+ return (int)$CFG->langrev;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Helper method that recursively loads all parents of the given language.
+ *
+ * @see self::get_language_dependencies()
+ * @param string $lang language code
+ * @param array $stack list of parent languages already populated in previous recursive calls
+ * @return array list of all parents of the given language with the $lang itself added as the last element
+ */
+ protected function populate_parent_languages($lang, array $stack = array()) {
+
+ // English does not have a parent language.
+ if ($lang === 'en') {
+ return $stack;
+ }
+
+ // Prevent circular dependency (and thence the infinitive recursion loop).
+ if (in_array($lang, $stack)) {
+ return $stack;
+ }
+
+ // Load language configuration and look for the explicit parent language.
+ if (!file_exists("$this->otherroot/$lang/langconfig.php")) {
+ return $stack;
+ }
+ $string = array();
+ include("$this->otherroot/$lang/langconfig.php");
+
+ if (empty($string['parentlanguage']) or $string['parentlanguage'] === 'en') {
+ return array_merge(array($lang), $stack);
+
+ }
+
+ $parentlang = $string['parentlanguage'];
+ return $this->populate_parent_languages($parentlang, array_merge(array($lang), $stack));
+ }
+}
}
$transaction->allow_commit();
- events_trigger('activity_completion_changed', $data);
+ $cmcontext = context_module::instance($data->coursemoduleid, MUST_EXIST);
+ $coursecontext = $cmcontext->get_parent_context();
+
+ // Trigger an event for course module completion changed.
+ $event = \core\event\course_module_completion_updated::create(
+ array('objectid' => $data->id,
+ 'userid' => $USER->id,
+ 'context' => $cmcontext,
+ 'courseid' => $coursecontext->instanceid,
+ 'other' => array('relateduserid' => $data->userid)
+ )
+ );
+ $event->add_record_snapshot('course_modules_completion', $data);
+ $event->trigger();
if ($data->userid == $USER->id) {
$SESSION->completioncache[$cm->course][$cm->id] = $data;
'descriptionformat' => null, // not cached
'parent' => array('pa', 0),
'sortorder' => array('so', 0),
- 'coursecount' => null, // not cached
+ 'coursecount' => array('cc', 0),
'visible' => array('vi', 1),
'visibleold' => null, // not cached
'timemodified' => null, // not cached
foreach ($rs as $record) {
// If the category's parent is not visible to the user, it is not visible as well.
if (!$record->parent || isset($baselist[$record->parent])) {
+ context_helper::preload_from_record($record);
$context = context_coursecat::instance($record->id);
if (!$record->visible && !has_capability('moodle/category:viewhiddencategories', $context)) {
// No cap to view category, added to neither $baselist nor $thislist
$definitions = array(
// Used to store processed lang files.
- // The keys used are the component of the string file.
+ // The keys used are the revision, lang and component of the string file.
// The persistent max size has been based upon student access of the site.
+ // NOTE: this data may be safely stored in local caches on cluster nodes.
'string' => array(
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'persistentmaxsize' => 30
),
+ // Used to store cache of all available translations.
+ // NOTE: this data may be safely stored in local caches on cluster nodes.
+ 'langmenu' => array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'simplekeys' => true,
+ 'simpledata' => true,
+ 'persistent' => true,
+ ),
+
// Used to store database meta information.
// The database meta information includes information about tables and there columns.
// Its keys are the table names.
$handlers = array(
- 'course_completed' => array (
- 'handlerfile' => '/lib/badgeslib.php',
- 'handlerfunction' => 'badges_award_handle_course_criteria_review',
- 'schedule' => 'instant',
- 'internal' => 1,
- ),
- 'activity_completion_changed' => array (
- 'handlerfile' => '/lib/badgeslib.php',
- 'handlerfunction' => 'badges_award_handle_activity_criteria_review',
- 'schedule' => 'instant',
- 'internal' => 1,
- ),
'user_updated' => array (
'handlerfile' => '/lib/badgeslib.php',
'handlerfunction' => 'badges_award_handle_profile_criteria_review',
/* no more here please, core should not consume any events!!!!!!! */
);
+$observers = array(
+ array(
+ 'eventname' => '\core\event\course_module_completion_updated',
+ 'callback' => 'core_badges_observer::course_module_criteria_review',
+ ),
+ array(
+ 'eventname' => '\core\event\course_completed',
+ 'callback' => 'core_badges_observer::course_criteria_review',
+ )
+
+);
/* List of events thrown from Moodle core
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="a unique shortname"/>
<FIELD NAME="downloadfiles" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="1 if the service allow people to download file from webservice/plugins.php - 0 if not"/>
+ <FIELD NAME="uploadfiles" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="1 if the service allow people to upload files to webservice/upload.php - 0 if not"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
'enabled' => 0,
'restrictedusers' => 0,
'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
- 'downloadfiles' => 1
+ 'downloadfiles' => 1,
+ 'uploadfiles' => 1
),
);
upgrade_main_savepoint(true, 2013072600.01);
}
+ if ($oldversion < 2013081200.00) {
+ // Define field uploadfiles to be added to external_services.
+ $table = new xmldb_table('external_services');
+ $field = new xmldb_field('uploadfiles', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'downloadfiles');
+
+ // Conditionally launch add field uploadfiles.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2013081200.00);
+ }
+
return true;
}
function isediting() {
throw new coding_exception('isediting() can not be used any more, please use $PAGE->user_is_editing() instead.');
}
+
+/**
+ * Get a list of all the plugins of a given type that contain a particular file.
+ *
+ * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
+ * @param string $file the name of file that must be present in the plugin.
+ * (e.g. 'view.php', 'db/install.xml').
+ * @param bool $include if true (default false), the file will be include_once-ed if found.
+ * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
+ * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
+ * @deprecated since 2.6
+ * @see core_component::get_plugin_list_with_file()
+ */
+function get_plugin_list_with_file($plugintype, $file, $include = false) {
+ debugging('get_plugin_list_with_file() is deprecated, please use core_component::get_plugin_list_with_file() instead.',
+ DEBUG_DEVELOPER);
+ return core_component::get_plugin_list_with_file($plugintype, $file, $include);
+}
};
ed.windowManager.onClose.add(onClose);
var vp = ed.dom.getViewPort(),
- width = 865 + parseInt(ed.getLang('advimage.delta_width', 0)),
+ width = 900 + parseInt(ed.getLang('advimage.delta_width', 0)),
height = 600 + parseInt(ed.getLang('advimage.delta_height', 0)),
maximizedmode = (width >= vp.w - 2 || height >= vp.h - 2);
if (maximizedmode) {
* this.areamaxbytes, the maximum size of the area
* this.filemanager, contains reference to filemanager Node
* this.selectnode, contains referenct to select-file Node
- * this.selectui, YUI Panel to select the file
+ * this.selectui, M.core.dialogue to select the file
*
* FileManager options:
* =====
}
// initialize 'select file' panel
this.selectnode = Y.Node.createWithFilesSkin(M.form_filemanager.templates.fileselectlayout);
+ this.selectnode.setAttribute('aria-live', 'assertive');
+ this.selectnode.setAttribute('role', 'dialog');
this.selectnode.generateID();
- this.selectui = new Y.Panel({
- srcNode : this.selectnode,
- zIndex : 7600,
+
+ var labelid = 'fm-dialog-label_'+ this.selectnode.get('id');
+ this.selectui = new M.core.dialogue({
+ draggable : true,
+ headerContent: '<span id="' + labelid +'">' + M.str.moodle.edit + '</span>',
+ bodyContent : this.selectnode,
centered : true,
modal : true,
- close : true,
- render : true
+ visible : false
});
- this.selectui.plug(Y.Plugin.Drag,{handles:['#'+this.selectnode.get('id')+' .yui3-widget-hd']});
+ Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', labelid);
this.selectui.hide();
this.setup_select_file();
// setup buttons onclick events
this.msg_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.message);
var nodeid = this.msg_dlg_node.generateID();
- this.msg_dlg = new Y.Panel({
- srcNode : this.msg_dlg_node,
- zIndex : 8000,
+ this.msg_dlg = new M.core.dialogue({
+ draggable : true,
+ bodyContent : this.msg_dlg_node,
centered : true,
modal : true,
visible : false,
- render : true
});
- this.msg_dlg.plug(Y.Plugin.Drag,{handles:['#'+nodeid+' .yui3-widget-hd']});
this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
e.preventDefault();
this.msg_dlg.hide();
};
if (!this.mkdir_dialog) {
var node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.mkdir);
- this.mkdir_dialog = new Y.Panel({
- srcNode : node,
- zIndex : 8000,
+ this.mkdir_dialog = new M.core.dialogue({
+ draggable : true,
+ bodyContent : node,
centered : true,
modal : true,
visible : false,
- render : true
});
- this.mkdir_dialog.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
node.one('.fp-dlg-butcreate').set('id', 'fm-mkdir-butcreate-'+this.client_id).on('click',
perform_action, this);
node.one('input').set('id', 'fm-newname-'+this.client_id).on('keydown', function(e) {
this.confirm_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.confirmdialog);
var node = this.confirm_dlg_node;
node.generateID();
- this.confirm_dlg = new Y.Panel({
- srcNode : node,
- zIndex : 8000,
+ this.confirm_dlg = new M.core.dialogue({
+ draggable : true,
+ bodyContent : node,
centered : true,
modal : true,
visible : false,
- render : true,
buttons : {}
});
- this.confirm_dlg.plug(Y.Plugin.Drag,{handles:['#'+node.get('id')+' .yui3-widget-hd']});
var handle_confirm = function(ev) {
var dlgopt = this.confirm_dlg.dlgopt;
ev.preventDefault();
}
}, false);
}
+ // update dialog header
+ var nodename = node.fullname;
+ // Limit the string length so it fits nicely on mobile devices
+ var namelength = 50;
+ if (nodename.length > namelength) {
+ nodename = nodename.substring(0, namelength) + '...';
+ }
+ Y.one('#fm-dialog-label_'+selectnode.get('id')).setContent(Y.Escape.html(M.str.moodle.edit+' '+nodename));
// show panel
this.selectui.show();
+ Y.one('#'+selectnode.get('id')).focus();
},
render: function() {
this.print_path();
// switch next two lines for ol li containers for form items.
// $this->_elementTemplates=array('default'=>"\n\t\t".'<li class="fitem"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class="qfelement<!-- BEGIN error --> error<!-- END error --> {type}"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></li>');
$this->_elementTemplates = array(
- 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}" {aria-live}><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
+ 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}" {aria-live}><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
'actionbuttons'=>"\n\t\t".'<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>',
- 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
+ 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
- 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
+ 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
if ($children = grade_item::fetch_all(array('categoryid'=>$this->id))) {
foreach ($children as $child) {
- $child->set_hidden($hidden, $cascade);
+ if ($child->can_control_visibility()) {
+ $child->set_hidden($hidden, $cascade);
+ }
}
}
if (core_component::get_plugin_directory($this->itemtype, $this->itemmodule)) {
return !plugin_supports($this->itemtype, $this->itemmodule, FEATURE_CONTROLS_GRADE_VISIBILITY, false);
}
- return true;
+ return parent::can_control_visibility();
}
}
$this->hidden = $hidden;
$this->update();
}
+
+ /**
+ * Returns whether the grade object can control the visibility of the grades.
+ *
+ * @return bool
+ */
+ public function can_control_visibility() {
+ return true;
+ }
}
$this->activities[6] = $this->getDataGenerator()->create_module('forum', array('course'=>$this->course->id));
$this->course_module[6] = get_coursemodule_from_instance('forum', $this->activities[6]->id);
+
+ $this->activities[7] = $this->getDataGenerator()->create_module('quiz', array('course'=>$this->course->id));
+ $this->course_module[7] = get_coursemodule_from_instance('quiz', $this->activities[7]->id);
}
private function load_scales() {
$grade_item->id = $DB->insert_record('grade_items', $grade_item);
$this->grade_items[10] = $grade_item;
+
+ // Quiz grade_item (course_module = 7).
+ // id = 11
+ $grade_item = new stdClass();
+
+ $grade_item->courseid = $this->course->id;
+ $grade_item->categoryid = $course_category->id;
+ $grade_item->itemname = 'Quiz grade item';
+ $grade_item->itemtype = 'mod';
+ $grade_item->itemmodule = $this->course_module[7]->modname;
+ $grade_item->iteminstance = $this->course_module[7]->instance;
+ $grade_item->itemnumber = 0;
+ $grade_item->gradetype = GRADE_TYPE_VALUE;
+ $grade_item->grademin = 0;
+ $grade_item->grademax = 100;
+ $grade_item->locked = 0;
+ $grade_item->iteminfo = 'Quiz grade item used for unit testing';
+ $grade_item->timecreated = time();
+ $grade_item->timemodified = time();
+ $grade_item->sortorder = 11;
+
+ $grade_item->id = $DB->insert_record('grade_items', $grade_item);
+ $this->grade_items[11] = $grade_item;
}
/**
$this->grade_outcomes[] = $grade_outcome;
}
}
-
-
$this->sub_test_grade_category_set_locked();
$this->sub_test_grade_category_is_hidden();
$this->sub_test_grade_category_set_hidden();
+ $this->sub_test_grade_category_can_control_visibility();
//this won't work until MDL-11837 is complete
//$this->sub_test_grade_category_generate_grades();
$this->assertEquals(true, $category->grade_item->is_hidden());
}
+ protected function sub_test_grade_category_can_control_visibility() {
+ $category = new grade_category($this->grade_categories[0]);
+ $this->assertTrue($category->can_control_visibility());
+ }
+
//beware: adding a duplicate course category messes up the data in a way that's hard to recover from
protected function sub_test_grade_category_insert_course_category() {
$grade_category = new grade_category();
$this->sub_test_grade_item_get_calculation();
$this->sub_test_grade_item_compute();
$this->sub_test_update_final_grade();
+ $this->sub_test_grade_item_can_control_visibility();
}
protected function sub_test_grade_item_construct() {
$last_grade_item = end($this->grade_items);
$this->assertEquals($grade_item->id, $last_grade_item->id + 1);
- $this->assertEquals(11, $grade_item->sortorder);
+ $this->assertEquals(12, $grade_item->sortorder);
//keep our reference collection the same as what is in the database
$this->grade_items[] = $grade_item;
$this->assertEquals($min, $grade_grade->rawgrademin);
$this->assertEquals($max, $grade_grade->rawgrademax);
}
+
+ protected function sub_test_grade_item_can_control_visibility() {
+ // Grade item 0 == Course module 0 == Assignment.
+ $grade_item = new grade_item($this->grade_items[0], false);
+ $this->assertTrue($grade_item->can_control_visibility());
+
+ // Grade item == Course module 7 == Quiz.
+ $grade_item = new grade_item($this->grade_items[11], false);
+ $this->assertFalse($grade_item->can_control_visibility());
+ }
}
*
* @category string
* @param bool $forcereload shall the singleton be released and new instance created instead?
- * @return string_manager
+ * @return core_string_manager
*/
function get_string_manager($forcereload=false) {
global $CFG;
$translist = explode(',', $CFG->langlist);
}
- if (empty($CFG->langmenucachefile)) {
- $langmenucache = $CFG->cachedir . '/languages';
- } else {
- $langmenucache = $CFG->langmenucachefile;
- }
-
- $singleton = new core_string_manager($CFG->langotherroot, $CFG->langlocalroot,
- !empty($CFG->langstringcache), $translist, $langmenucache);
+ $singleton = new core_string_manager_standard($CFG->langotherroot, $CFG->langlocalroot, $translist);
} else {
- $singleton = new install_string_manager();
+ $singleton = new core_string_manager_install();
}
}
return $singleton;
}
-
-/**
- * Interface for string manager
- *
- * Interface describing class which is responsible for getting
- * of localised strings from language packs.
- *
- * @package core
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-interface string_manager {
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null);
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- *
- * Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component);
-
- /**
- * Returns a localised list of all country names, sorted by country keys.
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null);
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * iso6392: three-letter language code (ISO 639-2/T) => translated name.
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6392');
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true);
-
- /**
- * Returns localised list of installed translations
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false);
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null);
-
- /**
- * Load all strings for one component
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false);
-
- /**
- * Invalidates all caches, should the implementation use any
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false);
-
- /**
- * Returns string revision counter, this is incremented after any
- * string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision();
-}
-
-
-/**
- * Standard string_manager implementation
- *
- * Implements string_manager with getting and printing localised strings
- *
- * @package core
- * @category string
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class core_string_manager implements string_manager {
- /** @var string location of all packs except 'en' */
- protected $otherroot;
- /** @var string location of all lang pack local modifications */
- protected $localroot;
- /** @var cache lang string cache - it will be optimised more later */
- protected $cache;
- /** @var int get_string() counter */
- protected $countgetstring = 0;
- /** @var bool use disk cache */
- protected $usecache;
- /** @var array limit list of translations */
- protected $translist;
- /** @var string location of a file that caches the list of available translations */
- protected $menucache;
-
- /**
- * Create new instance of string manager
- *
- * @param string $otherroot location of downlaoded lang packs - usually $CFG->dataroot/lang
- * @param string $localroot usually the same as $otherroot
- * @param bool $usecache use disk cache
- * @param array $translist limit list of visible translations
- * @param string $menucache the location of a file that caches the list of available translations
- */
- public function __construct($otherroot, $localroot, $usecache, $translist, $menucache) {
- $this->otherroot = $otherroot;
- $this->localroot = $localroot;
- $this->usecache = $usecache;
- $this->translist = $translist;
- $this->menucache = $menucache;
-
- if ($this->usecache) {
- // We can use a proper cache, establish the cache using the 'String cache' definition.
- $this->cache = cache::make('core', 'string');
- } else {
- // We only want a cache for the length of the request, create a static cache.
- $options = array(
- 'simplekeys' => true,
- 'simpledata' => true
- );
- $this->cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'string', array(), $options);
- }
- }
-
- /**
- * Returns list of all explicit parent languages for the given language.
- *
- * English (en) is considered as the top implicit parent of all language packs
- * and is not included in the returned list. The language itself is appended to the
- * end of the list. The method is aware of circular dependency risk.
- *
- * @see self::populate_parent_languages()
- * @param string $lang the code of the language
- * @return array all explicit parent languages with the lang itself appended
- */
- public function get_language_dependencies($lang) {
- return $this->populate_parent_languages($lang);
- }
-
- /**
- * Load all strings for one component
- *
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false) {
- global $CFG;
-
- list($plugintype, $pluginname) = core_component::normalize_component($component);
- if ($plugintype == 'core' and is_null($pluginname)) {
- $component = 'core';
- } else {
- $component = $plugintype . '_' . $pluginname;
- }
-
- $cachekey = $lang.'_'.$component;
-
- if (!$disablecache and !$disablelocal) {
- $string = $this->cache->get($cachekey);
- if ($string) {
- return $string;
- }
- }
-
- // No cache found - let us merge all possible sources of the strings.
- if ($plugintype === 'core') {
- $file = $pluginname;
- if ($file === null) {
- $file = 'moodle';
- }
- $string = array();
- // First load english pack.
- if (!file_exists("$CFG->dirroot/lang/en/$file.php")) {
- return array();
- }
- include("$CFG->dirroot/lang/en/$file.php");
- $originalkeys = array_keys($string);
- $originalkeys = array_flip($originalkeys);
-
- // And then corresponding local if present and allowed.
- if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
- include("$this->localroot/en_local/$file.php");
- }
- // Now loop through all langs in correct order.
- $deps = $this->get_language_dependencies($lang);
- foreach ($deps as $dep) {
- // The main lang string location.
- if (file_exists("$this->otherroot/$dep/$file.php")) {
- include("$this->otherroot/$dep/$file.php");
- }
- if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
- include("$this->localroot/{$dep}_local/$file.php");
- }
- }
-
- } else {
- if (!$location = core_component::get_plugin_directory($plugintype, $pluginname) or !is_dir($location)) {
- return array();
- }
- if ($plugintype === 'mod') {
- // Bloody mod hack.
- $file = $pluginname;
- } else {
- $file = $plugintype . '_' . $pluginname;
- }
- $string = array();
- // First load English pack.
- if (!file_exists("$location/lang/en/$file.php")) {
- // English pack does not exist, so do not try to load anything else.
- return array();
- }
- include("$location/lang/en/$file.php");
- $originalkeys = array_keys($string);
- $originalkeys = array_flip($originalkeys);
- // And then corresponding local english if present.
- if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
- include("$this->localroot/en_local/$file.php");
- }
-
- // Now loop through all langs in correct order.
- $deps = $this->get_language_dependencies($lang);
- foreach ($deps as $dep) {
- // Legacy location - used by contrib only.
- if (file_exists("$location/lang/$dep/$file.php")) {
- include("$location/lang/$dep/$file.php");
- }
- // The main lang string location.
- if (file_exists("$this->otherroot/$dep/$file.php")) {
- include("$this->otherroot/$dep/$file.php");
- }
- // Local customisations.
- if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
- include("$this->localroot/{$dep}_local/$file.php");
- }
- }
- }
-
- // We do not want any extra strings from other languages - everything must be in en lang pack.
- $string = array_intersect_key($string, $originalkeys);
-
- if (!$disablelocal) {
- // Now we have a list of strings from all possible sources. put it into both in-memory and on-disk
- // caches so we do not need to do all this merging and dependencies resolving again.
- $this->cache->set($cachekey, $string);
- }
- return $string;
- }
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- * Note: Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component) {
- $lang = current_language();
- $string = $this->load_component_strings($component, $lang);
- return isset($string[$identifier]);
- }
-
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null) {
- $this->countgetstring++;
- // There are very many uses of these time formating strings without the 'langconfig' component,
- // it would not be reasonable to expect that all of them would be converted during 2.0 migration.
- static $langconfigstrs = array(
- 'strftimedate' => 1,
- 'strftimedatefullshort' => 1,
- 'strftimedateshort' => 1,
- 'strftimedatetime' => 1,
- 'strftimedatetimeshort' => 1,
- 'strftimedaydate' => 1,
- 'strftimedaydatetime' => 1,
- 'strftimedayshort' => 1,
- 'strftimedaytime' => 1,
- 'strftimemonthyear' => 1,
- 'strftimerecent' => 1,
- 'strftimerecentfull' => 1,
- 'strftimetime' => 1);
-
- if (empty($component)) {
- if (isset($langconfigstrs[$identifier])) {
- $component = 'langconfig';
- } else {
- $component = 'moodle';
- }
- }
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- $string = $this->load_component_strings($component, $lang);
-
- if (!isset($string[$identifier])) {
- if ($component === 'pix' or $component === 'core_pix') {
- // This component contains only alt tags for emoticons, not all of them are supposed to be defined.
- return '';
- }
- if ($identifier === 'parentlanguage' and ($component === 'langconfig' or $component === 'core_langconfig')) {
- // Identifier parentlanguage is a special string, undefined means use English if not defined.
- return 'en';
- }
- if ($this->usecache) {
- // Maybe the on-disk cache is dirty - let the last attempt be to find the string in original sources,
- // do NOT write the results to disk cache because it may end up in race conditions see MDL-31904.
- $this->usecache = false;
- $string = $this->load_component_strings($component, $lang, true);
- $this->usecache = true;
- }
- if (!isset($string[$identifier])) {
- // The string is still missing - should be fixed by developer.
- list($plugintype, $pluginname) = core_component::normalize_component($component);
- if ($plugintype == 'core') {
- $file = "lang/en/{$component}.php";
- } else if ($plugintype == 'mod') {
- $file = "mod/{$pluginname}/lang/en/{$pluginname}.php";
- } else {
- $path = core_component::get_plugin_directory($plugintype, $pluginname);
- $file = "{$path}/lang/en/{$plugintype}_{$pluginname}.php";
- }
- debugging("Invalid get_string() identifier: '{$identifier}' or component '{$component}'. " .
- "Perhaps you are missing \$string['{$identifier}'] = ''; in {$file}?", DEBUG_DEVELOPER);
- return "[[$identifier]]";
- }
- }
-
- $string = $string[$identifier];
-
- if ($a !== null) {
- // Process array's and objects (except lang_strings).
- if (is_array($a) or (is_object($a) && !($a instanceof lang_string))) {
- $a = (array)$a;
- $search = array();
- $replace = array();
- foreach ($a as $key => $value) {
- if (is_int($key)) {
- // We do not support numeric keys - sorry!
- continue;
- }
- if (is_array($value) or (is_object($value) && !($value instanceof lang_string))) {
- // We support just string or lang_string as value.
- continue;
- }
- $search[] = '{$a->'.$key.'}';
- $replace[] = (string)$value;
- }
- if ($search) {
- $string = str_replace($search, $replace, $string);
- }
- } else {
- $string = str_replace('{$a}', (string)$a, $string);
- }
- }
-
- return $string;
- }
-
- /**
- * Returns information about the string_manager performance.
- *
- * @return array
- */
- public function get_performance_summary() {
- return array(array(
- 'langcountgetstring' => $this->countgetstring,
- ), array(
- 'langcountgetstring' => 'get_string calls',
- ));
- }
-
- /**
- * Returns a localised list of all country names, sorted by localised name.
- *
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null) {
- global $CFG;
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- $countries = $this->load_component_strings('core_countries', $lang);
- core_collator::asort($countries);
- if (!$returnall and !empty($CFG->allcountrycodes)) {
- $enabled = explode(',', $CFG->allcountrycodes);
- $return = array();
- foreach ($enabled as $c) {
- if (isset($countries[$c])) {
- $return[$c] = $countries[$c];
- }
- }
- return $return;
- }
-
- return $countries;
- }
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * - iso6392: three-letter language code (ISO 639-2/T) => translated name
- * - iso6391: two-letter langauge code (ISO 639-1) => translated name
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6391') {
- if ($lang === null) {
- $lang = current_language();
- }
-
- if ($standard === 'iso6392') {
- $langs = $this->load_component_strings('core_iso6392', $lang);
- ksort($langs);
- return $langs;
-
- } else if ($standard === 'iso6391') {
- $langs2 = $this->load_component_strings('core_iso6392', $lang);
- static $mapping = array('aar' => 'aa', 'abk' => 'ab', 'afr' => 'af', 'aka' => 'ak', 'sqi' => 'sq', 'amh' => 'am', 'ara' => 'ar', 'arg' => 'an', 'hye' => 'hy',
- 'asm' => 'as', 'ava' => 'av', 'ave' => 'ae', 'aym' => 'ay', 'aze' => 'az', 'bak' => 'ba', 'bam' => 'bm', 'eus' => 'eu', 'bel' => 'be', 'ben' => 'bn', 'bih' => 'bh',
- 'bis' => 'bi', 'bos' => 'bs', 'bre' => 'br', 'bul' => 'bg', 'mya' => 'my', 'cat' => 'ca', 'cha' => 'ch', 'che' => 'ce', 'zho' => 'zh', 'chu' => 'cu', 'chv' => 'cv',
- 'cor' => 'kw', 'cos' => 'co', 'cre' => 'cr', 'ces' => 'cs', 'dan' => 'da', 'div' => 'dv', 'nld' => 'nl', 'dzo' => 'dz', 'eng' => 'en', 'epo' => 'eo', 'est' => 'et',
- 'ewe' => 'ee', 'fao' => 'fo', 'fij' => 'fj', 'fin' => 'fi', 'fra' => 'fr', 'fry' => 'fy', 'ful' => 'ff', 'kat' => 'ka', 'deu' => 'de', 'gla' => 'gd', 'gle' => 'ga',
- 'glg' => 'gl', 'glv' => 'gv', 'ell' => 'el', 'grn' => 'gn', 'guj' => 'gu', 'hat' => 'ht', 'hau' => 'ha', 'heb' => 'he', 'her' => 'hz', 'hin' => 'hi', 'hmo' => 'ho',
- 'hrv' => 'hr', 'hun' => 'hu', 'ibo' => 'ig', 'isl' => 'is', 'ido' => 'io', 'iii' => 'ii', 'iku' => 'iu', 'ile' => 'ie', 'ina' => 'ia', 'ind' => 'id', 'ipk' => 'ik',
- 'ita' => 'it', 'jav' => 'jv', 'jpn' => 'ja', 'kal' => 'kl', 'kan' => 'kn', 'kas' => 'ks', 'kau' => 'kr', 'kaz' => 'kk', 'khm' => 'km', 'kik' => 'ki', 'kin' => 'rw',
- 'kir' => 'ky', 'kom' => 'kv', 'kon' => 'kg', 'kor' => 'ko', 'kua' => 'kj', 'kur' => 'ku', 'lao' => 'lo', 'lat' => 'la', 'lav' => 'lv', 'lim' => 'li', 'lin' => 'ln',
- 'lit' => 'lt', 'ltz' => 'lb', 'lub' => 'lu', 'lug' => 'lg', 'mkd' => 'mk', 'mah' => 'mh', 'mal' => 'ml', 'mri' => 'mi', 'mar' => 'mr', 'msa' => 'ms', 'mlg' => 'mg',
- 'mlt' => 'mt', 'mon' => 'mn', 'nau' => 'na', 'nav' => 'nv', 'nbl' => 'nr', 'nde' => 'nd', 'ndo' => 'ng', 'nep' => 'ne', 'nno' => 'nn', 'nob' => 'nb', 'nor' => 'no',
- 'nya' => 'ny', 'oci' => 'oc', 'oji' => 'oj', 'ori' => 'or', 'orm' => 'om', 'oss' => 'os', 'pan' => 'pa', 'fas' => 'fa', 'pli' => 'pi', 'pol' => 'pl', 'por' => 'pt',
- 'pus' => 'ps', 'que' => 'qu', 'roh' => 'rm', 'ron' => 'ro', 'run' => 'rn', 'rus' => 'ru', 'sag' => 'sg', 'san' => 'sa', 'sin' => 'si', 'slk' => 'sk', 'slv' => 'sl',
- 'sme' => 'se', 'smo' => 'sm', 'sna' => 'sn', 'snd' => 'sd', 'som' => 'so', 'sot' => 'st', 'spa' => 'es', 'srd' => 'sc', 'srp' => 'sr', 'ssw' => 'ss', 'sun' => 'su',
- 'swa' => 'sw', 'swe' => 'sv', 'tah' => 'ty', 'tam' => 'ta', 'tat' => 'tt', 'tel' => 'te', 'tgk' => 'tg', 'tgl' => 'tl', 'tha' => 'th', 'bod' => 'bo', 'tir' => 'ti',
- 'ton' => 'to', 'tsn' => 'tn', 'tso' => 'ts', 'tuk' => 'tk', 'tur' => 'tr', 'twi' => 'tw', 'uig' => 'ug', 'ukr' => 'uk', 'urd' => 'ur', 'uzb' => 'uz', 'ven' => 've',
- 'vie' => 'vi', 'vol' => 'vo', 'cym' => 'cy', 'wln' => 'wa', 'wol' => 'wo', 'xho' => 'xh', 'yid' => 'yi', 'yor' => 'yo', 'zha' => 'za', 'zul' => 'zu');
- $langs1 = array();
- foreach ($mapping as $c2 => $c1) {
- $langs1[$c1] = $langs2[$c2];
- }
- ksort($langs1);
- return $langs1;
-
- } else {
- debugging('Unsupported $standard parameter in get_list_of_languages() method: '.$standard);
- }
-
- return array();
- }
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true) {
-
- if (strpos($lang, '_local') !== false) {
- // Local packs are not real translations.
- return false;
- }
- if (!$includeall and !empty($this->translist)) {
- if (!in_array($lang, $this->translist)) {
- return false;
- }
- }
- if ($lang === 'en') {
- // Part of distribution.
- return true;
- }
- return file_exists("$this->otherroot/$lang/langconfig.php");
- }
-
- /**
- * Returns localised list of installed translations
- *
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false) {
- global $CFG;
-
- $languages = array();
-
- if (!empty($CFG->langcache) and is_readable($this->menucache)) {
- // Try to re-use the cached list of all available languages.
- $cachedlist = json_decode(file_get_contents($this->menucache), true);
-
- if (is_array($cachedlist) and !empty($cachedlist)) {
- // The cache file is restored correctly.
-
- if (!$returnall and !empty($this->translist)) {
- // Return just enabled translations.
- foreach ($cachedlist as $langcode => $langname) {
- if (in_array($langcode, $this->translist)) {
- $languages[$langcode] = $langname;
- }
- }
- return $languages;
-
- } else {
- // Return all translations.
- return $cachedlist;
- }
- }
- }
-
- // The cached list of languages is not available, let us populate the list.
- if (!$returnall and !empty($this->translist)) {
- // Return only some translations.
- foreach ($this->translist as $lang) {
- $lang = trim($lang); // Just trim spaces to be a bit more permissive.
- if (strstr($lang, '_local') !== false) {
- continue;
- }
- if (strstr($lang, '_utf8') !== false) {
- continue;
- }
- if ($lang !== 'en' and !file_exists("$this->otherroot/$lang/langconfig.php")) {
- // Some broken or missing lang - can not switch to it anyway.
- continue;
- }
- $string = $this->load_component_strings('langconfig', $lang);
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
- }
- unset($string);
- }
-
- } else {
- // Return all languages available in system.
- $langdirs = get_list_of_plugins('', '', $this->otherroot);
-
- $langdirs = array_merge($langdirs, array("$CFG->dirroot/lang/en" => 'en'));
- // Sort all.
-
- // Loop through all langs and get info.
- foreach ($langdirs as $lang) {
- if (strstr($lang, '_local') !== false) {
- continue;
- }
- if (strstr($lang, '_utf8') !== false) {
- continue;
- }
- $string = $this->load_component_strings('langconfig', $lang);
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
- }
- unset($string);
- }
-
- if (!empty($CFG->langcache) and !empty($this->menucache)) {
- // Cache the list so that it can be used next time.
- core_collator::asort($languages);
- check_dir_exists(dirname($this->menucache), true, true);
- file_put_contents($this->menucache, json_encode($languages));
- @chmod($this->menucache, $CFG->filepermissions);
- }
- }
-
- core_collator::asort($languages);
-
- return $languages;
- }
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null) {
- if ($lang === null) {
- $lang = current_language();
- }
-
- $currencies = $this->load_component_strings('core_currencies', $lang);
- asort($currencies);
-
- return $currencies;
- }
-
- /**
- * Clears both in-memory and on-disk caches
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false) {
- global $CFG;
- require_once("$CFG->libdir/filelib.php");
-
- // Clear the on-disk disk with aggregated string files.
- $this->cache->purge();
-
- if (!$phpunitreset) {
- // Increment the revision counter.
- $langrev = get_config('core', 'langrev');
- $next = time();
- if ($langrev !== false and $next <= $langrev and $langrev - $next < 60*60) {
- // This resolves problems when reset is requested repeatedly within 1s,
- // the < 1h condition prevents accidental switching to future dates
- // because we might not recover from it.
- $next = $langrev+1;
- }
- set_config('langrev', $next);
- }
-
- // Clear the cache containing the list of available translations
- // and re-populate it again.
- fulldelete($this->menucache);
- $this->get_list_of_translations(true);
-
- // Lang packs use PHP files in dataroot, it is better to invalidate opcode caches.
- if (function_exists('opcache_reset')) {
- opcache_reset();
- }
- }
-
- /**
- * Returns string revision counter, this is incremented after any string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision() {
- global $CFG;
- if (isset($CFG->langrev)) {
- return (int)$CFG->langrev;
- } else {
- return -1;
- }
- }
-
- // End of external API.
-
- /**
- * Helper method that recursively loads all parents of the given language.
- *
- * @see self::get_language_dependencies()
- * @param string $lang language code
- * @param array $stack list of parent languages already populated in previous recursive calls
- * @return array list of all parents of the given language with the $lang itself added as the last element
- */
- protected function populate_parent_languages($lang, array $stack = array()) {
-
- // English does not have a parent language.
- if ($lang === 'en') {
- return $stack;
- }
-
- // Prevent circular dependency (and thence the infinitive recursion loop).
- if (in_array($lang, $stack)) {
- return $stack;
- }
-
- // Load language configuration and look for the explicit parent language.
- if (!file_exists("$this->otherroot/$lang/langconfig.php")) {
- return $stack;
- }
- $string = array();
- include("$this->otherroot/$lang/langconfig.php");
-
- if (empty($string['parentlanguage']) or $string['parentlanguage'] === 'en') {
- unset($string);
- return array_merge(array($lang), $stack);
-
- } else {
- $parentlang = $string['parentlanguage'];
- unset($string);
- return $this->populate_parent_languages($parentlang, array_merge(array($lang), $stack));
- }
- }
-}
-
-
-/**
- * Fetches minimum strings for installation
- *
- * Minimalistic string fetching implementation
- * that is used in installer before we fetch the wanted
- * language pack from moodle.org lang download site.
- *
- * @package core
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class install_string_manager implements string_manager {
- /** @var string location of pre-install packs for all langs */
- protected $installroot;
-
- /**
- * Crate new instance of install string manager
- */
- public function __construct() {
- global $CFG;
- $this->installroot = "$CFG->dirroot/install/lang";
- }
-
- /**
- * Load all strings for one component
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false) {
- // Not needed in installer.
- return array();
- }
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- *
- * Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component) {
- // Simple old style hack ;).
- $str = get_string($identifier, $component);
- return (strpos($str, '[[') === false);
- }
-
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null) {
- if (!$component) {
- $component = 'moodle';
- }
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- // Get parent lang.
- $parent = '';
- if ($lang !== 'en' and $identifier !== 'parentlanguage' and $component !== 'langconfig') {
- if (file_exists("$this->installroot/$lang/langconfig.php")) {
- $string = array();
- include("$this->installroot/$lang/langconfig.php");
- if (isset($string['parentlanguage'])) {
- $parent = $string['parentlanguage'];
- }
- unset($string);
- }
- }
-
- // Include en string first.
- if (!file_exists("$this->installroot/en/$component.php")) {
- return "[[$identifier]]";
- }
- $string = array();
- include("$this->installroot/en/$component.php");
-
- // Now override en with parent if defined.
- if ($parent and $parent !== 'en' and file_exists("$this->installroot/$parent/$component.php")) {
- include("$this->installroot/$parent/$component.php");
- }
-
- // Finally override with requested language.
- if ($lang !== 'en' and file_exists("$this->installroot/$lang/$component.php")) {
- include("$this->installroot/$lang/$component.php");
- }
-
- if (!isset($string[$identifier])) {
- return "[[$identifier]]";
- }
-
- $string = $string[$identifier];
-
- if ($a !== null) {
- if (is_object($a) or is_array($a)) {
- $a = (array)$a;
- $search = array();
- $replace = array();
- foreach ($a as $key => $value) {
- if (is_int($key)) {
- // We do not support numeric keys - sorry!
- continue;
- }
- $search[] = '{$a->'.$key.'}';
- $replace[] = (string)$value;
- }
- if ($search) {
- $string = str_replace($search, $replace, $string);
- }
- } else {
- $string = str_replace('{$a}', (string)$a, $string);
- }
- }
-
- return $string;
- }
-
- /**
- * Returns a localised list of all country names, sorted by country keys.
- *
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null) {
- // Not used in installer.
- return array();
- }
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * iso6392: three-letter language code (ISO 639-2/T) => translated name.
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6392') {
- // Not used in installer.
- return array();
- }
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true) {
- return file_exists($this->installroot.'/'.$lang.'/langconfig.php');
- }
-
- /**
- * Returns localised list of installed translations
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false) {
- // Return all is ignored here - we need to know all langs in installer.
- $languages = array();
- // Get raw list of lang directories.
- $langdirs = get_list_of_plugins('install/lang');
- asort($langdirs);
- // Get some info from each lang.
- foreach ($langdirs as $lang) {
- if (file_exists($this->installroot.'/'.$lang.'/langconfig.php')) {
- $string = array();
- include($this->installroot.'/'.$lang.'/langconfig.php');
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('.$lang.')';
- }
- }
- }
- // Return array.
- return $languages;
- }
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null) {
- // Not used in installer.
- return array();
- }
-
- /**
- * This implementation does not use any caches.
- *
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false) {
- // Nothing to do.
- }
-
- /**
- * Returns string revision counter, this is incremented after any string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision() {
- return -1;
- }
-}
-
-
/**
* Returns a localized string.
*
return core_component::is_valid_plugin_name('tool', $name);
}
-/**
- * Get a list of all the plugins of a given type that contain a particular file.
- *
- * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
- * @param string $file the name of file that must be present in the plugin.
- * (e.g. 'view.php', 'db/install.xml').
- * @param bool $include if true (default false), the file will be include_once-ed if found.
- * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
- * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
- */
-function get_plugin_list_with_file($plugintype, $file, $include = false) {
- global $CFG; // Necessary in case it is referenced by include()d PHP scripts.
-
- $plugins = array();
-
- foreach (core_component::get_plugin_list($plugintype) as $plugin => $dir) {
- $path = $dir . '/' . $file;
- if (file_exists($path)) {
- if ($include) {
- include_once($path);
- }
- $plugins[$plugin] = $path;
- }
- }
-
- return $plugins;
-}
-
/**
* Get a list of all the plugins of a given type that define a certain API function
* in a certain file. The plugin component names and function names are returned.
*/
function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php') {
$pluginfunctions = array();
- foreach (get_plugin_list_with_file($plugintype, $file, true) as $plugin => $notused) {
+ $pluginswithfile = core_component::get_plugin_list_with_file($plugintype, $file, true);
+ foreach ($pluginswithfile as $plugin => $notused) {
$fullfunction = $plugintype . '_' . $plugin . '_' . $function;
if (function_exists($fullfunction)) {
}
/**
- * Determine if moodle installation requires update
+ * Determine if moodle installation requires update.
*
- * Checks version numbers of main code and all modules to see
- * if there are any mismatches
+ * Checks version numbers of main code and all plugins to see
+ * if there are any mismatches.
*
* @return bool
*/
function moodle_needs_upgrading() {
- global $CFG, $DB;
+ global $CFG;
if (empty($CFG->version)) {
return true;
}
- // We have to purge plugin related caches now to be sure we have fresh data
- // and new plugins can be detected.
- cache::make('core', 'plugininfo_base')->purge();
- cache::make('core', 'plugininfo_mod')->purge();
- cache::make('core', 'plugininfo_block')->purge();
- cache::make('core', 'plugininfo_filter')->purge();
- cache::make('core', 'plugininfo_repository')->purge();
- cache::make('core', 'plugininfo_portfolio')->purge();
+ // There is no need to purge plugininfo caches here because
+ // these caches are not used during upgrade and they are purged after
+ // every upgrade.
- // Check the main version first.
- $version = null;
- include($CFG->dirroot.'/version.php'); // Defines $version and upgrades.
- if ($version > $CFG->version) {
+ if (empty($CFG->allversionshash)) {
return true;
}
- // Modules.
- $mods = core_component::get_plugin_list('mod');
- $installed = $DB->get_records('modules', array(), '', 'name, version');
- foreach ($mods as $mod => $fullmod) {
- if ($mod === 'NEWMODULE') { // Someone has unzipped the template, ignore it.
- continue;
- }
- $module = new stdClass();
- $plugin = new stdClass();
- if (!is_readable($fullmod.'/version.php')) {
- continue;
- }
- include($fullmod.'/version.php'); // Defines $module with version etc.
- if (!isset($module->version) and isset($plugin->version)) {
- $module = $plugin;
- }
- if (empty($installed[$mod])) {
- return true;
- } else if ($module->version > $installed[$mod]->version) {
- return true;
- }
- }
- unset($installed);
+ $hash = core_component::get_all_versions_hash();
- // Blocks.
- $blocks = core_component::get_plugin_list('block');
- $installed = $DB->get_records('block', array(), '', 'name, version');
- require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
- foreach ($blocks as $blockname => $fullblock) {
- if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it.
- continue;
- }
- if (!is_readable($fullblock.'/version.php')) {
- continue;
- }
- $plugin = new stdClass();
- $plugin->version = null;
- include($fullblock.'/version.php');
- if (empty($installed[$blockname])) {
- return true;
- } else if ($plugin->version > $installed[$blockname]->version) {
- return true;
- }
- }
- unset($installed);
-
- // Now the rest of plugins.
- $plugintypes = core_component::get_plugin_types();
- unset($plugintypes['mod']);
- unset($plugintypes['block']);
-
- $versions = $DB->get_records_menu('config_plugins', array('name' => 'version'), 'plugin', 'plugin, value');
- foreach ($plugintypes as $type => $unused) {
- $plugs = core_component::get_plugin_list($type);
- foreach ($plugs as $plug => $fullplug) {
- $component = $type.'_'.$plug;
- if (!is_readable($fullplug.'/version.php')) {
- continue;
- }
- $plugin = new stdClass();
- include($fullplug.'/version.php'); // Defines $plugin with version etc.
- if (array_key_exists($component, $versions)) {
- $installedversion = $versions[$component];
- } else {
- $installedversion = get_config($component, 'version');
- }
- if (empty($installedversion)) { // New installation.
- return true;
- } else if ($installedversion < $plugin->version) { // Upgrade.
- return true;
- }
- }
- }
-
- return false;
+ return ($hash !== $CFG->allversionshash);
}
/**
}
// Give the local plugins a chance to include some navigation if they want.
- foreach (get_plugin_list_with_file('local', 'lib.php', true) as $plugin => $file) {
+ foreach (core_component::get_plugin_list_with_file('local', 'lib.php', true) as $plugin => $file) {
$function = "local_{$plugin}_extends_navigation";
$oldfunction = "{$plugin}_extends_navigation";
if (function_exists($function)) {
// Portfolio
if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) {
require_once($CFG->libdir . '/portfoliolib.php');
- if (portfolio_instances(true, false)) {
+ if (portfolio_has_visible_instances()) {
$portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING);
$url = new moodle_url('/user/portfolio.php', array('courseid'=>$course->id));
$link= '<a title="' . $title . '" href="' . $url . '">' . $txt . '</a>';
$output .= '<div class="profilingfooter">' . $link . '</div>';
}
- $output .= '<div class="purgecaches"><a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/purgecaches.php?confirm=1&sesskey='.sesskey().'">'.get_string('purgecaches', 'admin').'</a></div>';
+ $purgeurl = new moodle_url('/admin/purgecaches.php', array('confirm' => 1,
+ 'sesskey' => sesskey(), 'returnurl' => $this->page->url->out_as_local_url(false)));
+ $output .= '<div class="purgecaches">' .
+ html_writer::link($purgeurl, get_string('purgecaches', 'admin')) . '</div>';
}
if (!empty($CFG->debugvalidators)) {
// NOTE: this is not a nice hack, $PAGE->url is not always accurate and $FULLME neither, it is not a bug if it fails. --skodak
if (!empty($page->cm->id)) {
$params['cmid'] = $page->cm->id;
}
+ // Strings for drag and drop.
+ $this->strings_for_js(array('movecontent',
+ 'aftercontent',
+ 'emptydragdropregion'),
+ 'moodle');
$page->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
}
}
array('nofilesavailable', 'repository'), array('norepositoriesavailable', 'repository'),
array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'),
array('fileexistsdialog_filemanager', 'repository'), array('renameto', 'repository'),
- array('referencesexist', 'repository')
+ array('referencesexist', 'repository'), array('edit', 'moodle')
));
break;
case 'core_comment':
initialise_cfg();
return;
}
- if ($dbhash !== self::get_version_hash()) {
+ if ($dbhash !== core_component::get_all_versions_hash()) {
// do not set CFG - the only way forward is to drop and reinstall
return;
}
return $instances;
}
+/**
+ * Return whether there are visible instances in portfolio.
+ *
+ * @return bool true when there are some visible instances.
+ */
+function portfolio_has_visible_instances() {
+ global $DB;
+ return $DB->record_exists('portfolio_instance', array('visible' => 1));
+}
+
/**
* Supported formats currently in use.
* Canonical place for a list of all formats
// Remove some absolute paths from message and debugging info.
$searches = array();
$replaces = array();
- $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir',
- 'langmenucachefile', 'langcacheroot', 'dataroot', 'dirroot');
+ $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir', 'dataroot', 'dirroot');
foreach ($cfgnames as $cfgname) {
if (property_exists($CFG, $cfgname)) {
$searches[] = $CFG->$cfgname;
}
} else if ($newlimit == MEMORY_HUGE) {
+ // MEMORY_HUGE uses 2G or MEMORY_EXTRA, whichever is bigger.
$newlimit = get_real_size('2G');
+ if (!empty($CFG->extramemorylimit)) {
+ $extra = get_real_size($CFG->extramemorylimit);
+ if ($extra > $newlimit) {
+ $newlimit = $extra;
+ }
+ }
} else {
$newlimit = get_real_size($newlimit);
return false;
}
- $hash = self::get_version_hash();
+ $hash = core_component::get_all_versions_hash();
$oldhash = file_get_contents($datarootpath . '/versionshash.txt');
if ($hash !== $oldhash) {
global $CFG;
$framework = self::get_framework();
- $hash = self::get_version_hash();
+ $hash = core_component::get_all_versions_hash();
// add test db flag
set_config($framework . 'test', $hash);
}
}
}
-
- /**
- * Calculate unique version hash for all plugins and core.
- * @static
- * @return string sha1 hash
- */
- public static function get_version_hash() {
- global $CFG;
-
- if (self::$versionhash) {
- return self::$versionhash;
- }
-
- $versions = array();
-
- // main version first
- $version = null;
- include($CFG->dirroot.'/version.php');
- $versions['core'] = $version;
-
- // modules
- $mods = core_component::get_plugin_list('mod');
- ksort($mods);
- foreach ($mods as $mod => $fullmod) {
- $module = new stdClass();
- $module->version = null;
- include($fullmod.'/version.php');
- $versions[$mod] = $module->version;
- }
-
- // now the rest of plugins
- $plugintypes = core_component::get_plugin_types();
- unset($plugintypes['mod']);
- ksort($plugintypes);
- foreach ($plugintypes as $type => $unused) {
- $plugs = core_component::get_plugin_list($type);
- ksort($plugs);
- foreach ($plugs as $plug => $fullplug) {
- $plugin = new stdClass();
- $plugin->version = null;
- @include($fullplug.'/version.php');
- $versions[$plug] = $plugin->version;
- }
- }
-
- self::$versionhash = sha1(serialize($versions));
-
- return self::$versionhash;
- }
-
}
$this->assertTrue($result);
$permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
$this->assertEmpty($permission);
+
+ // Test event trigger.
+ $rolecapabilityevent = \core\event\role_capabilities_updated::create(array('context' => $syscontext,
+ 'objectid' => $student->id,
+ 'other' => array('name' => $student->shortname)
+ ));
+ $expectedlegacylog = array(SITEID, 'role', 'view', 'admin/roles/define.php?action=view&roleid=' . $student->id,
+ $student->shortname, '', $user->id);
+ $rolecapabilityevent->set_legacy_logdata($expectedlegacylog);
+ $rolecapabilityevent->add_record_snapshot('role', $student);
+
+ $sink = $this->redirectEvents();
+ $rolecapabilityevent->trigger();
+ $events = $sink->get_events();
+ $sink->close();
+ $event = array_pop($events);
+
+ $this->assertInstanceOf('\core\event\role_capabilities_updated', $event);
+ $expectedurl = new moodle_url('admin/roles/define.php', array('action' => 'view', 'roleid' => $student->id));
+ $this->assertEquals($expectedurl, $event->get_url());
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
$this->assertSame('', $event->other['component']);
$this->assertEquals(0, $event->other['itemid']);
$this->assertSame('role_assigned', $event::get_legacy_eventname());
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
+ $expectedlegacylog = array($course->id, 'role', 'assign',
+ 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
* Test role unassigning.
*/
public function test_role_unassign() {
- global $DB;
+ global $DB, $USER;
$this->resetAfterTest();
$this->assertCount(3, $event->other);
$this->assertSame('', $event->other['component']);
$this->assertEquals(0, $event->other['itemid']);
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
+ $expectedlegacylog = array($course->id, 'role', 'unassign',
+ 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
$this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
$this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
+ // Delete role and get event.
+ $sink = $this->redirectEvents();
$result = delete_role($role->id);
+ $events = $sink->get_events();
+ $sink->close();
+ $event = array_pop($events);
+
$this->assertTrue($result);
$this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
$this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
$this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
$this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
$this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
+
+ // Test triggered event.
+ $this->assertInstanceOf('\core\event\role_deleted', $event);
+ $this->assertSame('role', $event->target);
+ $this->assertSame('role', $event->objecttable);
+ $this->assertSame($role->id, $event->objectid);
+ $this->assertEquals(context_system::instance(), $event->get_context());
+ $this->assertSame($role->name, $event->other['name']);
+ $this->assertSame($role->shortname, $event->other['shortname']);
+ $this->assertSame($role->description, $event->other['description']);
+ $this->assertSame($role->archetype, $event->other['archetype']);
+
+ $expectedlegacylog = array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$role->id,
+ $role->shortname, '');
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
* Test allowing of role assignments.
*/
public function test_allow_assign() {
- global $DB;
+ global $DB, $CFG;
$this->resetAfterTest();
$this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
allow_assign($otherid, $student->id);
$this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
+
+ // Test event trigger.
+ $allowroleassignevent = \core\event\role_allow_assign_updated::create(array('context' => context_system::instance()));
+ $sink = $this->redirectEvents();
+ $allowroleassignevent->trigger();
+ $events = $sink->get_events();
+ $sink->close();
+ $event = array_pop($events);
+ $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event);
+ $mode = 'assign';
+ $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
+ $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
* Test allowing of role overrides.
*/
public function test_allow_override() {
- global $DB;
+ global $DB, $CFG;
$this->resetAfterTest();
$this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
allow_override($otherid, $student->id);
$this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
+
+ // Test event trigger.
+ $allowroleassignevent = \core\event\role_allow_override_updated::create(array('context' => context_system::instance()));
+ $sink = $this->redirectEvents();
+ $allowroleassignevent->trigger();
+ $events = $sink->get_events();
+ $sink->close();
+ $event = array_pop($events);
+ $this->assertInstanceOf('\core\event\role_allow_override_updated', $event);
+ $mode = 'override';
+ $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
+ $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
* Test allowing of role switching.
*/
public function test_allow_switch() {
- global $DB;
+ global $DB, $CFG;
$this->resetAfterTest();
$this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
allow_switch($otherid, $student->id);
$this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
+
+ // Test event trigger.
+ $allowroleassignevent = \core\event\role_allow_switch_updated::create(array('context' => context_system::instance()));
+ $sink = $this->redirectEvents();
+ $allowroleassignevent->trigger();
+ $events = $sink->get_events();
+ $sink->close();
+ $event = array_pop($events);
+ $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event);
+ $mode = 'switch';
+ $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
+ $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
+ $this->assertEventLegacyLogData($expectedlegacylog, $event);
}
/**
*/
class behat_data_generators extends behat_base {
+ const cap_allow = 'Allow';
+ const cap_prevent = 'Prevent';
+ const cap_prohibit = 'Prohibit';
+
/**
* @var testing_data_generator
*/
'switchids' => array('user' => 'userid', 'course' => 'courseid', 'role' => 'roleid')
),
+ 'permission overrides' => array(
+ 'datagenerator' => 'permission_override',
+ 'required' => array('capability', 'permission', 'role', 'contextlevel', 'reference'),
+ 'switchids' => array('role' => 'roleid')
+ ),
'system role assigns' => array(
'datagenerator' => 'system_role_assign',
'required' => array('user', 'role'),
}
+ /**
+ * Allows/denies a capability at the specified context
+ *
+ * @throws Exception
+ * @param array $data
+ * @return void
+ */
+ protected function process_permission_override($data) {
+
+ // Will throw an exception if it does not exist.
+ $context = $this->get_context($data['contextlevel'], $data['reference']);
+
+ switch ($data['permission']) {
+ case self::cap_allow:
+ $permission = CAP_ALLOW;
+ break;
+ case self::cap_prevent:
+ $permission = CAP_PREVENT;
+ break;
+ case self::cap_prohibit:
+ $permission = CAP_PROHIBIT;
+ break;
+ default:
+ throw new Exception('The \'' . $data['permission'] . '\' permission does not exist');
+ break;
+ }
+
+ if (is_null(get_capability_info($data['capability']))) {
+ throw new Exception('The \'' . $data['capability'] . '\' capability does not exist');
+ }
+
+ role_change_permission($data['roleid'], $context, $data['capability'], $permission);
+ }
+
/**
* Assigns a role to a user at system context
*
*/
protected static $lastbrowsersessionstart = 0;
+ /**
+ * @var For actions that should only run once.
+ */
+ protected static $initprocessesfinished = false;
+
/**
* Gives access to moodle codebase, ensures all is ready and sets up the test lock.
*
// Start always in the the homepage.
$this->getSession()->visit($this->locate_path('/'));
+ // Checking that the root path is a Moodle test site.
+ if (self::is_first_scenario()) {
+ $notestsiteexception = new Exception('The base URL (' . $CFG->wwwroot . ') is not a behat test site, ' .
+ 'ensure you started the built-in web server in the correct directory');
+ $this->find("xpath", "//head/child::title[normalize-space(.)='Acceptance test site']", $notestsiteexception);
+
+ self::$initprocessesfinished = true;
+ }
+
// Closing JS dialogs if present. Otherwise they would block this scenario execution.
if ($this->running_javascript()) {
try {
return preg_replace("/(\n)+/s", "\n", $notags);
}
+ /**
+ * Returns whether the first scenario of the suite is running
+ *
+ * @return bool
+ */
+ protected static function is_first_scenario() {
+ return !(self::$initprocessesfinished);
+ }
}
require_once($CFG->libdir.'/completionlib.php');
class core_completionlib_testcase extends advanced_testcase {
+ protected $course;
+ protected $user;
+ protected $module1;
+ protected $module2;
+
protected function mock_setup() {
global $DB, $CFG, $USER;
$USER = (object)array('id' =>314159);
}
+ /**
+ * Create course with user and activities.
+ */
+ protected function setup_data() {
+ global $DB, $CFG;
+
+ $this->resetAfterTest();
+
+ // Create a course with activities.
+ $this->course = $this->getDataGenerator()->create_course();
+ $this->user = $this->getDataGenerator()->create_user();
+ $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+ $this->assertNotEmpty($studentrole);
+
+ // Get manual enrolment plugin and enrol user.
+ require_once($CFG->dirroot.'/enrol/manual/locallib.php');
+ $manplugin = enrol_get_plugin('manual');
+ $maninstance = $DB->get_record('enrol', array('courseid' => $this->course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
+ $manplugin->enrol_user($maninstance, $this->user->id, $studentrole->id);
+ $this->assertEquals(1, $DB->count_records('user_enrolments'));
+
+ $this->module1 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id));
+ $this->module2 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id));
+ }
+
public function test_is_enabled() {
global $CFG;
$this->mock_setup();
public function test_internal_set_data() {
global $DB, $SESSION;
- $this->mock_setup();
+ $this->setup_data();
- $cm = (object)array('course' => 42, 'id' => 13);
- $c = new completion_info((object)array('id' => 42));
+ $this->setUser($this->user);
+ $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
+ $forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+ $cm = get_coursemodule_from_instance('forum', $forum->id);
+ $c = new completion_info($this->course);
// 1) Test with new data.
- $data = (object)array('id'=>0, 'userid' => 314159, 'coursemoduleid' => 99);
- $DB->expects($this->at(0))
- ->method('start_delegated_transaction')
- ->will($this->returnValue($this->getMock('moodle_transaction', array(), array($DB))));
-
- $DB->expects($this->at(1))
- ->method('get_field')
- ->with('course_modules_completion', 'id', array('coursemoduleid'=>99, 'userid'=>314159))
- ->will($this->returnValue(false));
-
- $DB->expects($this->at(2))
- ->method('insert_record')
- ->will($this->returnValue(4));
+ $data = new stdClass();
+ $data->id = 0;
+ $data->userid = $this->user->id;
+ $data->coursemoduleid = $cm->id;
+ $data->completionstate = COMPLETION_COMPLETE;
+ $data->timemodified = time();
$c->internal_set_data($cm, $data);
- $this->assertEquals(4, $data->id);
- $this->assertEquals(array(42 => array(13 => $data)), $SESSION->completioncache);
+ $d1 = $DB->get_field('course_modules_completion', 'id', array('coursemoduleid' => $cm->id));
+ $this->assertEquals($d1, $data->id);
+ $this->assertEquals(array($this->course->id => array($cm->id => $data)), $SESSION->completioncache);
// 2) Test with existing data and for different user (not cached).
unset($SESSION->completioncache);
- $d2 = (object)array('id' => 7, 'userid' => 17, 'coursemoduleid' => 66);
- $DB->expects($this->at(0))
- ->method('start_delegated_transaction')
- ->will($this->returnValue($this->getMock('moodle_transaction', array(), array($DB))));
- $DB->expects($this->at(1))
- ->method('update_record')
- ->with('course_modules_completion', $d2);
- $c->internal_set_data($cm, $d2);
+ $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+ $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
+ $newuser = $this->getDataGenerator()->create_user();
+
+ $d2 = new stdClass();
+ $d2->id = 7;
+ $d2->userid = $newuser->id;
+ $d2->coursemoduleid = $cm2->id;
+ $d2->completionstate = COMPLETION_COMPLETE;
+ $d2->timemodified = time();
+ $c->internal_set_data($cm2, $d2);
$this->assertFalse(isset($SESSION->completioncache));
// 3) Test where it THINKS the data is new (from cache) but actually
// in the database it has been set since.
// 1) Test with new data.
- $data = (object)array('id'=>0, 'userid' => 314159, 'coursemoduleid' => 99);
- $d3 = (object)array('id' => 13, 'userid' => 314159, 'coursemoduleid' => 99);
- $DB->expects($this->at(0))
- ->method('start_delegated_transaction')
- ->will($this->returnValue($this->getMock('moodle_transaction', array(), array($DB))));
- $DB->expects($this->at(1))
- ->method('get_field')
- ->with('course_modules_completion', 'id', array('coursemoduleid' => 99, 'userid' => 314159))
- ->will($this->returnValue(13));
- $DB->expects($this->at(2))
- ->method('update_record')
- ->with('course_modules_completion', $d3);
+ $forum3 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+ $cm3 = get_coursemodule_from_instance('forum', $forum3->id);
+ $newuser2 = $this->getDataGenerator()->create_user();
+ $d3 = new stdClass();
+ $d3->id = 13;
+ $d3->userid = $newuser2->id;
+ $d3->coursemoduleid = $cm3->id;
+ $d3->completionstate = COMPLETION_COMPLETE;
+ $d3->timemodified = time();
+ $DB->insert_record('course_modules_completion', $d3);
$c->internal_set_data($cm, $data);
}
$this->assertTrue($c1->has_activities());
$this->assertFalse($c2->has_activities());
}
+
+ /**
+ * Test course module completion update event.
+ */
+ public function test_course_module_completion_updated_event() {
+ global $USER;
+
+ $this->setup_data();
+ $this->setAdminUser();
+
+ $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
+ $forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+
+ $c = new completion_info($this->course);
+ $activities = $c->get_activities();
+ $this->assertEquals(1, count($activities));
+ $this->assertTrue(isset($activities[$forum->cmid]));
+ $this->assertEquals($activities[$forum->cmid]->name, $forum->name);
+
+ $current = $c->get_data($activities[$forum->cmid], false, $this->user->id);
+ $current->completionstate = COMPLETION_COMPLETE;
+ $current->timemodified = time();
+ $sink = $this->redirectEvents();
+ $c->internal_set_data($activities[$forum->cmid], $current);
+ $events = $sink->get_events();
+ $event = reset($events);
+ $this->assertInstanceOf('\core\event\course_module_completion_updated', $event);
+ $this->assertEquals($forum->cmid, $event->get_record_snapshot('course_modules_completion', $event->objectid)->coursemoduleid);
+ $this->assertEquals($current, $event->get_record_snapshot('course_modules_completion', $event->objectid));
+ $this->assertEquals(context_module::instance($forum->id), $event->get_context());
+ $this->assertEquals($USER->id, $event->userid);
+ $this->assertEquals($this->user->id, $event->other['relateduserid']);
+ $this->assertEventLegacyData($current, $event);
+ }
+
+ /**
+ * Test course completed event.
+ */
+ public function test_course_completed_event() {
+ global $USER;
+
+ $this->setup_data();
+ $this->setAdminUser();
+
+ $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
+ $ccompletion = new completion_completion(array('course' => $this->course->id, 'userid' => $this->user->id));
+
+ // Mark course as complete and get triggered event.
+ $sink = $this->redirectEvents();
+ $ccompletion->mark_complete();
+ $events = $sink->get_events();
+ $event = reset($events);
+
+ $this->assertInstanceOf('\core\event\course_completed', $event);
+ $this->assertEquals($this->course->id, $event->get_record_snapshot('course_completions', $event->objectid)->course);
+ $this->assertEquals($this->course->id, $event->courseid);
+ $this->assertEquals($USER->id, $event->userid);
+ $this->assertEquals($this->user->id, $event->other['relateduserid']);
+ $this->assertEquals(context_course::instance($this->course->id), $event->get_context());
+ $data = $ccompletion->get_record_data();
+ $this->assertEventLegacyData($data, $event);
+ }
}
);
$this->assertSame($expected, $types);
+
+ }
+
+ public function test_get_plugin_list_with_file() {
+ // Force the cache reset.
+ phpunit_util::reset_all_data();
+ $this->resetAfterTest(true);
+
+ $expected = array('completion', 'log', 'loglive', 'outline', 'participation', 'progress', 'stats');
+
+ // Test cold.
+ $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
+ $this->assertEquals($expected, array_keys($list));
+
+ // Test hot.
+ $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
+ $this->assertEquals($expected, array_keys($list));
+
+ // Test with include.
+ $list = core_component::get_plugin_list_with_file('report', 'lib.php', true);
+ $this->assertEquals($expected, array_keys($list));
+
+ // Test missing.
+ $list = core_component::get_plugin_list_with_file('report', 'idontexist.php', true);
+ $this->assertEquals(array(), array_keys($list));
}
}
* @copyright 2013 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class core_string_manager_testcase extends advanced_testcase {
+class core_string_manager_standard_testcase extends advanced_testcase {