Merge branch 'MDL-40403-master' of git://github.com/FMCorz/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 9 Jul 2013 05:38:10 +0000 (13:38 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 9 Jul 2013 05:38:10 +0000 (13:38 +0800)
84 files changed:
admin/cli/install.php
admin/cli/install_database.php
admin/cli/upgrade.php
admin/index.php
admin/plugins.php
admin/settings/security.php
admin/settings/users.php
admin/tool/behat/cli/init.php
admin/tool/capability/classes/settings_form.php [new file with mode: 0644]
admin/tool/capability/index.php
admin/tool/capability/lang/en/tool_capability.php
admin/tool/capability/locallib.php [new file with mode: 0644]
admin/tool/capability/module.js [deleted file]
admin/tool/capability/renderer.php [new file with mode: 0644]
admin/tool/capability/settings.php
admin/tool/capability/styles.css [new file with mode: 0644]
admin/tool/capability/version.php
admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-debug.js [new file with mode: 0644]
admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-min.js [new file with mode: 0644]
admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search.js [new file with mode: 0644]
admin/tool/capability/yui/src/search/build.json [new file with mode: 0644]
admin/tool/capability/yui/src/search/js/search.js [new file with mode: 0644]
admin/tool/capability/yui/src/search/meta/search.json [new file with mode: 0644]
admin/tool/phpunit/cli/init.php
admin/user/user_bulk_cohortadd.php
admin/user/user_bulk_display.php
auth/ldap/auth.php
backup/moodle2/backup_stepslib.php
cache/locallib.php
group/index.php
group/overview.php
lang/en/admin.php
lang/en/moodle.php
lib/accesslib.php
lib/badgeslib.php
lib/classes/component.php
lib/coursecatlib.php
lib/datalib.php
lib/db/install.xml
lib/db/upgrade.php
lib/dml/mssql_native_moodle_database.php
lib/modinfolib.php
lib/moodlelib.php
lib/outputcomponents.php
lib/phpunit/bootstrap.php
lib/phpunit/classes/autoloader.php
lib/phpunit/classes/util.php
lib/phpunit/tests/advanced_test.php
lib/setup.php
lib/tablelib.php
lib/testing/generator/data_generator.php
lib/tests/behat/behat_general.php
lib/tests/moodlelib_test.php
mod/book/edit.php
mod/data/lib.php
mod/data/tests/search_test.php
mod/data/view.php
mod/forum/lib.php
mod/quiz/renderer.php
mod/quiz/report/attemptsreport_table.php
mod/scorm/lib.php
mod/scorm/mod_form.php
mod/scorm/report/basic/report.php
mod/scorm/report/interactions/report.php
mod/workshop/allocation/manual/lib.php
mod/workshop/locallib.php
question/type/calculatedmulti/question.php
question/type/questiontypebase.php
report/log/locallib.php
repository/lib.php
repository/tests/repository_test.php
user/editlib.php
user/externallib.php
user/index.php
user/messageselect.php
user/selector/lib.php
user/tests/externallib_test.php
version.php
webservice/amf/server.php
webservice/amf/simpleserver.php
webservice/soap/server.php
webservice/soap/simpleserver.php
webservice/xmlrpc/server.php
webservice/xmlrpc/simpleserver.php

index d02d1e3..f0bee31 100644 (file)
@@ -36,6 +36,12 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
     exit(1);
 }
 
+// Force OPcache reset if used, we do not want any stale caches
+// when preparing test environment.
+if (function_exists('opcache_reset')) {
+    opcache_reset();
+}
+
 $help =
 "Command line Moodle installer, creates config.php and initializes database.
 Please note you must execute this script with the same uid as apache
index dfc7a42..7a4f288 100644 (file)
@@ -36,6 +36,12 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
     exit(1);
 }
 
+// Force OPcache reset if used, we do not want any stale caches
+// when preparing test environment.
+if (function_exists('opcache_reset')) {
+    opcache_reset();
+}
+
 $help =
 "Advanced command line Moodle database installer.
 Please note you must execute this script with the same uid as apache.
index ca6ef6a..98e8726 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+// Force OPcache reset if used, we do not want any stale caches
+// when detecting if upgrade necessary or when running upgrade.
+if (function_exists('opcache_reset') and !isset($_SERVER['REMOTE_ADDR'])) {
+    opcache_reset();
+}
+
 define('CLI_SCRIPT', true);
 define('CACHE_DISABLE_ALL', true);
 
index c54e838..9acf551 100644 (file)
@@ -52,6 +52,12 @@ if (empty($_GET['cache']) and empty($_POST['cache'])) {
     // we redirect to self once we known no upgrades are necessary.
     // Note: $_GET and $_POST are used here intentionally because our param cleaning is not loaded yet.
     define('CACHE_DISABLE_ALL', true);
+
+    // Force OPcache reset if used, we do not want any stale caches
+    // when detecting if upgrade necessary or when running upgrade.
+    if (function_exists('opcache_reset')) {
+        opcache_reset();
+    }
 }
 
 require('../config.php');
index 280c0ae..8ceba12 100644 (file)
@@ -85,10 +85,18 @@ if ($uninstall) {
         if ($pluginman->is_plugin_folder_removable($pluginfo->component)) {
             $continueurl = new moodle_url($PAGE->url, array('delete' => $pluginfo->component, 'sesskey' => sesskey(), 'confirm' => 1));
             echo $output->plugin_uninstall_results_removable_page($pluginman, $pluginfo, $progress, $continueurl);
+            // Reset op code caches.
+            if (function_exists('opcache_reset')) {
+                opcache_reset();
+            }
             exit();
 
         } else {
             echo $output->plugin_uninstall_results_page($pluginman, $pluginfo, $progress);
+            // Reset op code caches.
+            if (function_exists('opcache_reset')) {
+                opcache_reset();
+            }
             exit();
         }
     }
@@ -131,6 +139,10 @@ if ($delete and $confirmed) {
 
     // So long, and thanks for all the bugs.
     fulldelete($pluginfo->rootdir);
+    // Reset op code caches.
+    if (function_exists('opcache_reset')) {
+        opcache_reset();
+    }
     redirect($PAGE->url);
 }
 
index e720160..3d63ce6 100644 (file)
@@ -46,11 +46,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
                        1800 => new lang_string('numminutes', '', 30),
                        2700 => new lang_string('numminutes', '', 45),
                        3600 => new lang_string('numminutes', '', 60))));
-    $temp->add(new admin_setting_configselect('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'), new lang_string('configfullnamedisplay', 'admin'),
-                  'language', array('language' => new lang_string('language'),
-                                              'firstname lastname' => new lang_string('firstname').' + '.new lang_string('lastname'),
-                                              'lastname firstname' => new lang_string('lastname').' + '.new lang_string('firstname'),
-                                              'firstname' => new lang_string('firstname'))));
+
     $temp->add(new admin_setting_configcheckbox('extendedusernamechars', new lang_string('extendedusernamechars', 'admin'), new lang_string('configextendedusernamechars', 'admin'), 0));
     $temp->add(new admin_setting_configtext('sitepolicy', new lang_string('sitepolicy', 'admin'), new lang_string('sitepolicy_help', 'admin'), '', PARAM_RAW));
     $temp->add(new admin_setting_configtext('sitepolicyguest', new lang_string('sitepolicyguest', 'admin'), new lang_string('sitepolicyguest_help', 'admin'), (isset($CFG->sitepolicy) ? $CFG->sitepolicy : ''), PARAM_RAW));
index 0365ab5..5a50bce 100644 (file)
@@ -150,6 +150,7 @@ if ($hassiteconfig
                     'department'  => new lang_string('department'),
                     'institution' => new lang_string('institution'),
                 )));
+        $temp->add(new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'), new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50));
         $temp->add(new admin_setting_configtext('maxusersperpage', new lang_string('maxusersperpage','admin'), new lang_string('configmaxusersperpage','admin'), 100, PARAM_INT));
         $temp->add(new admin_setting_configcheckbox('enablegravatar', new lang_string('enablegravatar', 'admin'), new lang_string('enablegravatar_help', 'admin'), 0));
         $temp->add(new admin_setting_configtext('gravatardefaulturl', new lang_string('gravatardefaulturl', 'admin'), new lang_string('gravatardefaulturl_help', 'admin'), 'mm'));
index fd11b08..9ac6931 100644 (file)
@@ -26,6 +26,12 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
     die(); // No access from web!
 }
 
+// Force OPcache reset if used, we do not want any stale caches
+// when preparing test environment.
+if (function_exists('opcache_reset')) {
+    opcache_reset();
+}
+
 // Is not really necessary but adding it as is a CLI_SCRIPT.
 define('CLI_SCRIPT', true);
 
diff --git a/admin/tool/capability/classes/settings_form.php b/admin/tool/capability/classes/settings_form.php
new file mode 100644 (file)
index 0000000..cf5fa3e
--- /dev/null
@@ -0,0 +1,66 @@
+<?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/>.
+
+/**
+ * Capability tool settings form.
+ *
+ * Do no include this file, it is automatically loaded by the class loader!
+ *
+ * @package    tool_capability
+ * @copyright  2013 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir.'/formslib.php');
+
+/**
+ * Class tool_capability_settings_form
+ *
+ * The settings form for the comparison of roles/capabilities.
+ *
+ * @copyright  2013 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_capability_settings_form extends moodleform {
+
+    /**
+     * The form definition.
+     */
+    public function definition() {
+        $form = $this->_form;
+        $capabilities = $this->_customdata['capabilities'];
+        $roles = $this->_customdata['roles'];
+        // Set the form ID.
+        $form->setAttributes(array('id' => 'capability-overview-form') + $form->getAttributes());
+
+        $form->addElement('header', 'reportsettings', get_string('reportsettings', 'tool_capability'));
+        $form->addElement('html', html_writer::tag('p', get_string('intro', 'tool_capability'), array('id' => 'intro')));
+
+        $form->addElement('hidden', 'search');
+        $form->setType('search', PARAM_TEXT);
+
+        $attributes = array('multiple' => 'multiple', 'size' => 10, 'data-search' => 'capability');
+        $form->addElement('select', 'capability', get_string('capabilitylabel', 'tool_capability'), $capabilities, $attributes);
+        $form->setType('capability', PARAM_CAPABILITY);
+
+        $attributes = array('multiple' => 'multiple', 'size' => 10);
+        $form->addElement('select', 'roles', get_string('roleslabel', 'tool_capability'), $roles, $attributes);
+        $form->setType('roles', PARAM_TEXT);
+
+        $form->addElement('submit', 'submitbutton', get_string('getreport', 'tool_capability'));
+    }
+
+}
\ No newline at end of file
index e0a0e66..d1707d2 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * For a given capability, show what permission it has for every role, and
- * everywhere that it is overridden.
+ * For a given capability, show what permission it has for every role, and everywhere that it is overridden.
  *
- * @package    tool
- * @subpackage capability
+ * @package    tool_capability
  * @copyright  2008 Tim Hunt
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 require_once(dirname(__FILE__) . '/../../../config.php');
+require_once($CFG->dirroot.'/'.$CFG->admin.'/tool/capability/locallib.php');
 require_once($CFG->libdir.'/adminlib.php');
 
-// Check permissions.
-require_login();
-$systemcontext = context_system::instance();
-require_capability('moodle/role:manage', $systemcontext);
-
 // Get URL parameters.
-$capability = optional_param('capability', '', PARAM_CAPABILITY);
-$roleids = optional_param_array('roles', array('0'), PARAM_INT);
-
-// Clean the passed in list of role ids. If 'All' selected as an option, or
-// if none were selected, do all roles.
-$allroles = role_fix_names(get_all_roles());
-$cleanedroleids = array();
-foreach ($roleids as $roleid) {
-    if ($roleid == 0) {
-        $cleanedroleids = array_keys($allroles);
-        break;
-    }
-    if (array_key_exists($roleid, $allroles)) {
-        $cleanedroleids[] = $roleid;
-    }
-}
-if (empty($cleanedroleids)) {
-    $cleanedroleids = array_keys($allroles);
-}
-
-// Include the required JavaScript.
-$PAGE->requires->js_init_call('M.tool_capability.init', array(get_string('search')));
+$systemcontext = context_system::instance();
+$contextid = optional_param('context', $systemcontext->id, PARAM_INT);
 
-// Log.
-add_to_log(SITEID, "admin", "tool capability", "tool/capability/index.php?capability=$capability", $capability);
+// Check permissions.
+list($context, $course, $cm) = get_context_info_array($contextid);
+require_login($course, false, $cm);
+require_capability('moodle/role:manage', $context);
 
 // Print the header.
 admin_externalpage_setup('toolcapability');
-echo $OUTPUT->header();
 
-// Prepare the list of capabilities to choose from
-$allcapabilities = fetch_context_capabilities($systemcontext);
+// Prepare the list of capabilities to choose from.
 $capabilitychoices = array();
-foreach ($allcapabilities as $cap) {
+foreach ($context->get_capabilities() as $cap) {
     $capabilitychoices[$cap->name] = $cap->name . ': ' . get_capability_string($cap->name);
 }
 
-// Prepare the list of roles to choose from
+$allroles = role_fix_names(get_all_roles($context));
+// Prepare the list of roles to choose from.
 $rolechoices = array('0' => get_string('all'));
 foreach ($allroles as $role) {
     $rolechoices[$role->id] = $role->localname;
 }
-if (count($cleanedroleids) == count($allroles)) {
-    // Select 'All', rather than each role individually.
-    $selectedroleids = array('0');
-} else {
-    $selectedroleids = $cleanedroleids;
-}
 
-// Print the settings form.
-echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
-echo '<form method="get" action="" id="settingsform"><div>';
-echo $OUTPUT->heading(get_string('reportsettings', 'tool_capability'));
-echo '<p id="intro">', get_string('intro', 'tool_capability') , '</p>';
-echo '<p><label for="menucapability"> ' . get_string('capabilitylabel', 'tool_capability') . '</label></p>';
-echo  html_writer::select($capabilitychoices, 'capability', $capability, array(''=>'choose'), array('size'=>10));
-echo '<p><label for="menuroles"> ' . get_string('roleslabel', 'tool_capability') . '</label></p>';
-echo  html_writer::select($rolechoices, 'roles[]', $selectedroleids, false, array('size'=>10, 'multiple'=>'multiple'));
-echo '<p><input type="submit" id="settingssubmit" value="' . get_string('getreport', 'tool_capability') . '" /></p>';
-echo '</div></form>';
-echo $OUTPUT->box_end();
+$form = new tool_capability_settings_form(null, array(
+    'capabilities' => $capabilitychoices,
+    'roles' => $rolechoices
+));
+$PAGE->requires->yui_module(
+    'moodle-tool_capability-search',
+    'M.tool_capability.init_capability_search',
+    array(array('strsearch' => get_string('search')))
+);
 
-// If we have a capability, generate the report.
-if ($capability) {
-
-    // Work out the bits needed for the SQL WHERE clauses.
-    $params = array($capability);
-    $sqlroletest = '';
-    if (count($cleanedroleids) != count($allroles)) {
-        list($sqlroletest, $roleparams) = $DB->get_in_or_equal($cleanedroleids);
-        $params = array_merge($params, $roleparams);
-        $sqlroletest = 'AND roleid ' . $sqlroletest;
-    }
+// Log.
+$capabilities = array();
+$rolestoshow = array();
+$roleids = array('0');
+$cleanedroleids = array();
+if ($data = $form->get_data()) {
 
-    // Get all the role_capabilities rows for this capability - that is, all
-    // role definitions, and all role overrides.
-    $rolecaps = $DB->get_records_sql("
-            SELECT id, roleid, contextid, permission
-            FROM {role_capabilities}
-            WHERE capability = ? $sqlroletest", $params);
-
-    // In order to display a nice tree of contexts, we need to get all the
-    // ancestors of all the contexts in the query we just did.
-    $relevantpaths = $DB->get_records_sql_menu("
-            SELECT DISTINCT con.path, 1
-            FROM {context} con JOIN {role_capabilities} rc ON rc.contextid = con.id
-            WHERE capability = ? $sqlroletest", $params);
-    $requiredcontexts = array($systemcontext->id);
-    foreach ($relevantpaths as $path => $notused) {
-        $requiredcontexts = array_merge($requiredcontexts, explode('/', trim($path, '/')));
+    $roleids = array();
+    if (!empty($data->roles)) {
+        $roleids = $data->roles;
     }
-    $requiredcontexts = array_unique($requiredcontexts);
-
-    // Now load those contexts.
-    list($sqlcontexttest, $contextparams) = $DB->get_in_or_equal($requiredcontexts);
-    $contexts = get_sorted_contexts('ctx.id ' . $sqlcontexttest, $contextparams);
 
-    // Prepare some empty arrays to hold the data we are about to compute.
-    foreach ($contexts as $conid => $con) {
-        $contexts[$conid]->children = array();
-        $contexts[$conid]->rolecapabilities = array();
+    $capabilities = array();
+    if (!empty($data->capability)) {
+        $capabilities = $data->capability;
     }
 
-    // Put the contexts into a tree structure.
-    foreach ($contexts as $conid => $con) {
-        $context = context::instance_by_id($conid);
-        $parentcontextid = get_parent_contextid($context);
-        if ($parentcontextid) {
-            $contexts[$parentcontextid]->children[] = $conid;
+    if (in_array('0', $roleids)) {
+        $rolestoshow = $allroles;
+    } else {
+        $cleanedroleids = array_intersect(array_keys($allroles), $roleids);
+        if (count($cleanedroleids) === 0) {
+            $rolestoshow = $allroles;
+        } else {
+            foreach ($cleanedroleids as $id) {
+                $rolestoshow[$id] = $allroles[$id];
+            }
         }
     }
+}
 
-    // Put the role capabilities into the context tree.
-    foreach ($rolecaps as $rolecap) {
-        $contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
-    }
+add_to_log(SITEID, "admin", "tool capability", "tool/capability/index.php", count($capabilities));
 
-    // Fill in any missing rolecaps for the system context.
-    foreach ($cleanedroleids as $roleid) {
-        if (!isset($contexts[$systemcontext->id]->rolecapabilities[$roleid])) {
-            $contexts[$systemcontext->id]->rolecapabilities[$roleid] = CAP_INHERIT;
-        }
-    }
+$renderer = $PAGE->get_renderer('tool_capability');
 
-    // Print the report heading.
-    echo $OUTPUT->heading(get_string('reportforcapability', 'tool_capability', get_capability_string($capability)), 2, 'main', 'report');
-    if (count($cleanedroleids) != count($allroles)) {
-        $rolenames = array();
-        foreach ($cleanedroleids as $roleid) {
-            $rolenames[] = $allroles[$roleid]->localname;
-        }
-        echo '<p>', get_string('forroles', 'tool_capability', implode(', ', $rolenames)), '</p>';
-    }
+echo $OUTPUT->header();
+
+$form->display();
 
-    // Now, recursively print the contexts, and the role information.
-    print_report_tree($systemcontext->id, $contexts, $allroles);
+// If we have a capability, generate the report.
+if (count($capabilities) && count($rolestoshow)) {
+    /* @var tool_capability_renderer $renderer */
+    echo $renderer->capability_comparison_table($capabilities, $context->id, $rolestoshow);
 }
 
 // Footer.
index bae923f..3862006 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Strings for component 'tool_capability', language 'en', branch 'MOODLE_22_STABLE'
  *
- * @package    tool
- * @subpackage capability
+ * @package    tool_capability
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/admin/tool/capability/locallib.php b/admin/tool/capability/locallib.php
new file mode 100644 (file)
index 0000000..aff0791
--- /dev/null
@@ -0,0 +1,96 @@
+<?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/>.
+
+/**
+ * Functions used by the capability tool.
+ *
+ * @package    tool_capability
+ * @copyright  2013 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Calculates capability data organised by context for the given roles.
+ *
+ * @param string $capability The capability to get data for.
+ * @param array $roles An array of roles to get data for.
+ * @return context[] An array of contexts.
+ */
+function tool_capability_calculate_role_data($capability, array $roles) {
+    global $DB;
+
+    $systemcontext = context_system::instance();
+    $roleids = array_keys($roles);
+
+    // Work out the bits needed for the SQL WHERE clauses.
+    $params = array($capability);
+    list($sqlroletest, $roleparams) = $DB->get_in_or_equal($roleids);
+    $params = array_merge($params, $roleparams);
+    $sqlroletest = 'AND roleid ' . $sqlroletest;
+
+    // Get all the role_capabilities rows for this capability - that is, all
+    // role definitions, and all role overrides.
+    $sql = 'SELECT id, roleid, contextid, permission
+              FROM {role_capabilities}
+             WHERE capability = ? '.$sqlroletest;
+    $rolecaps = $DB->get_records_sql($sql, $params);
+
+    // In order to display a nice tree of contexts, we need to get all the
+    // ancestors of all the contexts in the query we just did.
+    $sql = 'SELECT DISTINCT con.path, 1
+              FROM {context} con
+              JOIN {role_capabilities} rc ON rc.contextid = con.id
+             WHERE capability = ? '.$sqlroletest;
+    $relevantpaths = $DB->get_records_sql_menu($sql, $params);
+    $requiredcontexts = array($systemcontext->id);
+    foreach ($relevantpaths as $path => $notused) {
+        $requiredcontexts = array_merge($requiredcontexts, explode('/', trim($path, '/')));
+    }
+    $requiredcontexts = array_unique($requiredcontexts);
+
+    // Now load those contexts.
+    list($sqlcontexttest, $contextparams) = $DB->get_in_or_equal($requiredcontexts);
+    $contexts = get_sorted_contexts('ctx.id ' . $sqlcontexttest, $contextparams);
+
+    // Prepare some empty arrays to hold the data we are about to compute.
+    foreach ($contexts as $conid => $con) {
+        $contexts[$conid]->children = array();
+        $contexts[$conid]->rolecapabilities = array();
+    }
+
+    // Put the contexts into a tree structure.
+    foreach ($contexts as $conid => $con) {
+        $context = context::instance_by_id($conid);
+        $parentcontextid = get_parent_contextid($context);
+        if ($parentcontextid) {
+            $contexts[$parentcontextid]->children[] = $conid;
+        }
+    }
+
+    // Put the role capabilities into the context tree.
+    foreach ($rolecaps as $rolecap) {
+        $contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
+    }
+
+    // Fill in any missing rolecaps for the system context.
+    foreach ($roleids as $roleid) {
+        if (!isset($contexts[$systemcontext->id]->rolecapabilities[$roleid])) {
+            $contexts[$systemcontext->id]->rolecapabilities[$roleid] = CAP_INHERIT;
+        }
+    }
+
+    return $contexts;
+}
\ No newline at end of file
diff --git a/admin/tool/capability/module.js b/admin/tool/capability/module.js
deleted file mode 100644 (file)
index 254f194..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-
-M.tool_capability = {
-    select: null,
-    input: null,
-    button: null,
-
-    init: function(Y, strsearch) {
-        var context = M.tool_capability;
-
-        // Find the form controls.
-        context.select = document.getElementById('menucapability');
-        context.button = document.getElementById('settingssubmit');
-
-        // Create a div to hold the search UI.
-        var div = document.createElement('div');
-        div.id = 'capabilitysearchui';
-
-        // Find the capability search input.
-        var input = document.createElement('input');
-        input.type = 'text';
-        input.id = 'capabilitysearch';
-        context.input = input;
-
-        // Create a label for the search input.
-        var label = document.createElement('label');
-        label.htmlFor = input.id;
-        label.appendChild(document.createTextNode(strsearch + ' '));
-
-        // Tie it all together
-        div.appendChild(label);
-        div.appendChild(input);
-        context.select.parentNode.insertBefore(div, context.select);
-        Y.on('keyup', context.typed, input);
-        Y.on('change', context.validate, context.select);
-        context.select.options[0].style.display = 'none';
-        context.validate();
-    },
-
-    typed: function() {
-        var context = M.tool_capability;
-
-        var filtertext = context.input.value;
-        var options = context.select.options;
-        var onlycapability = -1;
-        for (var i = 1; i < options.length; i++) {
-            if (options[i].text.indexOf(filtertext) >= 0) {
-                options[i].disabled = false;
-                options[i].style.display = 'block';
-                if (onlycapability == -1) {
-                    onlycapability = i;
-                } else {
-                    onlycapability = -2;
-                }
-            } else {
-                options[i].disabled = true;
-                options[i].selected = false;
-                options[i].style.display = 'none';
-            }
-        }
-        if (onlycapability >= 0) {
-            options[onlycapability].selected = true;
-        }
-        if (onlycapability == -1) {
-            context.input.className = "error";
-        } else {
-            context.input.className = "";
-        }
-        context.validate();
-    },
-
-    validate: function() {
-        var context = M.tool_capability;
-        context.button.disabled = (context.select.value == '');
-    }
-}
\ No newline at end of file
diff --git a/admin/tool/capability/renderer.php b/admin/tool/capability/renderer.php
new file mode 100644 (file)
index 0000000..586725a
--- /dev/null
@@ -0,0 +1,136 @@
+<?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/>.
+
+/**
+ * Capability tool renderer.
+ *
+ * @package    tool_capability
+ * @copyright  2013 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * The primary renderer for the capability tool.
+ *
+ * @copyright  2013 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_capability_renderer extends plugin_renderer_base {
+
+    /**
+     * Returns an array of permission strings.
+     *
+     * @return lang_string[]
+     */
+    protected function get_permission_strings() {
+        static $strpermissions;
+        if (!$strpermissions) {
+            $strpermissions = array(
+                CAP_INHERIT => new lang_string('inherit', 'role'),
+                CAP_ALLOW => new lang_string('allow', 'role'),
+                CAP_PREVENT => new lang_string('prevent', 'role'),
+                CAP_PROHIBIT => new lang_string('prohibit', 'role')
+            );
+        }
+        return $strpermissions;
+    }
+
+    /**
+     * Returns an array of permission CSS classes.
+     *
+     * @return string[]
+     */
+    protected function get_permission_classes() {
+        static $permissionclasses;
+        if (!$permissionclasses) {
+            $permissionclasses = array(
+                CAP_INHERIT => 'inherit',
+                CAP_ALLOW => 'allow',
+                CAP_PREVENT => 'prevent',
+                CAP_PROHIBIT => 'prohibit',
+            );
+        }
+        return $permissionclasses;
+    }
+
+    /**
+     * Produces a table to visually compare roles and capabilities.
+     *
+     * @param array $capabilities An array of capabilities to show comparison for.
+     * @param int $contextid The context we are displaying for.
+     * @param array $roles An array of roles to show comparison for.
+     * @return string
+     */
+    public function capability_comparison_table(array $capabilities, $contextid, array $roles) {
+
+        $strpermissions = $this->get_permission_strings();
+        $permissionclasses = $this->get_permission_classes();
+
+        if ($contextid === context_system::instance()->id) {
+            $strpermissions[CAP_INHERIT] = new lang_string('notset', 'role');
+        }
+
+        $table = new html_table();
+        $table->attributes['class'] = 'comparisontable';
+        $table->head = array('&nbsp;');
+        foreach ($roles as $role) {
+            $url = new moodle_url('/admin/roles/override.php', array('contextid' => $contextid, 'roleid' => $role->id));
+            $table->head[] = html_writer::div(html_writer::link($url, $role->localname));
+        }
+        $table->data = array();
+
+        foreach ($capabilities as $capability) {
+            $contexts = tool_capability_calculate_role_data($capability, $roles);
+            $captitle = new html_table_cell(get_capability_string($capability) . html_writer::span($capability));
+            $captitle->header = true;
+
+            $row = new html_table_row(array($captitle));
+
+            foreach ($roles as $role) {
+                if (isset($contexts[$contextid]->rolecapabilities[$role->id])) {
+                    $permission = $contexts[$contextid]->rolecapabilities[$role->id];
+                } else {
+                    $permission = CAP_INHERIT;
+                }
+                $cell = new html_table_cell($strpermissions[$permission]);
+                $cell->attributes['class'] = $permissionclasses[$permission];
+                $row->cells[] = $cell;
+            }
+
+            $table->data[] = $row;
+        }
+
+        // Start the list item, and print the context name as a link to the place to make changes.
+        if ($contextid == context_system::instance()->id) {
+            $url = new moodle_url('/admin/roles/manage.php');
+            $title = get_string('changeroles', 'tool_capability');
+        } else {
+            $url = new moodle_url('/admin/roles/override.php', array('contextid' => $contextid));
+            $title = get_string('changeoverrides', 'tool_capability');
+        }
+        $context = context::instance_by_id($contextid);
+        $html = $this->output->heading(html_writer::link($url, $context->get_context_name(), array('title' => $title)), 3);
+        $html .= html_writer::table($table);
+        // If there are any child contexts, print them recursively.
+        if (!empty($contexts[$contextid]->children)) {
+            foreach ($contexts[$contextid]->children as $childcontextid) {
+                $html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles, true);
+            }
+        }
+        return $html;
+    }
+
+}
\ No newline at end of file
index bf4d6ad..ba8d551 100644 (file)
 /**
  * Capability overview settings
  *
- * @package    tool
- * @subpackage capability
+ * @package    tool_capability
  * @copyright  2008 Tim Hunt
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die;
 
-$ADMIN->add('roles', new admin_externalpage('toolcapability', get_string('pluginname', 'tool_capability'), "$CFG->wwwroot/$CFG->admin/tool/capability/index.php",'moodle/role:manage'));
+$ADMIN->add('roles', new admin_externalpage(
+    'toolcapability',
+    get_string('pluginname', 'tool_capability'),
+    "$CFG->wwwroot/$CFG->admin/tool/capability/index.php",
+    'moodle/role:manage'
+));
diff --git a/admin/tool/capability/styles.css b/admin/tool/capability/styles.css
new file mode 100644 (file)
index 0000000..757066e
--- /dev/null
@@ -0,0 +1,32 @@
+.path-admin-tool-capability .comparisontable {margin-top:150px;}
+.path-admin-tool-capability .comparisontable th,
+.path-admin-tool-capability .comparisontable td {vertical-align:middle;padding:0.4em 0.5em 0.3em;}
+.path-admin-tool-capability .comparisontable thead th {vertical-align:bottom;background:none;}
+.path-admin-tool-capability .comparisontable thead th div {position:relative;}
+.path-admin-tool-capability .comparisontable thead th div > a {
+    position:absolute;
+    top:-1.75em;
+    left:1em;
+    width:150px;
+    text-align:left;
+    margin-bottom:1em;
+    text-indent:-1.45em;
+
+    -webkit-transform-origin: top left;
+    -moz-transform-origin:    top left;
+    -ms-transform-origin:     top left;
+    -o-transform-origin:      top left;
+
+    -webkit-transform: rotate(315deg);
+    -moz-transform:    rotate(315deg);
+    -ms-transform:     rotate(315deg);
+    -o-transform:      rotate(315deg);
+}
+.path-admin-tool-capability .comparisontable tbody th {background-color:#EEE;text-align:right;border:1px solid #DFDFDF;}
+.path-admin-tool-capability .comparisontable tbody th span {display:block;color:#666;font-size:80%;}
+.path-admin-tool-capability .comparisontable tbody td {border:1px solid #DFDFDF;}
+
+.path-admin-tool-capability .comparisontable .inherit {color:#666;}
+.path-admin-tool-capability .comparisontable .allow {color:#006600;font-weight:bold;}
+.path-admin-tool-capability .comparisontable .prevent {color:#ad6704;font-weight:bold;}
+.path-admin-tool-capability .comparisontable .prohibit {color:#880000;font-weight:bold;}
\ No newline at end of file
index e14328a..4ada1ea 100644 (file)
 /**
  * Version details.
  *
- * @package    tool
- * @subpackage capability
+ * @package    tool_capability
  * @copyright  2011 Petr Skoda
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2013050100; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2013050100; // Requires this Moodle version
-$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2013050100; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2013050100; // Requires this Moodle version.
+$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
diff --git a/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-debug.js b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-debug.js
new file mode 100644 (file)
index 0000000..f0661d5
Binary files /dev/null and b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-debug.js differ
diff --git a/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-min.js b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-min.js
new file mode 100644 (file)
index 0000000..0153975
Binary files /dev/null and b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-min.js differ
diff --git a/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search.js b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search.js
new file mode 100644 (file)
index 0000000..f0661d5
Binary files /dev/null and b/admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search.js differ
diff --git a/admin/tool/capability/yui/src/search/build.json b/admin/tool/capability/yui/src/search/build.json
new file mode 100644 (file)
index 0000000..2157889
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "name": "moodle-tool_capability-search",
+    "builds": {
+        "moodle-tool_capability-search": {
+            "jsfiles": [
+                "search.js"
+            ]
+        }
+    }
+}
diff --git a/admin/tool/capability/yui/src/search/js/search.js b/admin/tool/capability/yui/src/search/js/search.js
new file mode 100644 (file)
index 0000000..5e9dc34
--- /dev/null
@@ -0,0 +1,159 @@
+/**
+ * This file contains the capability overview search functionality.
+ *
+ * @module moodle-tool_capability-search
+ */
+
+/**
+ * Constructs a new capability search manager.
+ *
+ * @namespace M.tool_capability.search
+ * @class Search
+ * @constructor
+ * @extends Y.Base
+ */
+var SEARCH = function() {
+    SEARCH.superclass.constructor.apply(this, arguments);
+};
+SEARCH.prototype = {
+    /**
+     * The search form.
+     * @property form
+     * @type Node
+     * @protected
+     */
+    form : null,
+    /**
+     * The capability select node.
+     * @property select
+     * @type Node
+     * @protected
+     */
+    select: null,
+    /**
+     * An associative array of search option. Populated from the select node above during initialisation.
+     * @property selectoptions
+     * @type Object
+     * @protected
+     */
+    selectoptions : {},
+    /**
+     * The search input field.
+     * @property input
+     * @type Node
+     * @protected
+     */
+    input: null,
+    /**
+     * The submit button for the form.
+     * @property button
+     * @type Node
+     * @protected
+     */
+    button: null,
+    /**
+     * The last search node if there is one.
+     * If there is a last search node then the last search term will be persisted between requests.
+     * @property lastsearch
+     * @type Node
+     * @protected
+     */
+    lastsearch : null,
+    /**
+     * Constructs the search manager.
+     * @method initializer
+     */
+    initializer : function() {
+        this.form = Y.one('#capability-overview-form');
+        this.select = this.form.one('select[data-search=capability]');
+        this.select.setStyle('minWidth', this.select.get('offsetWidth'));
+        this.select.get('options').each(function(option) {
+            var capability = option.get('value');
+            this.selectoptions[capability] = option;
+        }, this);
+        this.button = this.form.all('input[type=submit]');
+        this.lastsearch = this.form.one('input[name=search]');
+
+        var div = Y.Node.create('<div id="capabilitysearchui"></div>'),
+            label = Y.Node.create('<label for="capabilitysearch">'+this.get('strsearch')+'</label>');
+        this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
+
+        div.append(label).append(this.input);
+
+        this.select.insert(div, 'before');
+        this.select.one('option').setStyle('display', 'none');
+
+        this.input.on('keyup', this.typed, this);
+        this.select.on('change', this.validate, this);
+
+        if (this.lastsearch) {
+            this.input.set('value', this.lastsearch.get('value'));
+            this.typed();
+            if (this.select.one('option[selected]')) {
+                this.select.set('scrollTop', this.select.one('option[selected]').get('getX'));
+            }
+        }
+
+        this.validate();
+    },
+    /**
+     * Disables the submit button if there are no capabilities selected.
+     * @method validate
+     */
+    validate : function() {
+        this.button.set('disabled', (this.select.get('value') === ''));
+    },
+    /**
+     * Called when ever the user types into the search field.
+     * This method hides any capabilities that don't match the search term.
+     * @method typed
+     */
+    typed : function() {
+        var search = this.input.get('value'),
+            matching = 0,
+            last = null,
+            capability;
+        if (this.lastsearch) {
+            this.lastsearch.set('value', search);
+        }
+        this.select.all('option').remove();
+        for (capability in this.selectoptions) {
+            if (capability.indexOf(search) >= 0) {
+                matching++;
+                this.select.append(this.selectoptions[capability]);
+            }
+        }
+        if (matching === 0) {
+            this.input.addClass("error");
+        } else {
+            this.input.removeClass("error");
+            if (matching === 1) {
+                last.set('selected', true);
+            }
+        }
+        this.validate();
+    }
+};
+Y.extend(SEARCH, Y.Base, SEARCH.prototype, {
+    NAME : 'tool_capability-search',
+    ATTRS : {
+        strsearch : {}
+    }
+});
+
+/**
+ * Core namespace.
+ * @static
+ * @class tool_capability
+ */
+M.tool_capability = M.tool_capability || {};
+
+/**
+ * Initialises capability search functionality.
+ * @static
+ * @method init_capability_search
+ * @param {Object} options
+ */
+M.tool_capability.init_capability_search = function(options) {
+    new SEARCH(options);
+};
\ No newline at end of file
diff --git a/admin/tool/capability/yui/src/search/meta/search.json b/admin/tool/capability/yui/src/search/meta/search.json
new file mode 100644 (file)
index 0000000..720e20b
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "moodle-tool_capability-search": {
+        "requires": [
+            "base",
+            "node"
+        ]
+    }
+}
index bf026a4..a3d875d 100644 (file)
@@ -26,6 +26,12 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
     die; // no access from web!
 }
 
+// Force OPcache reset if used, we do not want any stale caches
+// when preparing test environment.
+if (function_exists('opcache_reset')) {
+    opcache_reset();
+}
+
 require_once(__DIR__.'/../../../../lib/clilib.php');
 require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
 require_once(__DIR__.'/../../../../lib/testing/lib.php');
index be72d51..deb6143 100644 (file)
@@ -68,8 +68,10 @@ if (count($cohorts) < 2) {
 }
 
 $countries = get_string_manager()->get_list_of_countries(true);
+$namefields = get_all_user_name_fields(true);
 foreach ($users as $key => $id) {
-    $user = $DB->get_record('user', array('id'=>$id, 'deleted'=>0), 'id, firstname, lastname, username, email, country, lastaccess, city');
+    $user = $DB->get_record('user', array('id'=>$id, 'deleted'=>0), 'id, ' . $namefields . ', username,
+            email, country, lastaccess, city');
     $user->fullname = fullname($user, true);
     $user->country = @$countries[$user->country];
     unset($user->firstname);
index 1e8514a..44259df 100644 (file)
@@ -24,8 +24,9 @@ echo $OUTPUT->header();
 
 $countries = get_string_manager()->get_list_of_countries(true);
 
+$namefields = get_all_user_name_fields(true);
 foreach ($users as $key => $id) {
-    $user = $DB->get_record('user', array('id'=>$id), 'id, firstname, lastname, username, email, country, lastaccess, city');
+    $user = $DB->get_record('user', array('id'=>$id), 'id, ' . $namefields . ', username, email, country, lastaccess, city');
     $user->fullname = fullname($user, true);
     $user->country = @$countries[$user->country];
     unset($user->firstname);
index 314e5be..4eed099 100644 (file)
@@ -914,7 +914,7 @@ class auth_plugin_ldap extends auth_plugin_base {
 
                 $id = $DB->insert_record('user', $user);
                 echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)); echo "\n";
-                $euser = $DB->get_record('user', array('id' => $user->id));
+                $euser = $DB->get_record('user', array('id' => $id));
                 events_trigger('user_created', $euser);
                 if (!empty($this->config->forcechangepassword)) {
                     set_user_preference('auth_forcepasswordchange', 1, $id);
index a926756..952cc26 100644 (file)
@@ -1194,12 +1194,12 @@ class backup_users_structure_step extends backup_structure_step {
 
         // Then, the fields potentially needing anonymization
         $anonfields = array(
-            'username', 'idnumber', 'firstname', 'lastname',
-            'email', 'icq', 'skype',
+            'username', 'idnumber', 'email', 'icq', 'skype',
             'yahoo', 'aim', 'msn', 'phone1',
             'phone2', 'institution', 'department', 'address',
             'city', 'country', 'lastip', 'picture',
             'url', 'description', 'descriptionformat', 'imagealt', 'auth');
+        $anonfields = array_merge($anonfields, get_all_user_name_fields());
 
         // Add anonymized fields to $userfields with custom final element
         foreach ($anonfields as $field) {
index 8e4cc31..2e6c018 100644 (file)
@@ -108,6 +108,8 @@ class cache_config_writer extends cache_config {
             fflush($handle);
             fclose($handle);
             $locking->unlock('configwrite', 'config');
+            // Tell PHP to recompile the script.
+            core_component::invalidate_opcode_php_cache($cachefile);
         } else {
             throw new cache_exception('ex_configcannotsave', 'cache', '', null, 'Unable to open the cache config file.');
         }
index 9a0df5f..ffd8f74 100644 (file)
@@ -78,7 +78,7 @@ switch ($action) {
 
     case 'ajax_getmembersingroup':
         $roles = array();
-        if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, u.firstname, u.lastname')) {
+        if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, ' . get_all_user_name_fields(true, 'u'))) {
             foreach($groupmemberroles as $roleid=>$roledata) {
                 $shortroledata = new stdClass();
                 $shortroledata->name = $roledata->name;
@@ -246,7 +246,7 @@ $member_names = array();
 
 $atleastonemember = false;
 if ($singlegroup) {
-    if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, u.firstname, u.lastname')) {
+    if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, ' . get_all_user_name_fields(true, 'u'))) {
         foreach($groupmemberroles as $roleid=>$roledata) {
             echo '<optgroup label="'.s($roledata->name).'">';
             foreach($roledata->users as $member) {
index 7e6fa2c..134261e 100644 (file)
@@ -90,7 +90,8 @@ if ($groupingid) {
 
 list($sort, $sortparams) = users_order_by_sql('u');
 
-$sql = "SELECT g.id AS groupid, gg.groupingid, u.id AS userid, u.firstname, u.lastname, u.idnumber, u.username
+$allnames = get_all_user_name_fields(true, 'u');
+$sql = "SELECT g.id AS groupid, gg.groupingid, u.id AS userid, $allnames, u.idnumber, u.username
           FROM {groups} g
                LEFT JOIN {groupings_groups} gg ON g.id = gg.groupid
                LEFT JOIN {groups_members} gm ON g.id = gm.groupid
@@ -106,6 +107,9 @@ foreach ($rs as $row) {
     $user->lastname  = $row->lastname;
     $user->username  = $row->username;
     $user->idnumber  = $row->idnumber;
+    foreach (get_all_user_name_fields() as $addname) {
+        $user->$addname = $row->$addname;
+    }
     if (!$row->groupingid) {
         $row->groupingid = -1;
     }
index b6e872a..d6a3c2a 100644 (file)
@@ -227,7 +227,7 @@ $string['configfrontpage'] = 'The items selected above will be displayed on the
 $string['configfrontpagecourselimit'] = 'Maximum number of courses';
 $string['configfrontpagecourselimithelp'] = 'Maximum number of courses to be displayed on the site\'s front page in course listings.';
 $string['configfrontpageloggedin'] = 'The items selected above will be displayed on the site\'s front page when a user is logged in.';
-$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is "First name + Surname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions).';
+$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is "firstname lastname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions). Placeholders that can be used are: firstname, lastname, firstnamephonetic, lastnamephonetic, middlename, and alternatename.';
 $string['configgeoipfile'] = 'Location of GeoIP City binary data file. This file is not part of Moodle distribution and must be obtained separately from <a href="http://www.maxmind.com/">MaxMind</a>. You can either buy a commercial version or use the free version.<br />Simply download <a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" >http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz</a> and extract it into "{$a}" directory on your server.';
 $string['configgetremoteaddrconf'] = 'If your server is behind a reverse proxy, you can use this setting to specify which HTTP headers can be trusted to contain the remote IP address. The headers are read in order, using the first one that is available.';
 $string['configgradebookroles'] = 'This setting allows you to control who appears on the gradebook.  Users need to have at least one of these roles in a course to be shown in the gradebook for that course.';
@@ -548,6 +548,7 @@ $string['frontpagerestore'] = 'Front page restore';
 $string['frontpageroles'] = 'Front page roles';
 $string['frontpagesettings'] = 'Front page settings';
 $string['fullnamedisplay'] = 'Full name format';
+$string['fullnamedisplayprivate'] = 'Full name format - private';
 $string['gdrecommended'] = 'GD extension is used for conversion of images, some features such as user profile images will not be available if missing.';
 $string['gdrequired'] = 'The GD extension is now required by Moodle for image conversion.';
 $string['generalsettings'] = 'General settings';
index 3ec27d6..e92ab1f 100644 (file)
@@ -60,6 +60,7 @@ $string['addfilehere'] = 'Add file(s) here';
 $string['addinganew'] = 'Adding a new {$a}';
 $string['addinganewto'] = 'Adding a new {$a->what} to {$a->to}';
 $string['addingdatatoexisting'] = 'Adding data to existing';
+$string['additionalnames'] = 'Additional names';
 $string['addlinkhere'] = 'Add link here';
 $string['addnewcategory'] = 'Add new category';
 $string['addnewcourse'] = 'Add a new course';
@@ -135,6 +136,7 @@ $string['allparticipants'] = 'All participants';
 $string['allteachers'] = 'All teachers';
 $string['alphanumerical'] = 'Can only contain alphanumeric characters, hyphen (-) or period (.)';
 $string['alreadyconfirmed'] = 'Registration has already been confirmed';
+$string['alternatename'] = 'Alternate name';
 $string['always'] = 'Always';
 $string['and'] = '{$a->one} and {$a->two}';
 $string['answer'] = 'Answer';
@@ -680,6 +682,7 @@ $string['filter'] = 'Filter';
 $string['findmorecourses'] = 'Find more courses...';
 $string['firstaccess'] = 'First access';
 $string['firstname'] = 'First name';
+$string['firstnamephonetic'] = 'First name - phonetic';
 $string['firsttime'] = 'Is this your first time here?';
 $string['folder'] = 'Folder';
 $string['folderclosed'] = 'Closed folder';
@@ -910,6 +913,7 @@ $string['lastedited'] = 'Last edited';
 $string['lastlogin'] = 'Last login';
 $string['lastmodified'] = 'Last modified';
 $string['lastname'] = 'Surname';
+$string['lastnamephonetic'] = 'Surname - phonetic';
 $string['lastyear'] = 'Last year';
 $string['latestlanguagepack'] = 'Check for latest language pack on moodle.org';
 $string['layouttable'] = 'Layout table';
@@ -1019,6 +1023,7 @@ $string['messageprovider:instantmessage'] = 'Personal messages between users';
 $string['messageprovider:instantmessage_help'] = 'This section configures what happens to messages that are sent to you directly from other users on this site.';
 $string['messageselect'] = 'Select this user as a message recipient';
 $string['messageselectadd'] = 'Send a message';
+$string['middlename'] = 'Middle name';
 $string['migratinggrades'] = 'Migrating grades';
 $string['min'] = 'min';
 $string['mins'] = 'mins';
index ad09d5b..362c338 100644 (file)
@@ -3964,7 +3964,8 @@ function get_role_users($roleid, context $context, $parent = false, $fields = ''
     global $DB;
 
     if (empty($fields)) {
-        $fields = 'u.id, u.confirmed, u.username, u.firstname, u.lastname, '.
+        $allnames = get_all_user_name_fields(true, 'u');
+        $fields = 'u.id, u.confirmed, u.username, '. $allnames . ', ' .
                   'u.maildisplay, u.mailformat, u.maildigest, u.email, u.emailstop, u.city, '.
                   'u.country, u.picture, u.idnumber, u.department, u.institution, '.
                   'u.lang, u.timezone, u.lastaccess, u.mnethostid, r.name AS rolename, r.sortorder, '.
@@ -5357,6 +5358,10 @@ abstract class context extends stdClass implements IteratorAggregate {
         $fs = get_file_storage();
         $fs->delete_area_files($this->_id);
 
+        // Delete all repository instances attached to this context.
+        require_once($CFG->dirroot . '/repository/lib.php');
+        repository::delete_all_for_context($this->_id);
+
         // delete all advanced grading data attached to this context
         require_once($CFG->dirroot.'/grade/grading/lib.php');
         grading_manager::delete_all_for_context($this->_id);
index daf2d44..cf51764 100644 (file)
@@ -620,8 +620,10 @@ function badges_notify_badge_award(badge $badge, $userid, $issued, $filepathhash
     $userfrom = new stdClass();
     $userfrom->id = $admin->id;
     $userfrom->email = !empty($CFG->badges_defaultissuercontact) ? $CFG->badges_defaultissuercontact : $admin->email;
+    foreach (get_all_user_name_fields() as $addname) {
+        $userfrom->$addname = !empty($CFG->badges_defaultissuername) ? '' : $admin->$addname;
+    }
     $userfrom->firstname = !empty($CFG->badges_defaultissuername) ? $CFG->badges_defaultissuername : $admin->firstname;
-    $userfrom->lastname = !empty($CFG->badges_defaultissuername) ? '' : $admin->lastname;
     $userfrom->maildisplay = true;
 
     $issuedlink = html_writer::link(new moodle_url('/badges/badge.php', array('hash' => $issued)), $badge->name);
index fefe8e6..0c7a8fa 100644 (file)
@@ -142,6 +142,7 @@ class core_component {
                 @chmod($cachefile, $CFG->filepermissions);
             }
             @unlink($cachefile.'.tmp'); // Just in case anything fails (race condition).
+            self::invalidate_opcode_php_cache($cachefile);
         }
     }
 
@@ -735,4 +736,21 @@ $cache = '.var_export($cache, true).';
         }
         return $return;
     }
+
+    /**
+     * Invalidate opcode cache for given file, this is intended for
+     * php files that are stored in dataroot.
+     *
+     * Note: we need it here because this class must be self-contained.
+     *
+     * @param string $file
+     */
+    public static function invalidate_opcode_php_cache($file) {
+        if (function_exists('opcache_invalidate')) {
+            if (!file_exists($file)) {
+                return;
+            }
+            opcache_invalidate($file, true);
+        }
+    }
 }
index ba549e1..0204812 100644 (file)
@@ -712,9 +712,10 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
         list($sql2, $params2) = $DB->get_in_or_equal($managerroles, SQL_PARAMS_NAMED, 'rid');
         list($sort, $sortparams) = users_order_by_sql('u');
         $notdeleted = array('notdeleted'=>0);
+        $allnames = get_all_user_name_fields(true, 'u');
         $sql = "SELECT ra.contextid, ra.id AS raid,
                        r.id AS roleid, r.name AS rolename, r.shortname AS roleshortname,
-                       rn.name AS rolecoursealias, u.id, u.username, u.firstname, u.lastname
+                       rn.name AS rolecoursealias, u.id, u.username, $allnames
                   FROM {role_assignments} ra
                   JOIN {user} u ON ra.userid = u.id
                   JOIN {role} r ON ra.roleid = r.id
@@ -2109,8 +2110,9 @@ class course_in_list implements IteratorAggregate {
                 $user = new stdClass();
                 $user->id = $ruser->id;
                 $user->username = $ruser->username;
-                $user->firstname = $ruser->firstname;
-                $user->lastname = $ruser->lastname;
+                foreach (get_all_user_name_fields() as $addname) {
+                    $user->$addname = $ruser->$addname;
+                }
                 $role = new stdClass();
                 $role->id = $ruser->roleid;
                 $role->name = $ruser->rolename;
index 49d8cb5..d8404c9 100644 (file)
@@ -507,10 +507,11 @@ function get_users_listing($sort='lastaccess', $dir='ASC', $page=0, $recordsperp
                 array('id', 'username', 'email', 'firstname', 'lastname', 'city', 'country',
                 'lastaccess', 'confirmed', 'mnethostid'));
     }
+    $namefields = get_all_user_name_fields(true);
+    $extrafields = "$extrafields, $namefields";
 
     // warning: will return UNCONFIRMED USERS
-    return $DB->get_records_sql("SELECT id, username, email, firstname, lastname, city, country,
-                                        lastaccess, confirmed, mnethostid, suspended $extrafields
+    return $DB->get_records_sql("SELECT id, username, email, city, country, lastaccess, confirmed, mnethostid, suspended $extrafields
                                    FROM {user}
                                   WHERE $select
                                   $sort", $params, $page, $recordsperpage);
@@ -1781,8 +1782,8 @@ function get_logs($select, array $params=null, $order='l.time DESC', $limitfrom=
            $select";
 
     $totalcount = $DB->count_records_sql($sql, $params);
-
-    $sql = "SELECT l.*, u.firstname, u.lastname, u.picture
+    $allnames = get_all_user_name_fields(true, 'u');
+    $sql = "SELECT l.*, $allnames, u.picture
               FROM {log} l
               LEFT JOIN {user} u ON l.userid = u.id
            $select
index 67660b3..dba2025 100644 (file)
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="trustbitmask" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="imagealt" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="alt tag for user uploaded image"/>
+        <FIELD NAME="lastnamephonetic" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Last name phonetic"/>
+        <FIELD NAME="firstnamephonetic" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="First name phonetic"/>
+        <FIELD NAME="middlename" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Middle name"/>
+        <FIELD NAME="alternatename" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Alternate name - Useful for three-name countries."/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
         <INDEX NAME="email" UNIQUE="false" FIELDS="email"/>
         <INDEX NAME="auth" UNIQUE="false" FIELDS="auth"/>
         <INDEX NAME="idnumber" UNIQUE="false" FIELDS="idnumber"/>
+        <INDEX NAME="firstnamephonetic" UNIQUE="false" FIELDS="firstnamephonetic"/>
+        <INDEX NAME="lastnamephonetic" UNIQUE="false" FIELDS="lastnamephonetic"/>
+        <INDEX NAME="middlename" UNIQUE="false" FIELDS="middlename"/>
+        <INDEX NAME="alternatename" UNIQUE="false" FIELDS="alternatename"/>
       </INDEXES>
     </TABLE>
     <TABLE NAME="user_preferences" COMMENT="Allows modules to store arbitrary user preferences">
index c6bafe0..b593aef 100644 (file)
@@ -2190,5 +2190,74 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2013061700.00);
     }
 
+    if ($oldversion < 2013070800.00) {
+
+        // Remove orphan repository instances.
+        if ($DB->get_dbfamily() === 'mysql') {
+            $sql = "DELETE {repository_instances} FROM {repository_instances}
+                    LEFT JOIN {context} ON {context}.id = {repository_instances}.contextid
+                    WHERE {context}.id IS NULL";
+        } else {
+            $sql = "DELETE FROM {repository_instances}
+                    WHERE NOT EXISTS (
+                        SELECT 'x' FROM {context}
+                        WHERE {context}.id = {repository_instances}.contextid)";
+        }
+        $DB->execute($sql);
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2013070800.00);
+    }
+
+    if ($oldversion < 2013070800.01) {
+
+        // Define field lastnamephonetic to be added to user.
+        $table = new xmldb_table('user');
+        $field = new xmldb_field('lastnamephonetic', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'imagealt');
+        $index = new xmldb_index('lastnamephonetic', XMLDB_INDEX_NOTUNIQUE, array('lastnamephonetic'));
+
+        // Conditionally launch add field lastnamephonetic.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+            $dbman->add_index($table, $index);
+        }
+
+        // Define field firstnamephonetic to be added to user.
+        $table = new xmldb_table('user');
+        $field = new xmldb_field('firstnamephonetic', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'lastnamephonetic');
+        $index = new xmldb_index('firstnamephonetic', XMLDB_INDEX_NOTUNIQUE, array('firstnamephonetic'));
+
+        // Conditionally launch add field firstnamephonetic.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+            $dbman->add_index($table, $index);
+        }
+
+        // Define field alternatename to be added to user.
+        $table = new xmldb_table('user');
+        $field = new xmldb_field('middlename', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'firstnamephonetic');
+        $index = new xmldb_index('middlename', XMLDB_INDEX_NOTUNIQUE, array('middlename'));
+
+        // Conditionally launch add field firstnamephonetic.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+            $dbman->add_index($table, $index);
+        }
+
+        // Define field alternatename to be added to user.
+        $table = new xmldb_table('user');
+        $field = new xmldb_field('alternatename', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'middlename');
+        $index = new xmldb_index('alternatename', XMLDB_INDEX_NOTUNIQUE, array('alternatename'));
+
+        // Conditionally launch add field alternatename.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+            $dbman->add_index($table, $index);
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2013070800.01);
+    }
+
     return true;
 }
index 63f2470..4ac7472 100644 (file)
@@ -140,7 +140,8 @@ class mssql_native_moodle_database extends moodle_database {
         $this->store_settings($dbhost, $dbuser, $dbpass, $dbname, $prefix, $dboptions);
 
         $dbhost = $this->dbhost;
-        if (isset($dboptions['dbport'])) {
+        // Zero shouldn't be used as a port number so doing a check with empty() should be fine.
+        if (!empty($dboptions['dbport'])) {
             if (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) {
                 $dbhost .= ','.$dboptions['dbport'];
             } else {
index f099328..fc93e14 100644 (file)
@@ -275,7 +275,7 @@ class course_modinfo extends stdClass {
 
         // Load sectioncache field into memory as PHP object and check it's valid
         $sectioncache = unserialize($course->sectioncache);
-        if (!is_array($sectioncache) || empty($sectioncache)) {
+        if (!is_array($sectioncache)) {
             // hmm, something is wrong - let's fix it
             rebuild_course_cache($course->id);
             $course->sectioncache = $DB->get_field('course', 'sectioncache', array('id'=>$course->id));
index 9acd467..0767ee6 100644 (file)
@@ -3558,7 +3558,7 @@ function ismoving($courseid) {
 /**
  * Returns a persons full name
  *
- * Given an object containing firstname and lastname
+ * Given an object containing all of the users name
  * values, this function returns a string with the
  * full name of the person.
  * The result may depend on system settings
@@ -3567,7 +3567,7 @@ function ismoving($courseid) {
  *
  * @global object
  * @global object
- * @param object $user A {@link $USER} object to get full name of
+ * @param object $user A {@link $USER} object to get full name of.
  * @param bool $override If true then the name will be first name followed by last name rather than adhering to fullnamedisplay setting.
  * @return string
  */
@@ -3591,21 +3591,114 @@ function fullname($user, $override=false) {
         $CFG->fullnamedisplay = $SESSION->fullnamedisplay;
     }
 
-    if (!isset($CFG->fullnamedisplay) or $CFG->fullnamedisplay === 'firstname lastname') {
-        return $user->firstname .' '. $user->lastname;
+    $template = null;
+    // If the fullnamedisplay setting is available, set the template to that.
+    if (isset($CFG->fullnamedisplay)) {
+        $template = $CFG->fullnamedisplay;
+    }
+    // If the template is empty, or set to language, or $override is set, return the language string.
+    if (empty($template) || $template == 'language' || $override) {
+        return get_string('fullnamedisplay', null, $user);
+    }
 
-    } else if ($CFG->fullnamedisplay == 'lastname firstname') {
-        return $user->lastname .' '. $user->firstname;
+    // Get all of the name fields.
+    $allnames = get_all_user_name_fields();
+    $requirednames = array();
+    // With each name, see if it is in the display name template, and add it to the required names array if it is.
+    foreach ($allnames as $allname) {
+        if (strpos($template, $allname) !== false) {
+            $requirednames[] = $allname;
+            // If the field is in the template, but not set in the user object, then notify the programmer that it needs to be fixed.
+            if (!array_key_exists($allname, $user)) {
+                debugging('You need to update your sql query to include additional name fields in the user object.', DEBUG_DEVELOPER);
+            }
+        }
+    }
 
-    } else if ($CFG->fullnamedisplay == 'firstname') {
-        if ($override) {
-            return get_string('fullnamedisplay', '', $user);
+    $displayname = $template;
+    // Switch in the actual data into the template.
+    foreach ($requirednames as $altname) {
+        if (isset($user->$altname)) {
+            // Using empty() on the below if statement causes breakages.
+            if ((string)$user->$altname == '') {
+                $displayname = str_replace($altname, 'EMPTY', $displayname);
+            } else {
+                $displayname = str_replace($altname, $user->$altname, $displayname);
+            }
         } else {
-            return $user->firstname;
+            $displayname = str_replace($altname, 'EMPTY', $displayname);
+        }
+    }
+    // Tidy up any misc. characters (Not perfect, but gets most characters).
+    // Don't remove the "u" at the end of the first expression unless you want garbled characters when combining hiragana or katakana and parenthesis.
+    $patterns = array();
+    // This regular expression replacement is to fix problems such as 'James () Kirk' Where 'Tiberius' (middlename) has not been filled in by a user.
+    // The special characters are Japanese brackets that are common enough to make special allowance for them (not covered by :punct:).
+    $patterns[] = '/[[:punct:]「」]*EMPTY[[:punct:]「」]*/u';
+    // This regular expression is to remove any double spaces in the display name.
+    $patterns[] = '/\s{2,}/';
+    foreach ($patterns as $pattern) {
+        $displayname = preg_replace($pattern, ' ', $displayname);
+    }
+
+    // Trimming $displayname will help the next check to ensure that we don't have a display name with spaces.
+    $displayname = trim($displayname);
+    if (empty($displayname)) {
+        // Going with just the first name if no alternate fields are filled out. May be changed later depending on what
+        // people in general feel is a good setting to fall back on.
+        $displayname = $user->firstname;
+    }
+    return $displayname;
+}
+
+/**
+ * A centralised location for the all name fields. Returns an array / sql string snippet.
+ *
+ * @param bool $returnsql True for an sql select field snippet.
+ * @param string $alias table alias to use in front of each field.
+ * @return array|string All name fields.
+ */
+function get_all_user_name_fields($returnsql = false, $alias = null) {
+    $alternatenames = array('firstnamephonetic',
+                            'lastnamephonetic',
+                            'middlename',
+                            'alternatename',
+                            'firstname',
+                            'lastname',);
+    if ($returnsql) {
+        if ($alias) {
+            foreach ($alternatenames as $key => $altname) {
+                $alternatenames[$key] = "$alias.$altname";
+            }
         }
+        $alternatenames = implode(',', $alternatenames);
     }
+    return $alternatenames;
+}
 
-    return get_string('fullnamedisplay', '', $user);
+/**
+ * Returns an array of values in order of occurance in a provided string.
+ * The key in the result is the character postion in the string.
+ *
+ * @param array $values Values to be found in the string format
+ * @param string $stringformat The string which may contain values being searched for.
+ * @return array An array of values in order according to placement in the string format.
+ */
+function order_in_string($values, $stringformat) {
+    $valuearray = array();
+    foreach ($values as $value) {
+        $pattern = "/$value\b/";
+        // Using preg_match as strpos() may match values that are similar e.g. firstname and firstnamephonetic.
+        if (preg_match($pattern, $stringformat)) {
+            $replacement = "thing";
+            // replace the value with something more unique to ensure we get the right position when using strpos().
+            $newformat = preg_replace($pattern, $replacement, $stringformat);
+            $position = strpos($newformat, $replacement);
+            $valuearray[$position] = $value;
+        }
+    }
+    ksort($valuearray);
+    return $valuearray;
 }
 
 /**
@@ -7216,6 +7309,11 @@ class core_string_manager implements string_manager {
         // 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();
+        }
     }
 
     /**
index d309175..344d4df 100644 (file)
@@ -131,7 +131,8 @@ class user_picture implements renderable {
      * @var array List of mandatory fields in user record here. (do not include
      * TEXT columns because it would break SELECT DISTINCT in MSSQL and ORACLE)
      */
-    protected static $fields = array('id', 'picture', 'firstname', 'lastname', 'imagealt', 'email');
+    protected static $fields = array('id', 'picture', 'firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic',
+            'middlename', 'alternatename', 'imagealt', 'email');
 
     /**
      * @var stdClass A user object with at least fields all columns specified
@@ -224,7 +225,6 @@ class user_picture implements renderable {
         if ($tableprefix) {
             $tableprefix .= '.';
         }
-        $fields = array();
         foreach (self::$fields as $field) {
             if ($field === 'id' and $idalias and $idalias !== 'id') {
                 $fields[$field] = "$tableprefix$field AS $idalias";
index ed38405..0593812 100644 (file)
@@ -31,6 +31,15 @@ error_reporting(E_ALL | E_STRICT);
 ini_set('display_errors', '1');
 ini_set('log_errors', '1');
 
+// Make sure OPcache does not strip comments, we need them in phpunit!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require_once(__DIR__.'/bootstraplib.php');
 require_once(__DIR__.'/../testing/lib.php');
 require_once(__DIR__.'/classes/autoloader.php');
index 55654ae..7e37fde 100644 (file)
@@ -146,7 +146,8 @@ class phpunit_autoloader implements PHPUnit_Runner_TestSuiteLoader {
             );
         }
 
-        return $class;
+        $classname = reset($candidates);
+        return new ReflectionClass($classname);
     }
 
     public function reload(ReflectionClass $aClass) {
index 97c7681..85cdaed 100644 (file)
@@ -160,6 +160,10 @@ class phpunit_util extends testing_util {
         $_SERVER = self::get_global_backup('_SERVER');
         $CFG = self::get_global_backup('CFG');
         $SITE = self::get_global_backup('SITE');
+        $_GET = array();
+        $_POST = array();
+        $_FILES = array();
+        $_REQUEST = array();
         $COURSE = $SITE;
 
         // reinitialise following globals
index 60e058c..61f5a30 100644 (file)
@@ -219,6 +219,28 @@ class core_phpunit_advanced_testcase extends advanced_testcase {
         $this->assertTrue(isset($CFG->admin));
         $this->assertEquals(1, $CFG->rolesactive);
 
+        // _GET change.
+        $_GET['__somethingthatwillnotnormallybepresent__'] = 'yy';
+        phpunit_util::reset_all_data(true);
+
+        $this->assertEquals(array(), $_GET);
+
+
+        // _POST change.
+        $_POST['__somethingthatwillnotnormallybepresent2__'] = 'yy';
+        phpunit_util::reset_all_data(true);
+        $this->assertEquals(array(), $_POST);
+
+        // _FILES change.
+        $_FILES['__somethingthatwillnotnormallybepresent3__'] = 'yy';
+        phpunit_util::reset_all_data(true);
+        $this->assertEquals(array(), $_FILES);
+
+        // _REQUEST change.
+        $_REQUEST['__somethingthatwillnotnormallybepresent4__'] = 'yy';
+        phpunit_util::reset_all_data(true);
+        $this->assertEquals(array(), $_REQUEST);
+
         //silent changes
         $_SERVER['xx'] = 'yy';
         phpunit_util::reset_all_data(true);
index d42429f..0f79447 100644 (file)
@@ -289,6 +289,11 @@ umask(0000);
 $CFG->yui2version = '2.9.0';
 $CFG->yui3version = '3.9.1';
 
+if (!defined('MOODLE_INTERNAL')) { // Necessary because cli installer has to define it earlier.
+    /** Used by library scripts to check they are being called by Moodle. */
+    define('MOODLE_INTERNAL', true);
+}
+
 // core_component can be used in any scripts, it does not need anything else.
 require_once($CFG->libdir .'/classes/component.php');
 
@@ -316,11 +321,6 @@ if (defined('ABORT_AFTER_CONFIG')) {
     }
 }
 
-/** Used by library scripts to check they are being called by Moodle */
-if (!defined('MOODLE_INTERNAL')) { // necessary because cli installer has to define it earlier
-    define('MOODLE_INTERNAL', true);
-}
-
 // Early profiling start, based exclusively on config.php $CFG settings
 if (!empty($CFG->earlyprofilingenabled)) {
     require_once($CFG->libdir . '/xhprof/xhprof_moodle.php');
index ebd4886..06e97dc 100644 (file)
@@ -1100,24 +1100,23 @@ class flexible_table {
             switch ($column) {
 
                 case 'fullname':
-                if ($this->is_sortable($column)) {
-                    $firstnamesortlink = $this->sort_link(get_string('firstname'),
-                            'firstname', $primary_sort_column === 'firstname', $primary_sort_order);
-
-                    $lastnamesortlink = $this->sort_link(get_string('lastname'),
-                            'lastname', $primary_sort_column === 'lastname', $primary_sort_order);
-
-                    $override = new stdClass();
-                    $override->firstname = 'firstname';
-                    $override->lastname = 'lastname';
-                    $fullnamelanguage = get_string('fullnamedisplay', '', $override);
-
-                    if (($CFG->fullnamedisplay == 'firstname lastname') or
-                        ($CFG->fullnamedisplay == 'firstname') or
-                        ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
-                        $this->headers[$index] = $firstnamesortlink . ' / ' . $lastnamesortlink;
-                    } else {
-                        $this->headers[$index] = $lastnamesortlink . ' / ' . $firstnamesortlink;
+                // Check the full name display for sortable fields.
+                $nameformat = $CFG->fullnamedisplay;
+                if ($nameformat == 'language') {
+                    $nameformat = get_string('fullnamedisplay');
+                }
+                $requirednames = order_in_string(array('firstname', 'lastname'), $nameformat);
+
+                if (!empty($requirednames)) {
+                    if ($this->is_sortable($column)) {
+                        // Done this way for the possibility of more than two sortable full name display fields.
+                        $this->headers[$index] = '';
+                        foreach ($requirednames as $name) {
+                            $sortname = $this->sort_link(get_string($name),
+                                    $name, $primary_sort_column === $name, $primary_sort_order);
+                            $this->headers[$index] .= $sortname . ' / ';
+                        }
+                        $this->headers[$index] = substr($this->headers[$index], 0, -3);
                     }
                 }
                 break;
index a2578c7..552c162 100644 (file)
@@ -159,6 +159,26 @@ EOD;
             $record['lastname'] = 'Lastname'.$i;
         }
 
+        if (!isset($record['firstnamephonetic'])) {
+            $firstnamephonetic = rand(0, 59);
+            $record['firstnamephonetic'] = $this->firstnames[$firstnamephonetic];
+        }
+
+        if (!isset($record['lasttnamephonetic'])) {
+            $lastnamephonetic = rand(0, 59);
+            $record['lastnamephonetic'] = $this->lastnames[$lastnamephonetic];
+        }
+
+        if (!isset($record['middlename'])) {
+            $middlename = rand(0, 59);
+            $record['middlename'] = $this->firstnames[$middlename];
+        }
+
+        if (!isset($record['alternatename'])) {
+            $alternatename = rand(0, 59);
+            $record['alternatename'] = $this->firstnames[$alternatename];
+        }
+
         if (!isset($record['idnumber'])) {
             $record['idnumber'] = '';
         }
index db0e226..f15e5f6 100644 (file)
@@ -29,7 +29,8 @@ require_once(__DIR__ . '/../../behat/behat_base.php');
 
 use Behat\Mink\Exception\ExpectationException as ExpectationException,
     Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
-    Behat\Mink\Exception\DriverException as DriverException;
+    Behat\Mink\Exception\DriverException as DriverException,
+    WebDriver\Exception\NoSuchElement as NoSuchElement;
 
 /**
  * Cross component steps definitions.
@@ -78,10 +79,17 @@ class behat_general extends behat_base {
             return false;
         }
 
-        $content = $metarefresh->getAttribute('content');
+        // Wrapped in try & catch in case the redirection has already been executed.
+        try {
+            $content = $metarefresh->getAttribute('content');
+        } catch (NoSuchElement $e) {
+            return false;
+        }
+
+        // Getting the refresh time and the url if present.
         if (strstr($content, 'url') != false) {
 
-            list($waittime, $url) = explode(';', $metarefresh->getAttribute('content'));
+            list($waittime, $url) = explode(';', $content);
 
             // Cleaning the URL value.
             $url = trim(substr($url, strpos($url, 'http')));
index 627d8f8..112e743 100644 (file)
@@ -2623,4 +2623,163 @@ class moodlelib_testcase extends advanced_testcase {
             $this->assertFalse(password_is_legacy_hash($user->password));
         }
     }
+
+    public function test_fullname() {
+        global $CFG;
+
+        $this->resetAfterTest();
+
+        // Create a user to test the name display on.
+        $record = array();
+        $record['firstname'] = 'Scott';
+        $record['lastname'] = 'Fletcher';
+        $record['firstnamephonetic'] = 'スコット';
+        $record['lastnamephonetic'] = 'フレチャー';
+        $record['alternatename'] = 'No friends';
+        $user = $this->getDataGenerator()->create_user($record);
+
+        // back up config settings for restore later.
+        $originalcfg = new stdClass();
+        $originalcfg->fullnamedisplay = $CFG->fullnamedisplay;
+
+        // Testing existing fullnamedisplay settings.
+        $CFG->fullnamedisplay = 'firstname';
+        $testname = fullname($user);
+        $this->assertEquals($testname, $user->firstname);
+
+        $CFG->fullnamedisplay = 'firstname lastname';
+        $expectedname = "$user->firstname $user->lastname";
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        $CFG->fullnamedisplay = 'lastname firstname';
+        $expectedname = "$user->lastname $user->firstname";
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        $expectedname = get_string('fullnamedisplay', null, $user);
+        $CFG->fullnamedisplay = 'language';
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        // Test override parameter.
+        $CFG->fullnamedisplay = 'firstname';
+        $expectedname = "$user->firstname $user->lastname";
+        $testname = fullname($user, true);
+        $this->assertEquals($testname, $expectedname);
+
+        // Test additional name fields.
+        $CFG->fullnamedisplay = 'lastname lastnamephonetic firstname firstnamephonetic';
+        $expectedname = "$user->lastname $user->lastnamephonetic $user->firstname $user->firstnamephonetic";
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        // Test for handling missing data.
+        $user->middlename = null;
+        // Parenthesis with no data.
+        $CFG->fullnamedisplay = 'firstname (middlename) lastname';
+        $expectedname = "$user->firstname $user->lastname";
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        // Extra spaces due to no data.
+        $CFG->fullnamedisplay = 'firstname middlename lastname';
+        $expectedname = "$user->firstname $user->lastname";
+        $testname = fullname($user);
+        $this->assertEquals($testname, $expectedname);
+
+        // Regular expression testing.
+        // Remove some data from the user fields
+        $user->firstnamephonetic = '';
+        $user->lastnamephonetic = '';
+
+        // Removing empty brackets and excess whitespace.
+        // All of these configurations should resolve to just firstname lastname.
+        $configarray = array();
+        $configarray[] = 'firstname lastname [firstnamephonetic lastnamephonetic]';
+        $configarray[] = 'firstname lastname \'middlename\'';
+        $configarray[] = 'firstname "firstnamephonetic" lastname';
+        $configarray[] = 'firstname 「firstnamephonetic」 lastname 「lastnamephonetic」';
+
+        foreach ($configarray as $config) {
+            $CFG->fullnamedisplay = $config;
+            $expectedname = "$user->firstname $user->lastname";
+            $testname = fullname($user);
+            $this->assertEquals($testname, $expectedname);
+        }
+
+        // Check to make sure that other characters are left in place.
+        $configarray = array();
+        $configarray['0'] = new stdClass();
+        $configarray['0']->config = 'lastname firstname, middlename';
+        $configarray['0']->expectedname = "$user->lastname $user->firstname,";
+        $configarray['1'] = new stdClass();
+        $configarray['1']->config = 'lastname firstname + alternatename';
+        $configarray['1']->expectedname = "$user->lastname $user->firstname + $user->alternatename";
+        $configarray['2'] = new stdClass();
+        $configarray['2']->config = 'firstname aka: alternatename';
+        $configarray['2']->expectedname = "$user->firstname aka: $user->alternatename";
+        $configarray['3'] = new stdClass();
+        $configarray['3']->config = 'firstname (alternatename)';
+        $configarray['3']->expectedname = "$user->firstname ($user->alternatename)";
+        $configarray['4'] = new stdClass();
+        $configarray['4']->config = 'firstname [alternatename]';
+        $configarray['4']->expectedname = "$user->firstname [$user->alternatename]";
+        $configarray['5'] = new stdClass();
+        $configarray['5']->config = 'firstname "lastname"';
+        $configarray['5']->expectedname = "$user->firstname \"$user->lastname\"";
+
+        foreach ($configarray as $config) {
+            $CFG->fullnamedisplay = $config->config;
+            $expectedname = $config->expectedname;
+            $testname = fullname($user);
+            $this->assertEquals($testname, $expectedname);
+        }
+
+        // tidy up after we finish testing.
+        $CFG->fullnamedisplay = $originalcfg->fullnamedisplay;
+    }
+
+    public function test_get_all_user_name_fields() {
+        $this->resetAfterTest();
+
+        // Additional names in an array.
+        $testarray = array('firstnamephonetic',
+                           'lastnamephonetic',
+                           'middlename',
+                           'alternatename',
+                           'firstname',
+                           'lastname');
+        $this->assertEquals($testarray, get_all_user_name_fields());
+
+        // Additional names as a string.
+        $teststring = 'firstnamephonetic,lastnamephonetic,middlename,alternatename,firstname,lastname';
+        $this->assertEquals($teststring, get_all_user_name_fields(true));
+
+        // Additional names as a string with an alias.
+        $teststring = 't.firstnamephonetic,t.lastnamephonetic,t.middlename,t.alternatename,t.firstname,t.lastname';
+        $this->assertEquals($teststring, get_all_user_name_fields(true, 't'));
+    }
+
+    public function test_order_in_string() {
+        $this->resetAfterTest();
+
+        // Return an array in an order as they are encountered in a string.
+        $valuearray = array('second', 'firsthalf', 'first');
+        $formatstring = 'first firsthalf some other text (second)';
+        $expectedarray = array('0' => 'first', '6' => 'firsthalf', '33' => 'second');
+        $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
+
+        // Try again with a different order for the format.
+        $valuearray = array('second', 'firsthalf', 'first');
+        $formatstring = 'firsthalf first second';
+        $expectedarray = array('0' => 'firsthalf', '10' => 'first', '16' => 'second');
+        $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
+
+        // Try again with yet another different order for the format.
+        $valuearray = array('second', 'firsthalf', 'first');
+        $formatstring = 'start seconds away second firstquater first firsthalf';
+        $expectedarray = array('19' => 'second', '38' => 'first', '44' => 'firsthalf');
+        $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
+    }
 }
index ea21820..547a9d1 100644 (file)
@@ -70,6 +70,7 @@ if ($mform->is_cancelled()) {
 
     if ($data->id) {
         // store the files
+        $data->timemodified = time();
         $data = file_postupdate_standard_editor($data, 'content', $options, $context, 'mod_book', 'chapter', $data->id);
         $DB->update_record('book_chapters', $data);
         $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
index 9051b74..2da45f7 100644 (file)
@@ -3548,12 +3548,14 @@ function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
  */
 function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $sortorder) {
     global $DB;
+
+    $namefields = get_all_user_name_fields(true, 'u');
     if ($sort == 0) {
-        $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname
+        $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . '
                         FROM {data_content} c,
                              {data_records} r,
                              {user} u ';
-        $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname ';
+        $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' . $namefields;
     } else {
         // Sorting through 'Other' criteria
         if ($sort <= 0) {
@@ -3580,12 +3582,13 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
             $sortcontentfull = $sortfield->get_sort_sql($sortcontent);
         }
 
-        $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' . $sortcontentfull . '
+        $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . ',
+                                 ' . $sortcontentfull . '
                               AS sortorder
                             FROM {data_content} c,
                                  {data_records} r,
                                  {user} u ';
-        $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' .$sortcontentfull;
+        $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . ', ' .$sortcontentfull;
     }
 
     // Default to a standard Where statement if $selectdata is empty.
index 2980643..bfc84b8 100644 (file)
@@ -162,6 +162,10 @@ class data_advanced_search_sql_test extends advanced_testcase {
         $this->finalrecord[6]->userid = 6;
         $this->finalrecord[6]->firstname = $user->firstname;
         $this->finalrecord[6]->lastname = $user->lastname;
+        $this->finalrecord[6]->firstnamephonetic = $user->firstnamephonetic;
+        $this->finalrecord[6]->lastnamephonetic = $user->lastnamephonetic;
+        $this->finalrecord[6]->middlename = $user->middlename;
+        $this->finalrecord[6]->alternatename = $user->alternatename;
     }
 
     /**
index 1b8b278..3192721 100644 (file)
@@ -498,6 +498,7 @@ if ($showactivity) {
         $advparams       = array();
         // This is used for the initial reduction of advanced search results with required entries.
         $entrysql        = '';
+        $namefields = get_all_user_name_fields(true, 'u');
 
     /// Find the field we are sorting on
         if ($sort <= 0 or !$sortfield = data_get_field_from_id($sort, $data)) {
@@ -521,7 +522,7 @@ if ($showactivity) {
                     $ordering = "r.timecreated $order";
             }
 
-            $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname';
+            $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields;
             $count = ' COUNT(DISTINCT c.recordid) ';
             $tables = '{data_content} c,{data_records} r, {user} u ';
             $where =  'WHERE c.recordid = r.id
@@ -554,7 +555,9 @@ if ($showactivity) {
                     $advparams = array_merge($advparams, $val->params);
                 }
             } else if ($search) {
-                $searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)." OR ".$DB->sql_like('u.firstname', ':search2', false)." OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
+                $searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)."
+                                  OR ".$DB->sql_like('u.firstname', ':search2', false)."
+                                  OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
                 $params['search1'] = "%$search%";
                 $params['search2'] = "%$search%";
                 $params['search3'] = "%$search%";
@@ -567,7 +570,8 @@ if ($showactivity) {
             $sortcontent = $DB->sql_compare_text('c.' . $sortfield->get_sort_field());
             $sortcontentfull = $sortfield->get_sort_sql($sortcontent);
 
-            $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' . $sortcontentfull . ' AS sortorder ';
+            $what = ' DISTINCT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . ',
+                    ' . $sortcontentfull . ' AS sortorder ';
             $count = ' COUNT(DISTINCT c.recordid) ';
             $tables = '{data_content} c, {data_records} r, {user} u ';
             $where =  'WHERE c.recordid = r.id
index f3e33c8..e23f4a8 100644 (file)
@@ -1763,7 +1763,8 @@ function forum_scale_used_anywhere($scaleid) {
 function forum_get_post_full($postid) {
     global $CFG, $DB;
 
-    return $DB->get_record_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
+    $allnames = get_all_user_name_fields(true, 'u');
+    return $DB->get_record_sql("SELECT p.*, d.forum, $allnames, u.email, u.picture, u.imagealt
                              FROM {forum_posts} p
                                   JOIN {forum_discussions} d ON p.discussion = d.id
                                   LEFT JOIN {user} u ON p.userid = u.id
@@ -1782,7 +1783,8 @@ function forum_get_post_full($postid) {
 function forum_get_discussion_posts($discussion, $sort, $forumid) {
     global $CFG, $DB;
 
-    return $DB->get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
+    $allnames = get_all_user_name_fields(true, 'u');
+    return $DB->get_records_sql("SELECT p.*, $forumid AS forum, $allnames, u.email, u.picture, u.imagealt
                               FROM {forum_posts} p
                          LEFT JOIN {user} u ON p.userid = u.id
                              WHERE p.discussion = ?
@@ -1815,8 +1817,9 @@ function forum_get_all_discussion_posts($discussionid, $sort, $tracking=false) {
         $params[] = $USER->id;
     }
 
+    $allnames = get_all_user_name_fields(true, 'u');
     $params[] = $discussionid;
-    if (!$posts = $DB->get_records_sql("SELECT p.*, u.firstname, u.lastname, u.email, u.picture, u.imagealt $tr_sel
+    if (!$posts = $DB->get_records_sql("SELECT p.*, $allnames, u.email, u.picture, u.imagealt $tr_sel
                                      FROM {forum_posts} p
                                           LEFT JOIN {user} u ON p.userid = u.id
                                           $tr_join
@@ -1860,7 +1863,8 @@ function forum_get_all_discussion_posts($discussionid, $sort, $tracking=false) {
 function forum_get_child_posts($parent, $forumid) {
     global $CFG, $DB;
 
-    return $DB->get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
+    $allnames = get_all_user_name_fields(true, 'u');
+    return $DB->get_records_sql("SELECT p.*, $forumid AS forum, $allnames, u.email, u.picture, u.imagealt
                               FROM {forum_posts} p
                          LEFT JOIN {user} u ON p.userid = u.id
                              WHERE p.parent = ?
@@ -2103,10 +2107,10 @@ function forum_search_posts($searchterms, $courseid=0, $limitfrom=0, $limitnum=5
                    FROM $fromsql
                   WHERE $selectsql";
 
+    $allnames = get_all_user_name_fields(true, 'u');
     $searchsql = "SELECT p.*,
                          d.forum,
-                         u.firstname,
-                         u.lastname,
+                         $allnames,
                          u.email,
                          u.picture,
                          u.imagealt
@@ -2243,7 +2247,8 @@ function forum_get_user_posts($forumid, $userid) {
         }
     }
 
-    return $DB->get_records_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
+    $allnames = get_all_user_name_fields(true, 'u');
+    return $DB->get_records_sql("SELECT p.*, d.forum, $allnames, u.email, u.picture, u.imagealt
                               FROM {forum} f
                                    JOIN {forum_discussions} d ON d.forum = f.id
                                    JOIN {forum_posts} p       ON p.discussion = d.id
@@ -2333,10 +2338,10 @@ function forum_count_user_posts($forumid, $userid) {
 function forum_get_post_from_log($log) {
     global $CFG, $DB;
 
+    $allnames = get_all_user_name_fields(true, 'u');
     if ($log->action == "add post") {
 
-        return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
-                                           u.firstname, u.lastname, u.email, u.picture
+        return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid, $allnames, u.email, u.picture
                                  FROM {forum_discussions} d,
                                       {forum_posts} p,
                                       {forum} f,
@@ -2350,8 +2355,7 @@ function forum_get_post_from_log($log) {
 
     } else if ($log->action == "add discussion") {
 
-        return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
-                                           u.firstname, u.lastname, u.email, u.picture
+        return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid, $allnames, u.email, u.picture
                                  FROM {forum_discussions} d,
                                       {forum_posts} p,
                                       {forum} f,
@@ -2684,8 +2688,9 @@ function forum_get_discussions($cm, $forumsort="d.timemodified DESC", $fullpost=
         $umtable  = " LEFT JOIN {user} um ON (d.usermodified = um.id)";
     }
 
-    $sql = "SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend,
-                   u.firstname, u.lastname, u.email, u.picture, u.imagealt $umfields
+    $allnames = get_all_user_name_fields(true, 'u');
+    $sql = "SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend, $allnames,
+                   u.email, u.picture, u.imagealt $umfields
               FROM {forum_discussions} d
                    JOIN {forum_posts} p ON p.discussion = d.id
                    JOIN {user} u ON p.userid = u.id
@@ -2862,7 +2867,8 @@ function forum_get_user_discussions($courseid, $userid, $groupid=0) {
         $groupselect = "";
     }
 
-    return $DB->get_records_sql("SELECT p.*, d.groupid, u.firstname, u.lastname, u.email, u.picture, u.imagealt,
+    $allnames = get_all_user_name_fields(true, 'u');
+    return $DB->get_records_sql("SELECT p.*, d.groupid, $allnames, u.email, u.picture, u.imagealt,
                                    f.type as forumtype, f.name as forumname, f.id as forumid
                               FROM {forum_discussions} d,
                                    {forum_posts} p,
@@ -2919,11 +2925,11 @@ function forum_get_potential_subscribers($forumcontext, $groupid, $fields, $sort
 function forum_subscribed_users($course, $forum, $groupid=0, $context = null, $fields = null) {
     global $CFG, $DB;
 
+    $allnames = get_all_user_name_fields(true, 'u');
     if (empty($fields)) {
         $fields ="u.id,
                   u.username,
-                  u.firstname,
-                  u.lastname,
+                  $allnames,
                   u.maildisplay,
                   u.mailformat,
                   u.maildigest,
@@ -3301,8 +3307,9 @@ function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=fa
     // Build an object that represents the posting user
     $postuser = new stdClass;
     $postuser->id        = $post->userid;
-    $postuser->firstname = $post->firstname;
-    $postuser->lastname  = $post->lastname;
+    foreach (get_all_user_name_fields() as $addname) {
+        $postuser->$addname  = $post->$addname;
+    }
     $postuser->imagealt  = $post->imagealt;
     $postuser->picture   = $post->picture;
     $postuser->email     = $post->email;
@@ -3732,8 +3739,9 @@ function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring=""
     // Picture
     $postuser = new stdClass();
     $postuser->id = $post->userid;
-    $postuser->firstname = $post->firstname;
-    $postuser->lastname = $post->lastname;
+    foreach (get_all_user_name_fields() as $addname) {
+        $postuser->$addname = $post->$addname;
+    }
     $postuser->imagealt = $post->imagealt;
     $postuser->picture = $post->picture;
     $postuser->email = $post->email;
@@ -3800,8 +3808,10 @@ function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring=""
     $parenturl = (empty($post->lastpostid)) ? '' : '&amp;parent='.$post->lastpostid;
     $usermodified = new stdClass();
     $usermodified->id        = $post->usermodified;
-    $usermodified->firstname = $post->umfirstname;
-    $usermodified->lastname  = $post->umlastname;
+    foreach (get_all_user_name_fields() as $addname) {
+        $temp = 'um' . $addname;
+        $usermodified->$addname  = $post->$temp;
+    }
     echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->usermodified.'&amp;course='.$forum->course.'">'.
          fullname($usermodified).'</a><br />';
     echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.$parenturl.'">'.
@@ -6043,9 +6053,10 @@ function forum_get_recent_mod_activity(&$activities, &$index, $timestart, $cours
         $groupjoin   = "";
     }
 
+    $allnames = get_all_user_name_fields(true, 'u');
     if (!$posts = $DB->get_records_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
                                               d.timestart, d.timeend, d.userid AS duserid,
-                                              u.firstname, u.lastname, u.email, u.picture, u.imagealt, u.email
+                                              $allnames, u.email, u.picture, u.imagealt, u.email
                                          FROM {forum_posts} p
                                               JOIN {forum_discussions} d ON d.id = p.discussion
                                               JOIN {forum} f             ON f.id = d.forum
@@ -6118,11 +6129,12 @@ function forum_get_recent_mod_activity(&$activities, &$index, $timestart, $cours
 
         $tmpactivity->user = new stdClass();
         $tmpactivity->user->id        = $post->userid;
-        $tmpactivity->user->firstname = $post->firstname;
-        $tmpactivity->user->lastname  = $post->lastname;
         $tmpactivity->user->picture   = $post->picture;
         $tmpactivity->user->imagealt  = $post->imagealt;
         $tmpactivity->user->email     = $post->email;
+        foreach (get_all_user_name_fields() as $addname) {
+            $tmpactivity->user->$addname = $post->$addname;
+        }
 
         $activities[$index++] = $tmpactivity;
     }
index 7937ebd..80202e2 100644 (file)
@@ -835,14 +835,15 @@ class mod_quiz_renderer extends plugin_renderer_base {
         global $CFG;
 
         $output = '';
+
         // Print quiz name and description.
         $output .= $this->heading(format_string($quiz->name));
-        if (trim(strip_tags($quiz->intro))) {
-            $output .= $this->box(format_module_intro('quiz', $quiz, $cm->id), 'generalbox',
-                    'intro');
-        }
+        $output .= $this->quiz_intro($quiz, $cm);
 
-        $output .= $this->box($this->access_messages($messages), 'quizinfo');
+        // Output any access messages.
+        if ($messages) {
+            $output .= $this->box($this->access_messages($messages), 'quizinfo');
+        }
 
         // Show number of attempts summary to those who can view reports.
         if (has_capability('mod/quiz:viewreports', $context)) {
@@ -862,13 +863,11 @@ class mod_quiz_renderer extends plugin_renderer_base {
      * @return string HTML to output.
      */
     public function quiz_intro($quiz, $cm) {
-        if (trim(strip_tags($quiz->intro))) {
-            return $this->box(format_module_intro('quiz', $quiz, $cm->id),
-                    'generalbox', 'intro');
-
-        } else {
+        if (html_is_blank($quiz->intro)) {
             return '';
         }
+
+        return $this->box(format_module_intro('quiz', $quiz, $cm->id), 'generalbox', 'intro');
     }
 
     /**
index 3795776..52c34e3 100644 (file)
@@ -122,11 +122,12 @@ abstract class quiz_attempts_report_table extends table_sql {
         global $OUTPUT;
         $user = new stdClass();
         $user->id = $attempt->userid;
-        $user->lastname = $attempt->lastname;
-        $user->firstname = $attempt->firstname;
         $user->imagealt = $attempt->imagealt;
         $user->picture = $attempt->picture;
         $user->email = $attempt->email;
+        foreach (get_all_user_name_fields() as $addname) {
+            $user->$addname = $attempt->$addname;
+        }
         return $OUTPUT->user_picture($user);
     }
 
@@ -345,13 +346,12 @@ abstract class quiz_attempts_report_table extends table_sql {
         $extrafields = get_extra_user_fields_sql($this->context, 'u', '',
                 array('id', 'idnumber', 'firstname', 'lastname', 'picture',
                 'imagealt', 'institution', 'department', 'email'));
+        $allnames = get_all_user_name_fields(true, 'u');
         $fields .= '
                 quiza.uniqueid AS usageid,
                 quiza.id AS attempt,
                 u.id AS userid,
-                u.idnumber,
-                u.firstname,
-                u.lastname,
+                u.idnumber, ' . $allnames . ',
                 u.picture,
                 u.imagealt,
                 u.institution,
index 06ffdca..fe26e54 100644 (file)
@@ -137,6 +137,7 @@ function scorm_add_instance($scorm, $mform=null) {
         $record->reference = $scorm->packageurl;
     } else if ($record->scormtype === SCORM_TYPE_AICCURL) {
         $record->reference = $scorm->packageurl;
+        $record->hidetoc = SCORM_TOC_DISABLED; // TOC is useless for direct AICCURL so disable it.
     } else {
         return false;
     }
@@ -208,6 +209,7 @@ function scorm_update_instance($scorm, $mform=null) {
         $scorm->reference = $scorm->packageurl;
     } else if ($scorm->scormtype === SCORM_TYPE_AICCURL) {
         $scorm->reference = $scorm->packageurl;
+        $scorm->hidetoc = SCORM_TOC_DISABLED; // TOC is useless for direct AICCURL so disable it.
     } else {
         return false;
     }
index e44bb6c..8263a6d 100644 (file)
@@ -160,6 +160,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->addHelpButton('hidetoc', 'hidetoc', 'scorm');
         $mform->setDefault('hidetoc', $cfg_scorm->hidetoc);
         $mform->setAdvanced('hidetoc', $cfg_scorm->hidetoc_adv);
+        $mform->disabledIf('hidetoc', 'scormtype', 'eq', SCORM_TYPE_AICCURL);
 
         // Hide Navigation panel.
         $mform->addElement('selectyesno', 'hidenav', get_string('hidenav', 'scorm'));
index c8d1082..aac8d1c 100644 (file)
@@ -273,7 +273,7 @@ class scorm_basic_report extends scorm_default_report {
                             // Construct the SQL
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
-                    'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, u.email' .
+                    user_picture::fields('u', array('idnumber'), 'userid') .
                     get_extra_user_fields_sql($coursecontext, 'u', '', array('email', 'idnumber')) . ' ';
 
             // This part is the same for all cases - join users and scorm_scoes_track tables
@@ -384,9 +384,10 @@ class scorm_basic_report extends scorm_default_report {
                                     'id'=>$scouser->userid,
                                     'picture'=>$scouser->picture,
                                     'imagealt'=>$scouser->imagealt,
-                                    'email'=>$scouser->email,
-                                    'firstname'=>$scouser->firstname,
-                                    'lastname'=>$scouser->lastname);
+                                    'email'=>$scouser->email);
+                        foreach (get_all_user_name_fields() as $addname) {
+                            $user->$addname = $scouser->$addname;
+                        }
                         $row[] = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
                     }
                     if (!$download) {
index 71d4ce4..7b3ebb4 100644 (file)
@@ -158,10 +158,10 @@ class scorm_interactions_report extends scorm_default_report {
 
             $params = array();
             list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED);
-                                    // Construct the SQL
+            // Construct the SQL
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
-                    'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, u.email'.
+                    user_picture::fields('u', array('idnumber'), 'userid') .
                     get_extra_user_fields_sql($coursecontext, 'u', '', array('email', 'idnumber')) . ' ';
 
             // This part is the same for all cases - join users and scorm_scoes_track tables
@@ -419,9 +419,10 @@ class scorm_interactions_report extends scorm_default_report {
                                     'id'=>$scouser->userid,
                                     'picture'=>$scouser->picture,
                                     'imagealt'=>$scouser->imagealt,
-                                    'email'=>$scouser->email,
-                                    'firstname'=>$scouser->firstname,
-                                    'lastname'=>$scouser->lastname);
+                                    'email'=>$scouser->email);
+                        foreach (get_all_user_name_fields() as $addname) {
+                            $user->$addname = $scouser->$addname;
+                        }
                         $row[] = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
                     }
                     if (!$download) {
index 24df2c7..5e00ac4 100644 (file)
@@ -224,15 +224,18 @@ class workshop_manual_allocator implements workshop_allocator {
 
         // load the participants' submissions
         $submissions = $this->workshop->get_submissions(array_keys($participants));
+        $allnames = get_all_user_name_fields();
         foreach ($submissions as $submission) {
             if (!isset($userinfo[$submission->authorid])) {
                 $userinfo[$submission->authorid]            = new stdclass();
                 $userinfo[$submission->authorid]->id        = $submission->authorid;
-                $userinfo[$submission->authorid]->firstname = $submission->authorfirstname;
-                $userinfo[$submission->authorid]->lastname  = $submission->authorlastname;
                 $userinfo[$submission->authorid]->picture   = $submission->authorpicture;
                 $userinfo[$submission->authorid]->imagealt  = $submission->authorimagealt;
                 $userinfo[$submission->authorid]->email     = $submission->authoremail;
+                foreach ($allnames as $addname) {
+                    $temp = 'author' . $addname;
+                    $userinfo[$submission->authorid]->$addname = $submission->$temp;
+                }
             }
         }
 
@@ -240,8 +243,8 @@ class workshop_manual_allocator implements workshop_allocator {
         $reviewers = array();
         if ($submissions) {
             list($submissionids, $params) = $DB->get_in_or_equal(array_keys($submissions), SQL_PARAMS_NAMED);
-            $sql = "SELECT a.id AS assessmentid, a.submissionid,
-                           r.id AS reviewerid, r.lastname, r.firstname, r.picture, r.imagealt, r.email,
+            $picturefields = user_picture::fields('r', array(), 'reviewerid')
+            $sql = "SELECT a.id AS assessmentid, a.submissionid, $picturefields,
                            s.id AS submissionid, s.authorid
                       FROM {workshop_assessments} a
                       JOIN {user} r ON (a.reviewerid = r.id)
@@ -252,11 +255,12 @@ class workshop_manual_allocator implements workshop_allocator {
                 if (!isset($userinfo[$reviewer->reviewerid])) {
                     $userinfo[$reviewer->reviewerid]            = new stdclass();
                     $userinfo[$reviewer->reviewerid]->id        = $reviewer->reviewerid;
-                    $userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
-                    $userinfo[$reviewer->reviewerid]->lastname  = $reviewer->lastname;
                     $userinfo[$reviewer->reviewerid]->picture   = $reviewer->picture;
                     $userinfo[$reviewer->reviewerid]->imagealt  = $reviewer->imagealt;
                     $userinfo[$reviewer->reviewerid]->email     = $reviewer->email;
+                    foreach ($allnames as $addname) {
+                        $userinfo[$reviewer->reviewerid]->$addname = $reviewer->$addname;
+                    }
                 }
             }
         }
@@ -265,11 +269,12 @@ class workshop_manual_allocator implements workshop_allocator {
         $reviewees = array();
         if ($participants) {
             list($participantids, $params) = $DB->get_in_or_equal(array_keys($participants), SQL_PARAMS_NAMED);
+            $namefields = get_all_user_name_fields(true, 'e');
             $params['workshopid'] = $this->workshop->id;
             $sql = "SELECT a.id AS assessmentid, a.submissionid,
                            u.id AS reviewerid,
                            s.id AS submissionid,
-                           e.id AS revieweeid, e.lastname, e.firstname, e.picture, e.imagealt, e.email
+                           e.id AS revieweeid, e.lastname, e.firstname, $namefields, e.picture, e.imagealt, e.email
                       FROM {user} u
                       JOIN {workshop_assessments} a ON (a.reviewerid = u.id)
                       JOIN {workshop_submissions} s ON (a.submissionid = s.id)
@@ -285,6 +290,9 @@ class workshop_manual_allocator implements workshop_allocator {
                     $userinfo[$reviewee->revieweeid]->picture   = $reviewee->picture;
                     $userinfo[$reviewee->revieweeid]->imagealt  = $reviewee->imagealt;
                     $userinfo[$reviewee->revieweeid]->email     = $reviewee->email;
+                    foreach ($allnames as $addname) {
+                        $userinfo[$reviewee->revieweeid]->$addname = $reviewee->$addname;
+                    }
                 }
             }
         }
index 6b143cd..dcbde8e 100644 (file)
@@ -1761,8 +1761,8 @@ class workshop {
                 $sqlsort[] = $sqlsortfieldname . ' ' . $sqlsortfieldhow;
             }
             $sqlsort = implode(',', $sqlsort);
-            $sql = "SELECT u.id AS userid,u.firstname,u.lastname,u.picture,u.imagealt,u.email,
-                           s.title AS submissiontitle, s.grade AS submissiongrade, ag.gradinggrade
+            $picturefields = user_picture::fields('u', array(), 'userid');
+            $sql = "SELECT $picturefields, s.title AS submissiontitle, s.grade AS submissiongrade, ag.gradinggrade
                       FROM {user} u
                  LEFT JOIN {workshop_submissions} s ON (s.authorid = u.id AND s.workshopid = :workshopid1 AND s.example = 0)
                  LEFT JOIN {workshop_aggregations} ag ON (ag.userid = u.id AND ag.workshopid = :workshopid2)
@@ -1777,15 +1777,17 @@ class workshop {
         $userinfo = array();
 
         // get the user details for all participants to display
+        $additionalnames = get_all_user_name_fields();
         foreach ($participants as $participant) {
             if (!isset($userinfo[$participant->userid])) {
                 $userinfo[$participant->userid]            = new stdclass();
                 $userinfo[$participant->userid]->id        = $participant->userid;
-                $userinfo[$participant->userid]->firstname = $participant->firstname;
-                $userinfo[$participant->userid]->lastname  = $participant->lastname;
                 $userinfo[$participant->userid]->picture   = $participant->picture;
                 $userinfo[$participant->userid]->imagealt  = $participant->imagealt;
                 $userinfo[$participant->userid]->email     = $participant->email;
+                foreach ($additionalnames as $addname) {
+                    $userinfo[$participant->userid]->$addname = $participant->$addname;
+                }
             }
         }
 
@@ -1797,22 +1799,25 @@ class workshop {
             if (!isset($userinfo[$submission->gradeoverby])) {
                 $userinfo[$submission->gradeoverby]            = new stdclass();
                 $userinfo[$submission->gradeoverby]->id        = $submission->gradeoverby;
-                $userinfo[$submission->gradeoverby]->firstname = $submission->overfirstname;
-                $userinfo[$submission->gradeoverby]->lastname  = $submission->overlastname;
                 $userinfo[$submission->gradeoverby]->picture   = $submission->overpicture;
                 $userinfo[$submission->gradeoverby]->imagealt  = $submission->overimagealt;
                 $userinfo[$submission->gradeoverby]->email     = $submission->overemail;
+                foreach ($additionalnames as $addname) {
+                    $temp = 'over' . $addname;
+                    $userinfo[$submission->gradeoverby]->$addname = $submission->$temp;
+                }
             }
         }
 
         // get the user details for all reviewers of the displayed participants
         $reviewers = array();
+
         if ($submissions) {
             list($submissionids, $params) = $DB->get_in_or_equal(array_keys($submissions), SQL_PARAMS_NAMED);
             list($sort, $sortparams) = users_order_by_sql('r');
+            $picturefields = user_picture::fields('r', array(), 'reviewerid');
             $sql = "SELECT a.id AS assessmentid, a.submissionid, a.grade, a.gradinggrade, a.gradinggradeover, a.weight,
-                           r.id AS reviewerid, r.lastname, r.firstname, r.picture, r.imagealt, r.email,
-                           s.id AS submissionid, s.authorid
+                           $picturefields, s.id AS submissionid, s.authorid
                       FROM {workshop_assessments} a
                       JOIN {user} r ON (a.reviewerid = r.id)
                       JOIN {workshop_submissions} s ON (a.submissionid = s.id AND s.example = 0)
@@ -1823,11 +1828,12 @@ class workshop {
                 if (!isset($userinfo[$reviewer->reviewerid])) {
                     $userinfo[$reviewer->reviewerid]            = new stdclass();
                     $userinfo[$reviewer->reviewerid]->id        = $reviewer->reviewerid;
-                    $userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
-                    $userinfo[$reviewer->reviewerid]->lastname  = $reviewer->lastname;
                     $userinfo[$reviewer->reviewerid]->picture   = $reviewer->picture;
                     $userinfo[$reviewer->reviewerid]->imagealt  = $reviewer->imagealt;
                     $userinfo[$reviewer->reviewerid]->email     = $reviewer->email;
+                    foreach ($additionalnames as $addname) {
+                        $userinfo[$reviewer->reviewerid]->$addname = $reviewer->$addname;
+                    }
                 }
             }
         }
@@ -1838,9 +1844,9 @@ class workshop {
             list($participantids, $params) = $DB->get_in_or_equal(array_keys($participants), SQL_PARAMS_NAMED);
             list($sort, $sortparams) = users_order_by_sql('e');
             $params['workshopid'] = $this->id;
+            $picturefields = user_picture::fields('e', array(), 'authorid');
             $sql = "SELECT a.id AS assessmentid, a.submissionid, a.grade, a.gradinggrade, a.gradinggradeover, a.reviewerid, a.weight,
-                           s.id AS submissionid,
-                           e.id AS authorid, e.lastname, e.firstname, e.picture, e.imagealt, e.email
+                           s.id AS submissionid, $picturefields
                       FROM {user} u
                       JOIN {workshop_assessments} a ON (a.reviewerid = u.id)
                       JOIN {workshop_submissions} s ON (a.submissionid = s.id AND s.example = 0)
@@ -1852,11 +1858,12 @@ class workshop {
                 if (!isset($userinfo[$reviewee->authorid])) {
                     $userinfo[$reviewee->authorid]            = new stdclass();
                     $userinfo[$reviewee->authorid]->id        = $reviewee->authorid;
-                    $userinfo[$reviewee->authorid]->firstname = $reviewee->firstname;
-                    $userinfo[$reviewee->authorid]->lastname  = $reviewee->lastname;
                     $userinfo[$reviewee->authorid]->picture   = $reviewee->picture;
                     $userinfo[$reviewee->authorid]->imagealt  = $reviewee->imagealt;
                     $userinfo[$reviewee->authorid]->email     = $reviewee->email;
+                    foreach ($additionalnames as $addname) {
+                        $userinfo[$reviewee->authorid]->$addname = $reviewee->$addname;
+                    }
                 }
             }
         }
index a6ff02a..f93b0f2 100644 (file)
@@ -65,7 +65,6 @@ class qtype_calculatedmulti_single_question extends qtype_multichoice_single_que
         qtype_calculatedmulti_calculate_helper::calculate_all_expressions($this);
     }
 
-
     public function get_num_variants() {
         return $this->datasetloader->get_number_of_items();
     }
@@ -115,6 +114,19 @@ class qtype_calculatedmulti_multi_question extends qtype_multichoice_multi_quest
     public function calculate_all_expressions() {
         qtype_calculatedmulti_calculate_helper::calculate_all_expressions($this);
     }
+
+    public function get_num_variants() {
+        return $this->datasetloader->get_number_of_items();
+    }
+
+    public function get_variants_selection_seed() {
+        if (!empty($this->synchronised) &&
+                $this->datasetloader->datasets_are_synchronised($this->category)) {
+            return 'category' . $this->category;
+        } else {
+            return parent::get_variants_selection_seed();
+        }
+    }
 }
 
 
index 35075ba..a6c3a57 100644 (file)
@@ -47,7 +47,7 @@ require_once($CFG->dirroot . '/question/engine/lib.php');
  */
 class question_type {
     protected $fileoptions = array(
-        'subdirs' => false,
+        'subdirs' => true,
         'maxfiles' => -1,
         'maxbytes' => 0,
     );
index 3d8370a..2b55a8a 100644 (file)
@@ -139,10 +139,12 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
 
     // If looking at a different host, we're interested in all our site users
     if ($hostid == $CFG->mnet_localhost_id && $course->id != SITEID) {
-        $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', null, $limitfrom, $limitnum);
+        $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, ' . get_all_user_name_fields(true, 'u'),
+                null, $limitfrom, $limitnum);
     } else {
         // this may be a lot of users :-(
-        $courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, firstname, lastname, idnumber', $limitfrom, $limitnum);
+        $courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, ' . get_all_user_name_fields(true),
+                $limitfrom, $limitnum);
     }
 
     if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) {
@@ -440,7 +442,8 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate=
     $limitfrom = empty($showusers) ? 0 : '';
     $limitnum  = empty($showusers) ? COURSE_MAX_USERS_PER_DROPDOWN + 1 : '';
 
-    $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname', null, $limitfrom, $limitnum);
+    $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, ' . get_all_user_name_fields(true, 'u'),
+            null, $limitfrom, $limitnum);
 
     if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) {
         $showusers = 1;
index bb25071..c3b17f2 100644 (file)
@@ -2077,6 +2077,32 @@ abstract class repository implements cacheable_object {
         return true;
     }
 
+    /**
+     * Delete all the instances associated to a context.
+     *
+     * This method is intended to be a callback when deleting
+     * a course or a user to delete all the instances associated
+     * to their context. The usual way to delete a single instance
+     * is to use {@link self::delete()}.
+     *
+     * @param int $contextid context ID.
+     * @param boolean $downloadcontents true to convert references to hard copies.
+     * @return void
+     */
+    final public static function delete_all_for_context($contextid, $downloadcontents = true) {
+        global $DB;
+        $repoids = $DB->get_fieldset_select('repository_instances', 'id', 'contextid = :contextid', array('contextid' => $contextid));
+        if ($downloadcontents) {
+            foreach ($repoids as $repoid) {
+                $repo = repository::get_repository_by_id($repoid, $contextid);
+                $repo->convert_references_to_local();
+            }
+        }
+        cache::make('core', 'repositories')->purge();
+        $DB->delete_records_list('repository_instances', 'id', $repoids);
+        $DB->delete_records_list('repository_instance_config', 'instanceid', $repoids);
+    }
+
     /**
      * Hide/Show a repository
      *
index 6061ccf..9b4c8ae 100644 (file)
@@ -460,4 +460,86 @@ class repositorylib_testcase extends advanced_testcase {
         $this->assertTrue($notprivaterepo->check_capability());
     }
 
+    function test_delete_all_for_context() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        $this->setAdminUser();
+        $course = $this->getDataGenerator()->create_course();
+        $user = $this->getDataGenerator()->create_user();
+        $this->getDataGenerator()->create_repository_type('flickr_public');
+        $this->getDataGenerator()->create_repository_type('filesystem');
+        $coursecontext = context_course::instance($course->id);
+        $usercontext = context_user::instance($user->id);
+
+        // Creating course instances.
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id));
+        $courserepo1 = repository::get_repository_by_id($repo->id, $coursecontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+
+        $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $coursecontext->id));
+        $courserepo2 = repository::get_repository_by_id($repo->id, $coursecontext);
+        $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+
+        // Creating user instances.
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id));
+        $userrepo1 = repository::get_repository_by_id($repo->id, $usercontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+
+        $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $usercontext->id));
+        $userrepo2 = repository::get_repository_by_id($repo->id, $usercontext);
+        $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+
+        // Simulation of course deletion.
+        repository::delete_all_for_context($coursecontext->id);
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo1->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo2->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo1->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo2->id)));
+
+        // Simulation of user deletion.
+        repository::delete_all_for_context($usercontext->id);
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo1->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo2->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo1->id)));
+        $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo2->id)));
+
+        // Checking deletion upon course context deletion.
+        $course = $this->getDataGenerator()->create_course();
+        $coursecontext = context_course::instance($course->id);
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id));
+        $courserepo = repository::get_repository_by_id($repo->id, $coursecontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+        $coursecontext->delete();
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+
+        // Checking deletion upon user context deletion.
+        $user = $this->getDataGenerator()->create_user();
+        $usercontext = context_user::instance($user->id);
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id));
+        $userrepo = repository::get_repository_by_id($repo->id, $usercontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+        $usercontext->delete();
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+
+        // Checking deletion upon course deletion.
+        $course = $this->getDataGenerator()->create_course();
+        $coursecontext = context_course::instance($course->id);
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id));
+        $courserepo = repository::get_repository_by_id($repo->id, $coursecontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+        delete_course($course, false);
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id)));
+
+        // Checking deletion upon user deletion.
+        $user = $this->getDataGenerator()->create_user();
+        $usercontext = context_user::instance($user->id);
+        $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id));
+        $userrepo = repository::get_repository_by_id($repo->id, $usercontext);
+        $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+        delete_user($user);
+        $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id)));
+    }
 }
index 46d8753..fd2dc57 100644 (file)
@@ -129,22 +129,41 @@ function useredit_shared_definition(&$mform, $editoroptions = null, $filemanager
 
     $strrequired = get_string('required');
 
-    $nameordercheck = new stdClass();
-    $nameordercheck->firstname = 'a';
-    $nameordercheck->lastname  = 'b';
-    if (fullname($nameordercheck) == 'b a' ) {  // See MDL-4325
-        $mform->addElement('text', 'lastname',  get_string('lastname'),  'maxlength="100" size="30"');
-        $mform->addElement('text', 'firstname', get_string('firstname'), 'maxlength="100" size="30"');
-    } else {
-        $mform->addElement('text', 'firstname', get_string('firstname'), 'maxlength="100" size="30"');
-        $mform->addElement('text', 'lastname',  get_string('lastname'),  'maxlength="100" size="30"');
+    $nameformat = $CFG->fullnamedisplay;
+    if ($nameformat == 'language') {
+        $nameformat = get_string('fullnamedisplay');
     }
 
-    $mform->addRule('firstname', $strrequired, 'required', null, 'client');
-    $mform->setType('firstname', PARAM_NOTAGS);
+    $necessarynames = array('firstname', 'lastname');
+    $enablednames = array_diff(get_all_user_name_fields(), $necessarynames);
+    // Get a list of all of the enabled names.
+    $enabledadditionalusernames = array();
+    foreach ($enablednames as $enabledname) {
+        if (strpos($CFG->fullnamedisplay, $enabledname) !== false) {
+            $enabledadditionalusernames[] = $enabledname;
+        }
+    }
+
+    $combinednames = array_merge($necessarynames, $enabledadditionalusernames);
+    $requirednames = order_in_string($combinednames, $nameformat);
+    foreach ($necessarynames as $necessaryname) {
+        if (!in_array($necessaryname, $requirednames)) {
+            $requirednames = order_in_string($combinednames, get_string('fullnamedisplay'));
+        }
+    }
+    foreach ($requirednames as $fullname) {
+        $mform->addElement('text', $fullname,  get_string($fullname),  'maxlength="100" size="30"');
+        $mform->setType($fullname, PARAM_NOTAGS);
+    }
 
+    $mform->addRule('firstname', $strrequired, 'required', null, 'client');
     $mform->addRule('lastname', $strrequired, 'required', null, 'client');
-    $mform->setType('lastname', PARAM_NOTAGS);
+
+    $morenames = array_diff($enabledadditionalusernames, $requirednames);
+    foreach ($morenames as $addname) {
+        $mform->addElement('text', $addname,  get_string($addname), 'maxlength="100" size="30"');
+        $mform->setType($addname, PARAM_NOTAGS);
+    }
 
     // Do not show email field if change confirmation is pending
     if (!empty($CFG->emailchangeconfirmation) and !empty($user->preference_newemail)) {
@@ -278,6 +297,18 @@ function useredit_shared_definition(&$mform, $editoroptions = null, $filemanager
 
     }
 
+    $alladditionalnames = array_diff(get_all_user_name_fields(), $necessarynames);
+    if (count($enabledadditionalusernames) < count($alladditionalnames)) {
+        $mform->addElement('header', 'moodle_additional_names', get_string('additionalnames'));
+        foreach ($alladditionalnames as $allname) {
+            if (!in_array($allname, $enabledadditionalusernames)) {
+                $mform->addElement('text', $allname, get_string($allname), 'maxlength="100" size="30"');
+                $mform->setType($allname, PARAM_NOTAGS);
+            }
+        }
+
+    }
+
     if (!empty($CFG->usetags) and empty($USER->newadminuser)) {
         $mform->addElement('header', 'moodle_interests', get_string('interests'));
         $mform->addElement('tags', 'interests', get_string('interestslist'), array('display' => 'noofficial'));
index e21ed8c..9f8f375 100644 (file)
@@ -51,21 +51,25 @@ class core_user_external extends external_api {
                 'users' => new external_multiple_structure(
                     new external_single_structure(
                         array(
-                            'username'    => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.'),
-                            'password'    => new external_value(PARAM_RAW, 'Plain text password consisting of any characters'),
-                            'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user'),
-                            'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user'),
-                            'email'       => new external_value(PARAM_EMAIL, 'A valid and unique email address'),
-                            'auth'        => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_DEFAULT, 'manual', NULL_NOT_ALLOWED),
-                            'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_DEFAULT, ''),
-                            'lang'        => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_DEFAULT, $CFG->lang, NULL_NOT_ALLOWED),
-                            'theme'       => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
-                            'timezone'    => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
-                            'mailformat'  => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
-                            'description' => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
-                            'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
-                            'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
-                            'preferences' => new external_multiple_structure(
+                            'username'            => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.'),
+                            'password'            => new external_value(PARAM_RAW, 'Plain text password consisting of any characters'),
+                            'firstname'           => new external_value(PARAM_NOTAGS, 'The first name(s) of the user'),
+                            'lastname'            => new external_value(PARAM_NOTAGS, 'The family name of the user'),
+                            'email'               => new external_value(PARAM_EMAIL, 'A valid and unique email address'),
+                            'auth'                => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_DEFAULT, 'manual', NULL_NOT_ALLOWED),
+                            'idnumber'            => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_DEFAULT, ''),
+                            'lang'                => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_DEFAULT, $CFG->lang, NULL_NOT_ALLOWED),
+                            'theme'               => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
+                            'timezone'            => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
+                            'mailformat'          => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
+                            'description'         => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
+                            'city'                => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
+                            'country'             => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
+                            'firstnamephonetic'   => new external_value(PARAM_NOTAGS, 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
+                            'lastnamephonetic'    => new external_value(PARAM_NOTAGS, 'The family name phonetically of the user', VALUE_OPTIONAL),
+                            'middlename'          => new external_value(PARAM_NOTAGS, 'The middle name of the user', VALUE_OPTIONAL),
+                            'alternatename'       => new external_value(PARAM_NOTAGS, 'The alternate name of the user', VALUE_OPTIONAL),
+                            'preferences'         => new external_multiple_structure(
                                 new external_single_structure(
                                     array(
                                         'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
@@ -276,21 +280,25 @@ class core_user_external extends external_api {
                     new external_single_structure(
                         array(
                             'id'    => new external_value(PARAM_INT, 'ID of the user'),
-                            'username'    => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
-                            'password'    => new external_value(PARAM_RAW, 'Plain text password consisting of any characters', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
-                            'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
-                            'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
-                            'email'       => new external_value(PARAM_EMAIL, 'A valid and unique email address', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
-                            'auth'        => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
-                            'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
-                            'lang'        => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
-                            'theme'       => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
-                            'timezone'    => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
-                            'mailformat'  => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
-                            'description' => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
-                            'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
-                            'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
-                            'customfields' => new external_multiple_structure(
+                            'username'            => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
+                            'password'            => new external_value(PARAM_RAW, 'Plain text password consisting of any characters', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
+                            'firstname'           => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
+                            'lastname'            => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
+                            'email'               => new external_value(PARAM_EMAIL, 'A valid and unique email address', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
+                            'auth'                => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
+                            'idnumber'            => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
+                            'lang'                => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
+                            'theme'               => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
+                            'timezone'            => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
+                            'mailformat'          => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
+                            'description'         => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
+                            'city'                => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
+                            'country'             => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
+                            'firstnamephonetic'   => new external_value(PARAM_NOTAGS, 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
+                            'lastnamephonetic'    => new external_value(PARAM_NOTAGS, 'The family name phonetically of the user', VALUE_OPTIONAL),
+                            'middlename'          => new external_value(PARAM_NOTAGS, 'The middle name of the user', VALUE_OPTIONAL),
+                            'alternatename'       => new external_value(PARAM_NOTAGS, 'The alternate name of the user', VALUE_OPTIONAL),
+                            'customfields'        => new external_multiple_structure(
                                 new external_single_structure(
                                     array(
                                         'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
index 59fa416..adf8a37 100644 (file)
             'id', 'username', 'firstname', 'lastname', 'email', 'city', 'country',
             'picture', 'lang', 'timezone', 'maildisplay', 'imagealt', 'lastaccess'));
 
+    $mainuserfields = user_picture::fields('u', array('username', 'email', 'city', 'country', 'lang', 'timezone', 'maildisplay'));
+
     if ($isfrontpage) {
-        $select = "SELECT u.id, u.username, u.firstname, u.lastname,
-                          u.email, u.city, u.country, u.picture,
-                          u.lang, u.timezone, u.maildisplay, u.imagealt,
-                          u.lastaccess$extrasql";
+        $select = "SELECT $mainuserfields, u.lastaccess$extrasql";
         $joins[] = "JOIN ($esql) e ON e.id = u.id"; // everybody on the frontpage usually
         if ($accesssince) {
             $wheres[] = get_user_lastaccess_sql($accesssince);
         }
 
     } else {
-        $select = "SELECT u.id, u.username, u.firstname, u.lastname,
-                          u.email, u.city, u.country, u.picture,
-                          u.lang, u.timezone, u.maildisplay, u.imagealt,
-                          COALESCE(ul.timeaccess, 0) AS lastaccess$extrasql";
+        $select = "SELECT $mainuserfields, COALESCE(ul.timeaccess, 0) AS lastaccess$extrasql";
         $joins[] = "JOIN ($esql) e ON e.id = u.id"; // course enrolled users only
         $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // not everybody accessed course yet
         $params['courseid'] = $course->id;
index 51f6291..6143521 100644 (file)
@@ -93,10 +93,12 @@ $count = 0;
 
 if ($data = data_submitted()) {
     require_sesskey();
+    $namefields = get_all_user_name_fields(true);
     foreach ($data as $k => $v) {
         if (preg_match('/^(user|teacher)(\d+)$/',$k,$m)) {
             if (!array_key_exists($m[2],$SESSION->emailto[$id])) {
-                if ($user = $DB->get_record_select('user', "id = ?", array($m[2]), 'id,firstname,lastname,idnumber,email,mailformat,lastaccess, lang, maildisplay')) {
+                if ($user = $DB->get_record_select('user', "id = ?", array($m[2]), 'id,
+                        ' . $namefields . ',idnumber,email,mailformat,lastaccess, lang, maildisplay')) {
                     $SESSION->emailto[$id][$m[2]] = $user;
                     $count++;
                 }
index 9692e3b..f64e687 100644 (file)
@@ -413,8 +413,9 @@ abstract class user_selector_base {
      */
     protected function required_fields_sql($u) {
         // Raw list of fields.
-        $fields = array('id', 'firstname', 'lastname');
-        $fields = array_merge($fields, $this->extrafields);
+        $fields = array('id');
+        // Add additional name fields
+        $fields = array_merge($fields, get_all_user_name_fields(), $this->extrafields);
 
         // Prepend the table alias.
         if ($u) {
index 42f080b..ae5cfdd 100644 (file)
@@ -457,6 +457,10 @@ class core_user_external_testcase extends externallib_advanced_testcase {
             'idnumber' => 'idnumbertest1',
             'firstname' => 'First Name User Test 1',
             'lastname' => 'Last Name User Test 1',
+            'middlename' => 'Middle Name User Test 1',
+            'lastnamephonetic' => '最後のお名前のテスト一号',
+            'firstnamephonetic' => 'お名前のテスト一号',
+            'alternatename' => 'Alternate Name User Test 1',
             'email' => 'usertest1@email.com',
             'description' => 'This is a description for user 1',
             'city' => 'Perth',
@@ -632,6 +636,10 @@ class core_user_external_testcase extends externallib_advanced_testcase {
             'idnumber' => 'idnumbertest1',
             'firstname' => 'First Name User Test 1',
             'lastname' => 'Last Name User Test 1',
+            'middlename' => 'Middle Name User Test 1',
+            'lastnamephonetic' => '最後のお名前のテスト一号',
+            'firstnamephonetic' => 'お名前のテスト一号',
+            'alternatename' => 'Alternate Name User Test 1',
             'email' => 'usertest1@email.com',
             'description' => 'This is a description for user 1',
             'city' => 'Perth',
index beef47c..37d042e 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2013062700.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2013070800.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.6dev (Build: 20130627)'; // Human-friendly version name
+$release  = '2.6dev (Build: 20130704)'; // Human-friendly version name
 
 $branch   = '26';                       // this version's branch
 $maturity = MATURITY_ALPHA;             // this version's maturity level
index 32a4602..a91fd59 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/amf/locallib.php");
 
index 896ff35..9a12c29 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/amf/locallib.php");
 
index b110cfe..0c34b9d 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/soap/locallib.php");
 
index e9e1bb6..26c5ddf 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/soap/locallib.php");
 
index bb07369..6e13b65 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/xmlrpc/locallib.php");
 
index ca8bbe1..27df839 100644 (file)
@@ -33,6 +33,15 @@ define('NO_DEBUG_DISPLAY', true);
  */
 define('NO_MOODLE_COOKIES', true);
 
+// Make sure OPcache does not strip comments, we need them for Zend!
+if (ini_get('opcache.enable') and strtolower(ini_get('opcache.enable')) !== 'off') {
+    if (!ini_get('opcache.save_comments') or strtolower(ini_get('opcache.save_comments')) === 'off') {
+        ini_set('opcache.enable', 0);
+    } else {
+        ini_set('opcache.load_comments', 1);
+    }
+}
+
 require('../../config.php');
 require_once("$CFG->dirroot/webservice/xmlrpc/locallib.php");