Merge branch 'MDL-26784-plugin-manager' of git://github.com/mudrd8mz/moodle
authorPetr Skoda <commits@skodak.org>
Mon, 4 Apr 2011 09:55:39 +0000 (11:55 +0200)
committerPetr Skoda <commits@skodak.org>
Mon, 4 Apr 2011 09:55:39 +0000 (11:55 +0200)
22 files changed:
admin/cli/install.php
admin/cli/install_database.php
admin/langimport.php
admin/report/profiling/settings.php
config-dist.php
grade/lib.php
grade/report/grader/lib.php
grade/report/user/lib.php
install.php
lang/en/admin.php
lib/componentlib.class.php
lib/dml/moodle_database.php
lib/dml/simpletest/testdml.php
lib/navigationlib.php
lib/setup.php
lib/simpletest/testcomponentlib.php
lib/tablelib.php
lib/upgradelib.php
lib/xhprof/readme_moodle.txt
lib/xhprof/xhprof_moodle.php
message/output/email/message_output_email.php
theme/boxxie/style/core.css

index fc643b5..1c37f54 100644 (file)
@@ -376,25 +376,16 @@ if ($interactive) {
     }
 }
 
-//download lang pack with optional notification
-if ($CFG->lang != 'en') {
-    if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $CFG->lang.'.zip', 'languages.md5', 'lang')) {
-        if ($cd->install() == COMPONENT_ERROR) {
-            if ($cd->get_error() == 'remotedownloaderror') {
-                $a = new stdClass();
-                $a->url  = 'http://download.moodle.org/langpack/2.0/'.$CFG->lang.'.zip';
-                $a->dest = $CFG->dataroot.'/lang';
-                cli_problem(get_string($cd->get_error(), 'error', $a));
-            } else {
-                cli_problem(get_string($cd->get_error(), 'error'));
-            }
-        } else {
-            // install parent lang if defined
-            if ($parentlang = get_parent_language()) {
-                if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
-                    $cd->install();
-                }
-            }
+// download required lang packs
+if ($CFG->lang !== 'en') {
+    $installer = new lang_installer($CFG->lang);
+    $results = $installer->run();
+    foreach ($results as $langcode => $langstatus) {
+        if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
+            $a       = new stdClass();
+            $a->url  = $installer->lang_pack_url($langcode);
+            $a->dest = $CFG->dataroot.'/lang';
+            cli_problem(get_string('remotedownloaderror', 'error', $a));
         }
     }
 }
index 17f6d59..ac58928 100644 (file)
@@ -121,26 +121,17 @@ if (!file_exists($CFG->dirroot.'/install/lang/'.$options['lang'])) {
 }
 $CFG->lang = $options['lang'];
 
-//download lang pack with optional notification
-if ($CFG->lang != 'en') {
+// download required lang packs
+if ($CFG->lang !== 'en') {
     make_upload_directory('lang');
-    if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $CFG->lang.'.zip', 'languages.md5', 'lang')) {
-        if ($cd->install() == COMPONENT_ERROR) {
-            if ($cd->get_error() == 'remotedownloaderror') {
-                $a = new stdClass();
-                $a->url  = 'http://download.moodle.org/langpack/2.0/'.$CFG->lang.'.zip';
-                $a->dest = $CFG->dataroot.'/lang';
-                cli_problem(get_string($cd->get_error(), 'error', $a));
-            } else {
-                cli_problem(get_string($cd->get_error(), 'error'));
-            }
-        } else {
-            // install parent lang if defined
-            if ($parentlang = get_parent_language()) {
-                if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
-                    $cd->install();
-                }
-            }
+    $installer = new lang_installer($CFG->lang);
+    $results = $installer->run();
+    foreach ($results as $langcode => $langstatus) {
+        if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
+            $a       = new stdClass();
+            $a->url  = $installer->lang_pack_url($langcode);
+            $a->dest = $CFG->dataroot.'/lang';
+            cli_problem(get_string('remotedownloaderror', 'error', $a));
         }
     }
 }
index 3ebb9de..4aa614b 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * Fetches language packages from download.moodle.org server
  *
- * Language packages are available at http://download.moodle.org/langpack/2.0/
+ * Language packages are available at http://download.moodle.org/langpack/
  * in ZIP format together with a file languages.md5 containing their hashes
  * and meta info.
  * Locally, language packs are saved into $CFG->dataroot/lang/
@@ -33,8 +33,6 @@ require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->libdir.'/filelib.php');
 require_once($CFG->libdir.'/componentlib.class.php');
 
-$thisversion = '2.0'; // TODO this information should be taken from version.php or similar source
-
 admin_externalpage_setup('langimport');
 
 if (!empty($CFG->skiplangupgrade)) {
@@ -63,41 +61,22 @@ if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($p
     make_upload_directory('temp');
     make_upload_directory('lang');
 
-    if (is_array($pack)) {
-        $packs = $pack;
-    } else {
-        $packs = array($pack);
-    }
-
-    foreach ($packs as $pack) {
-        if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
-            $status = $cd->install();
-            switch ($status) {
-            case COMPONENT_ERROR:
-                if ($cd->get_error() == 'remotedownloaderror') {
-                    $a = new stdClass();
-                    $a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
-                    $a->dest = $CFG->dataroot.'/lang';
-                    print_error($cd->get_error(), 'error', 'langimport.php', $a);
-                } else {
-                    print_error($cd->get_error(), 'error', 'langimport.php');
-                }
-                break;
-            case COMPONENT_INSTALLED:
-                $notice_ok[] = get_string('langpackinstalled','admin',$pack);
-                if ($parentlang = get_parent_language($pack)) {
-                    // install also parent pack if specified
-                    if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion,
-                            $parentlang.'.zip', 'languages.md5', 'lang')) {
-                        $cd->install();
-                    }
-                }
-                break;
-            case COMPONENT_UPTODATE:
-                break;
-            }
-        } else {
-            echo $OUTPUT->notification('Had an unspecified error with the component installer, sorry.');
+    $installer = new lang_installer($pack);
+    $results = $installer->run();
+    foreach ($results as $langcode => $langstatus) {
+        switch ($langstatus) {
+        case lang_installer::RESULT_DOWNLOADERROR:
+            $a       = new stdClass();
+            $a->url  = $installer->lang_pack_url($langcode);
+            $a->dest = $CFG->dataroot.'/lang';
+            print_error('remotedownloaderror', 'error', 'langimport.php', $a);
+            break;
+        case lang_installer::RESULT_INSTALLED:
+            $notice_ok[] = get_string('langpackinstalled', 'admin', $langcode);
+            break;
+        case lang_installer::RESULT_UPTODATE:
+            $notice_ok[] = get_string('langpackuptodate', 'admin', $langcode);
+            break;
         }
     }
 }
@@ -136,7 +115,9 @@ if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
 if ($mode == UPDATE_ALL_LANG) {
     set_time_limit(0);
 
-    if (!$availablelangs = get_remote_list_of_languages()) {
+    $installer = new lang_installer();
+
+    if (!$availablelangs = $installer->get_remote_list_of_languages()) {
         print_error('cannotdownloadlanguageupdatelist', 'error');
     }
     $md5array = array();    // (string)langcode => (string)md5
@@ -171,8 +152,8 @@ if ($mode == UPDATE_ALL_LANG) {
     make_upload_directory('temp');
     make_upload_directory('lang');
 
-    $updated = false;       // any packs updated?
-    foreach ($neededlangs as $pack) {
+    // clean-up currently installed versions of the packs
+    foreach ($neededlangs as $packindex => $pack) {
         if ($pack == 'en') {
             continue;
         }
@@ -185,41 +166,38 @@ if ($mode == UPDATE_ALL_LANG) {
         if (file_exists($dest1)) {
             if (!remove_dir($dest1)) {
                 $notice_error[] = 'Could not delete old directory '.$dest1.', update of '.$pack.' failed, please check permissions.';
+                unset($neededlangs[$packindex]);
                 continue;
             }
         }
         if (file_exists($dest2)) {
             if (!remove_dir($dest2)) {
                 $notice_error[] = 'Could not delete old directory '.$dest2.', update of '.$pack.' failed, please check permissions.';
+                unset($neededlangs[$packindex]);
                 continue;
             }
         }
+    }
 
-        // copy and unzip new version
-        if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
-        $status = $cd->install();
-        switch ($status) {
-
-            case COMPONENT_ERROR:
-                if ($cd->get_error() == 'remotedownloaderror') {
-                    $a = new stdClass();
-                    $a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
-                    $a->dest = $CFG->dataroot.'/lang';
-                    print_error($cd->get_error(), 'error', 'langimport.php', $a);
-                } else {
-                    print_error($cd->get_error(), 'error', 'langimport.php');
-                }
-                break;
-
-            case COMPONENT_UPTODATE:
-                // should not get here
-                break;
-
-            case COMPONENT_INSTALLED:
-                $notice_ok[] = get_string('langpackupdated', 'admin', $pack);
-                $updated = true;
-                break;
-            }
+    // install all needed language packs
+    $installer->set_queue($neededlangs);
+    $results = $installer->run();
+    $updated = false;    // any packs updated?
+    foreach ($results as $langcode => $langstatus) {
+        switch ($langstatus) {
+        case lang_installer::RESULT_DOWNLOADERROR:
+            $a       = new stdClass();
+            $a->url  = $installer->lang_pack_url($langcode);
+            $a->dest = $CFG->dataroot.'/lang';
+            print_error('remotedownloaderror', 'error', 'langimport.php', $a);
+            break;
+        case lang_installer::RESULT_INSTALLED:
+            $updated = true;
+            $notice_ok[] = get_string('langpackinstalled', 'admin', $langcode);
+            break;
+        case lang_installer::RESULT_UPTODATE:
+            $notice_ok[] = get_string('langpackuptodate', 'admin', $langcode);
+            break;
         }
     }
 
@@ -228,6 +206,8 @@ if ($mode == UPDATE_ALL_LANG) {
     } else {
         $notice_ok[] = get_string('nolangupdateneeded','admin');
     }
+
+    unset($installer);
 }
 get_string_manager()->reset_caches();
 
@@ -239,7 +219,7 @@ $installedlangs = get_string_manager()->get_list_of_translations(true);
 $missingparents = array();
 foreach ($installedlangs as $installedlang => $unused) {
     $parent = get_parent_language($installedlang);
-    if (empty($parent) or ($parent === 'en')) {
+    if (empty($parent)) {
         continue;
     }
     if (!isset($installedlangs[$parent])) {
@@ -247,7 +227,9 @@ foreach ($installedlangs as $installedlang => $unused) {
     }
 }
 
-if ($availablelangs = get_remote_list_of_languages()) {
+$installer = new lang_installer();
+
+if ($availablelangs = $installer->get_remote_list_of_languages()) {
     $remote = true;
 } else {
     $remote = false;
@@ -357,26 +339,3 @@ function is_installed_lang($lang, $md5check) {
     }
     return false;
 }
-
-/**
- * Returns the list of available language packs from download.moodle.org
- *
- * @return array|bool false if can not download
- */
-function get_remote_list_of_languages() {
-    $source = 'http://download.moodle.org/langpack/2.0/languages.md5';
-    $availablelangs = array();
-
-    if ($content = download_file_content($source)) {
-        $alllines = explode("\n", $content);
-        foreach($alllines as $line) {
-            if (!empty($line)){
-                $availablelangs[] = explode(',', $line);
-            }
-        }
-        return $availablelangs;
-
-    } else {
-        return false;
-    }
-}
index b7c724b..bf2dc5f 100644 (file)
@@ -3,6 +3,6 @@
 defined('MOODLE_INTERNAL') || die;
 
 // profiling report, added to development
-if (extension_loaded('xhprof') && function_exists('xhprof_enable') && !empty($CFG->profilingenabled)) {
+if (extension_loaded('xhprof') && function_exists('xhprof_enable') && (!empty($CFG->profilingenabled) || !empty($CFG->earlyprofilingenabled))) {
     $ADMIN->add('development', new admin_externalpage('reportprofiling', get_string('pluginname', 'report_profiling'), "$CFG->wwwroot/$CFG->admin/report/profiling/index.php", 'moodle/site:config'));
 }
index e5952af..61c4e20 100644 (file)
@@ -297,6 +297,13 @@ $CFG->admin = 'admin';
 //   Print to footer (works with the default theme)
 //   define('MDL_PERFTOFOOT', true);
 //
+//   Enable earlier profiling that causes more code to be covered
+//   on every request (db connections, config load, other inits...).
+//   Requires extra configuration to be defined in config.php like:
+//   profilingincluded, profilingexcluded, profilingautofrec,
+//   profilingallowme, profilingallowall, profilinglifetime
+//       $CFG->earlyprofilingenabled = true;
+//
 // Force displayed usernames
 //   A little hack to anonymise user names for all students.  If you set these
 //   then all non-teachers will always see these for every person.
index 848408a..b8651a9 100644 (file)
@@ -85,10 +85,16 @@ class graded_users_iterator {
             return false;
         }
 
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id);
+        $relatedcontexts = get_related_contexts_string($coursecontext);
+
         list($gradebookroles_sql, $params) =
             $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
 
-        $relatedcontexts = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $this->course->id));
+        //limit to users with an active enrolment
+        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext);
+
+        $params = array_merge($params, $enrolledparams);
 
         if ($this->groupid) {
             $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id";
@@ -123,31 +129,39 @@ class graded_users_iterator {
         // $params contents: gradebookroles and groupid (for $groupwheresql)
         $users_sql = "SELECT u.* $ofields
                         FROM {user} u
-                             INNER JOIN {role_assignments} ra ON u.id = ra.userid
+                        JOIN ($enrolledsql) je ON je.id = u.id
                              $groupsql
-                       WHERE u.deleted=0
-                             AND ra.roleid $gradebookroles_sql
-                             AND ra.contextid $relatedcontexts
+                        JOIN (
+                                  SELECT DISTINCT ra.userid
+                                    FROM {role_assignments} ra
+                                   WHERE ra.roleid $gradebookroles_sql
+                                     AND ra.contextid $relatedcontexts
+                             ) rainner ON rainner.userid = u.id
+                         WHERE u.deleted = 0
                              $groupwheresql
                     ORDER BY $order";
-
         $this->users_rs = $DB->get_recordset_sql($users_sql, $params);
 
         if (!empty($this->grade_items)) {
             $itemids = array_keys($this->grade_items);
             list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items0');
             $params = array_merge($params, $grades_params);
+            // $params contents: gradebookroles, enrolledparams, groupid (for $groupwheresql) and itemids
 
-            // $params contents: gradebookroles, groupid (for $groupwheresql) and itemids
             $grades_sql = "SELECT g.* $ofields
                              FROM {grade_grades} g
-                                  INNER JOIN {user} u ON g.userid = u.id
-                                  INNER JOIN {role_assignments} ra ON u.id = ra.userid
+                             JOIN {user} u ON g.userid = u.id
+                             JOIN ($enrolledsql) je ON je.id = u.id
                                   $groupsql
-                            WHERE ra.roleid $gradebookroles_sql
-                                  AND ra.contextid $relatedcontexts
-                                  $groupwheresql
-                                  AND g.itemid $itemidsql
+                             JOIN (
+                                      SELECT DISTINCT ra.userid
+                                        FROM {role_assignments} ra
+                                       WHERE ra.roleid $gradebookroles_sql
+                                         AND ra.contextid $relatedcontexts
+                                  ) rainnner ON rainner.userid = u.id
+                              WHERE u.deleted = 0
+                              AND g.itemid $itemidsql
+                              $groupwheresql
                          ORDER BY $order, g.itemid ASC";
             $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params);
         } else {
index d76d679..4b5d23b 100644 (file)
@@ -342,55 +342,47 @@ class grade_report_grader extends grade_report {
         //fields we need from the user table
         $userfields = user_picture::fields('u', array('idnumber'));
 
+        $sortjoin = $sort = $params = null;
+
         //if the user has clicked one of the sort asc/desc arrows
         if (is_numeric($this->sortitemid)) {
             $params = array_merge(array('gitemid'=>$this->sortitemid), $gradebookrolesparams, $this->groupwheresql_params, $enrolledparams);
-            // the MAX() magic is required in order to please PG
-            $sort = "MAX(g.finalgrade) $this->sortorder";
 
-            $sql = "SELECT $userfields
-                      FROM {user} u
-                      JOIN ($enrolledsql) je
-                           ON je.id = u.id
-                      JOIN {role_assignments} ra
-                           ON ra.userid = u.id
-                      $this->groupsql
-                      LEFT JOIN {grade_grades} g
-                                ON (g.userid = u.id AND g.itemid = :gitemid)
-                     WHERE ra.roleid $gradebookrolessql
-                           AND u.deleted = 0
-                           AND ra.contextid ".get_related_contexts_string($this->context)."
-                           $this->groupwheresql
-                  GROUP BY $userfields
-                  ORDER BY $sort";
+            $sortjoin = "LEFT JOIN {grade_grades} g ON g.userid = u.id AND g.itemid = $this->sortitemid";
+            $sort = "g.finalgrade $this->sortorder";
 
         } else {
+            $sortjoin = '';
             switch($this->sortitemid) {
                 case 'lastname':
-                    $sort = "u.lastname $this->sortorder, u.firstname $this->sortorder"; break;
+                    $sort = "u.lastname $this->sortorder, u.firstname $this->sortorder";
+                    break;
                 case 'firstname':
-                    $sort = "u.firstname $this->sortorder, u.lastname $this->sortorder"; break;
+                    $sort = "u.firstname $this->sortorder, u.lastname $this->sortorder";
+                    break;
                 case 'idnumber':
                 default:
-                    $sort = "u.idnumber $this->sortorder"; break;
+                    $sort = "u.idnumber $this->sortorder";
+                    break;
             }
 
             $params = array_merge($gradebookrolesparams, $this->groupwheresql_params, $enrolledparams);
-
-            $sql = "SELECT DISTINCT $userfields
-                      FROM {user} u
-                      JOIN ($enrolledsql) je
-                           ON je.id = u.id
-                      JOIN {role_assignments} ra
-                           ON u.id = ra.userid
-                           $this->groupsql
-                     WHERE ra.roleid $gradebookrolessql
-                           AND u.deleted = 0
-                           AND ra.contextid ".get_related_contexts_string($this->context)."
-                           $this->groupwheresql
-                  ORDER BY $sort";
         }
 
+        $sql = "SELECT $userfields
+                  FROM {user} u
+                  JOIN ($enrolledsql) je ON je.id = u.id
+                       $this->groupsql
+                       $sortjoin
+                  JOIN (
+                           SELECT DISTINCT ra.userid
+                             FROM {role_assignments} ra
+                            WHERE ra.roleid IN ($this->gradebookroles)
+                              AND ra.contextid " . get_related_contexts_string($this->context) . "
+                       ) rainner ON rainner.userid = u.id
+                   AND u.deleted = 0
+                   $this->groupwheresql
+              ORDER BY $sort";
 
         $this->users = $DB->get_records_sql($sql, $params, $this->get_pref('studentsperpage') * $this->page, $this->get_pref('studentsperpage'));
 
@@ -1294,25 +1286,25 @@ class grade_report_grader extends grade_report {
             $params = array_merge(array('courseid'=>$this->courseid), $gradebookrolesparams, $enrolledparams, $groupwheresqlparams);
 
             // find sums of all grade items in course
-            $SQL = "SELECT g.itemid, SUM(g.finalgrade) AS sum
+            $sql = "SELECT g.itemid, SUM(g.finalgrade) AS sum
                       FROM {grade_items} gi
-                      JOIN {grade_grades} g
-                           ON g.itemid = gi.id
-                      JOIN {user} u
-                           ON u.id = g.userid
-                      JOIN ($enrolledsql) je
-                           ON je.id = u.id
-                      JOIN {role_assignments} ra
-                           ON ra.userid = u.id
+                      JOIN {grade_grades} g ON g.itemid = gi.id
+                      JOIN {user} u ON u.id = g.userid
+                      JOIN ($enrolledsql) je ON je.id = u.id
+                      JOIN (
+                               SELECT DISTINCT ra.userid
+                                 FROM {role_assignments} ra
+                                WHERE ra.roleid $gradebookrolessql
+                                  AND ra.contextid " . get_related_contexts_string($this->context) . "
+                           ) rainner ON rainner.userid = u.id
                       $groupsql
                      WHERE gi.courseid = :courseid
-                           AND ra.roleid $gradebookrolessql
-                           AND ra.contextid ".get_related_contexts_string($this->context)."
-                           AND g.finalgrade IS NOT NULL
-                           $groupwheresql
-                  GROUP BY g.itemid";
+                       AND u.deleted = 0
+                       AND g.finalgrade IS NOT NULL
+                       $groupwheresql
+                     GROUP BY g.itemid";
             $sumarray = array();
-            if ($sums = $DB->get_records_sql($SQL, $params)) {
+            if ($sums = $DB->get_records_sql($sql, $params)) {
                 foreach ($sums as $itemid => $csum) {
                     $sumarray[$itemid] = $csum->sum;
                 }
@@ -1320,7 +1312,7 @@ class grade_report_grader extends grade_report {
 
             // MDL-10875 Empty grades must be evaluated as grademin, NOT always 0
             // This query returns a count of ungraded grades (NULL finalgrade OR no matching record in grade_grades table)
-            $SQL = "SELECT gi.id, COUNT(u.id) AS count
+            $sql = "SELECT gi.id, COUNT(DISTINCT u.id) AS count
                       FROM {grade_items} gi
                       CROSS JOIN {user} u
                       JOIN ($enrolledsql) je
@@ -1333,11 +1325,12 @@ class grade_report_grader extends grade_report {
                      WHERE gi.courseid = :courseid
                            AND ra.roleid $gradebookrolessql
                            AND ra.contextid ".get_related_contexts_string($this->context)."
+                           AND u.deleted = 0
                            AND g.id IS NULL
                            $groupwheresql
                   GROUP BY gi.id";
 
-            $ungradedcounts = $DB->get_records_sql($SQL, $params);
+            $ungradedcounts = $DB->get_records_sql($sql, $params);
 
             $avgrow = new html_table_row();
             $avgrow->attributes['class'] = 'avg';
index 7a84094..22791e1 100644 (file)
@@ -618,19 +618,21 @@ class grade_report_user extends grade_report {
             // find sums of all grade items in course
             $sql = "SELECT gg.itemid, SUM(gg.finalgrade) AS sum
                       FROM {grade_items} gi
-                      JOIN {grade_grades} gg
-                           ON gg.itemid = gi.id
-                      JOIN ($enrolledsql) je
-                           ON je.id = gg.userid
-                      JOIN {role_assignments} ra
-                           ON ra.userid = gg.userid
+                      JOIN {grade_grades} gg ON gg.itemid = gi.id
+                      JOIN {user} u ON u.id = gg.userid
+                      JOIN ($enrolledsql) je ON je.id = gg.userid
+                      JOIN (
+                                   SELECT DISTINCT ra.userid
+                                     FROM {role_assignments} ra
+                                    WHERE ra.roleid $gradebookrolessql
+                                      AND ra.contextid " . get_related_contexts_string($this->context) . "
+                           ) rainner ON rainner.userid = u.id
                       $groupsql
                      WHERE gi.courseid = :courseid
-                           AND ra.roleid $gradebookrolessql
-                           AND ra.contextid ".get_related_contexts_string($this->context)."
-                           AND gg.finalgrade IS NOT NULL
-                           AND gg.hidden = 0
-                           $groupwheresql
+                       AND u.deleted = 0
+                       AND gg.finalgrade IS NOT NULL
+                       AND gg.hidden = 0
+                       $groupwheresql
                   GROUP BY gg.itemid";
 
             $sum_array = array();
@@ -649,19 +651,21 @@ class grade_report_user extends grade_report {
             $sql = "SELECT gi.id, COUNT(u.id) AS count
                       FROM {grade_items} gi
                       JOIN {user} u
-                      JOIN ($enrolledsql) je
-                           ON je.id = u.id
-                      JOIN {role_assignments} ra
-                           ON ra.userid = u.id
+                      JOIN ($enrolledsql) je ON je.id = u.id
+                      JOIN (
+                               SELECT DISTINCT ra.userid
+                                 FROM {role_assignments} ra
+                                WHERE ra.roleid $gradebookrolessql
+                                  AND ra.contextid " . get_related_contexts_string($this->context) . "
+                           ) rainner ON rainner.userid = u.id
                       LEFT JOIN {grade_grades} gg
                            ON (gg.itemid = gi.id AND gg.userid = u.id AND gg.finalgrade IS NOT NULL AND gg.hidden = 0)
                       $groupsql
-                    WHERE gi.courseid = :courseid
-                          AND ra.roleid $gradebookrolessql
-                          AND ra.contextid ".get_related_contexts_string($this->context)."
-                          AND gg.finalgrade IS NULL
-                          $groupwheresql
-                    GROUP BY gi.id";
+                     WHERE gi.courseid = :courseid
+                           AND u.deleted = 0
+                           AND gg.finalgrade IS NULL
+                           $groupwheresql
+                  GROUP BY gi.id";
 
             $ungraded_counts = $DB->get_records_sql($sql, $params);
 
index 4a4896a..b615587 100644 (file)
@@ -354,24 +354,15 @@ if ($config->stage == INSTALL_DATABASETYPE) {
 if ($config->stage == INSTALL_DOWNLOADLANG) {
     $downloaderror = '';
 
-// Download and install lang component, lang dir was already created in install_init_dataroot
-    if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $CFG->lang.'.zip', 'languages.md5', 'lang')) {
-        if ($cd->install() == COMPONENT_ERROR) {
-            if ($cd->get_error() == 'remotedownloaderror') {
-                $a = new stdClass();
-                $a->url  = 'http://download.moodle.org/langpack/2.0/'.$config->lang.'.zip';
-                $a->dest = $CFG->dataroot.'/lang';
-                $downloaderror = get_string($cd->get_error(), 'error', $a);
-            } else {
-                $downloaderror = get_string($cd->get_error(), 'error');
-            }
-        } else {
-            // install parent lang if defined
-            if ($parentlang = get_parent_language()) {
-                if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
-                    $cd->install();
-                }
-            }
+    // download and install required lang packs, the lang dir has already been created in install_init_dataroot
+    $installer = new lang_installer($CFG->lang);
+    $results = $installer->run();
+    foreach ($results as $langcode => $langstatus) {
+        if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
+            $a       = new stdClass();
+            $a->url  = $installer->lang_pack_url($langcode);
+            $a->dest = $CFG->dataroot.'/lang';
+            $downloaderror = get_string('remotedownloaderror', 'error', $a);
         }
     }
 
index b503267..9db50c3 100644 (file)
@@ -648,6 +648,7 @@ $string['langpackremoved'] = 'Language pack was uninstalled';
 $string['langpacks'] = 'Language packs';
 $string['langpackupdated'] = 'Language pack {$a} was successfully updated';
 $string['langpackupdateskipped'] = 'Update of {$a} language pack skipped';
+$string['langpackuptodate'] = 'Language pack {$a} is up-to-date';
 $string['langpackwillbeupdated'] = 'NOTE: Moodle will try to download updates for your language packs during the upgrade.';
 $string['langrmyourself'] = 'To prevent data loss, lang.php is not able to overwrite existing file with empty content. Please, remove the file manually in order to get rid of it.';
 $string['langstringcache'] = 'Cache all language strings';
index b064161..39209bc 100644 (file)
@@ -549,3 +549,267 @@ class component_installer {
     }
 
 } /// End of component_installer class
+
+
+/**
+ * Language packs installer
+ *
+ * This class wraps the functionality provided by {@link component_installer}
+ * and adds support for installing a set of language packs.
+ *
+ * Given an array of required language packs, this class fetches them all
+ * and installs them. It detects eventual dependencies and installs
+ * all parent languages, too.
+ *
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class lang_installer {
+
+    /** lang pack was successfully downloaded and deployed */
+    const RESULT_INSTALLED      = 'installed';
+    /** lang pack was up-to-date so no download was needed */
+    const RESULT_UPTODATE       = 'uptodate';
+    /** there was a problem with downloading the lang pack */
+    const RESULT_DOWNLOADERROR  = 'downloaderror';
+
+    /** @var array of languages to install */
+    protected $queue = array();
+    /** @var string the code of language being currently installed */
+    protected $current;
+    /** @var array of languages already installed by this instance */
+    protected $done = array();
+    /** @var string this Moodle major version */
+    protected $version;
+
+    /**
+     * Prepare the installer
+     *
+     * @todo Moodle major version is hardcoded here, should be obtained from version.php or so
+     * @param string|array $langcode a code of the language to install
+     */
+    public function __construct($langcode = '') {
+        global $CFG;
+
+        $this->set_queue($langcode);
+        $this->version = '2.0';
+
+        if (!empty($CFG->langotherroot) and $CFG->langotherroot !== $CFG->dataroot . '/lang') {
+            debugging('The in-built language pack installer does not support alternative location ' .
+                'of languages root directory. You are supposed to install and update your language '.
+                'packs on your own.');
+        }
+    }
+
+    /**
+     * Sets the queue of language packs to be installed
+     *
+     * @param string|array $langcodes language code like 'cs' or a list of them
+     */
+    public function set_queue($langcodes) {
+        if (is_array($langcodes)) {
+            $this->queue = $langcodes;
+        } else if (!empty($langcodes)) {
+            $this->queue = array($langcodes);
+        }
+    }
+
+    /**
+     * Runs the installer
+     *
+     * This method calls {@link self::install_language_pack} for every language in the
+     * queue. If a dependency is detected, the parent language is added to the queue.
+     *
+     * @return array results, array of self::RESULT_xxx constants indexed by language code
+     */
+    public function run() {
+
+        $results = array();
+
+        while ($this->current = array_shift($this->queue)) {
+
+            if ($this->was_processed($this->current)) {
+                // do not repeat yourself
+                continue;
+            }
+
+            if ($this->current === 'en') {
+                $this->mark_processed($this->current);
+                continue;
+            }
+
+            $results[$this->current] = $this->install_language_pack($this->current);
+
+            if (in_array($results[$this->current], array(self::RESULT_INSTALLED, self::RESULT_UPTODATE))) {
+                if ($parentlang = $this->get_parent_language($this->current)) {
+                    if (!$this->is_queued($parentlang) and !$this->was_processed($parentlang)) {
+                        $this->add_to_queue($parentlang);
+                    }
+                }
+            }
+
+            $this->mark_processed($this->current);
+        }
+
+        return $results;
+    }
+
+    /**
+     * Returns the URL where a given language pack can be downloaded
+     *
+     * Alternatively, if the parameter is empty, returns URL of the page with the
+     * list of all available language packs.
+     *
+     * @param string $langcode language code like 'cs' or empty for unknown
+     * @return string URL
+     */
+    public function lang_pack_url($langcode = '') {
+
+        $baseurl = 'http://download.moodle.org/langpack/' . $this->version . '/';
+
+        if (empty($langcode)) {
+            return $baseurl;
+        } else {
+            return $baseurl . $langcode . '.zip';
+        }
+    }
+
+    /**
+     * Returns the list of available language packs from download.moodle.org
+     *
+     * @return array|bool false if can not download
+     */
+    public function get_remote_list_of_languages() {
+        $source = 'http://download.moodle.org/langpack/' . $this->version . '/languages.md5';
+        $availablelangs = array();
+
+        if ($content = download_file_content($source)) {
+            $alllines = explode("\n", $content);
+            foreach($alllines as $line) {
+                if (!empty($line)){
+                    $availablelangs[] = explode(',', $line);
+                }
+            }
+            return $availablelangs;
+
+        } else {
+            return false;
+        }
+    }
+
+    // Internal implementation /////////////////////////////////////////////////
+
+    /**
+     * Adds a language pack (or a list of them) to the queue
+     *
+     * @param string|array $langcodes code of the language to install or a list of them
+     */
+    protected function add_to_queue($langcodes) {
+        if (is_array($langcodes)) {
+            $this->queue = array_merge($this->queue, $langcodes);
+        } else if (!empty($langcodes)) {
+            $this->queue[] = $langcodes;
+        }
+    }
+
+    /**
+     * Checks if the given language is queued or if the queue is empty
+     *
+     * @example $installer->is_queued('es');    // is Spanish going to be installed?
+     * @example $installer->is_queued();        // is there a language queued?
+     *
+     * @param string $langcode language code or empty string for "any"
+     * @return boolean
+     */
+    protected function is_queued($langcode = '') {
+
+        if (empty($langcode)) {
+            return !empty($this->queue);
+
+        } else {
+            return in_array($langcode, $this->queue);
+        }
+    }
+
+    /**
+     * Checks if the given language has already been processed by this instance
+     *
+     * @see self::mark_processed()
+     * @param string $langcode
+     * @return boolean
+     */
+    protected function was_processed($langcode) {
+        return isset($this->done[$langcode]);
+    }
+
+    /**
+     * Mark the given language pack as processed
+     *
+     * @see self::was_processed()
+     * @param string $langcode
+     */
+    protected function mark_processed($langcode) {
+        $this->done[$langcode] = 1;
+    }
+
+    /**
+     * Returns a parent language of the given installed language
+     *
+     * @param string $langcode
+     * @return string parent language's code
+     */
+    protected function get_parent_language($langcode) {
+        return get_parent_language($langcode);
+    }
+
+    /**
+     * Perform the actual language pack installation
+     *
+     * @uses component_installer
+     * @param string $langcode
+     * @return int return status
+     */
+    protected function install_language_pack($langcode) {
+
+        // initialise new component installer to process this language
+        $installer = new component_installer('http://download.moodle.org', 'langpack/' . $this->version,
+            $langcode . '.zip', 'languages.md5', 'lang');
+
+        if (!$installer->requisitesok) {
+            throw new lang_installer_exception('installer_requisites_check_failed');
+        }
+
+        $status = $installer->install();
+
+        if ($status == COMPONENT_ERROR) {
+            if ($installer->get_error() === 'remotedownloaderror') {
+                return self::RESULT_DOWNLOADERROR;
+            } else {
+                throw new lang_installer_exception($installer->get_error(), $langcode);
+            }
+
+        } else if ($status == COMPONENT_UPTODATE) {
+            return self::RESULT_UPTODATE;
+
+        } else if ($status == COMPONENT_INSTALLED) {
+            return self::RESULT_INSTALLED;
+
+        } else {
+            throw new lang_installer_exception('unexpected_installer_result', $status);
+        }
+    }
+}
+
+
+/**
+ * Exception thrown by {@link lang_installer}
+ *
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class lang_installer_exception extends moodle_exception {
+
+    public function __construct($errorcode, $debuginfo = null) {
+        parent::__construct($errorcode, 'error', '', null, $debuginfo);
+    }
+}
index 2d6b2be..b647ca9 100644 (file)
@@ -569,12 +569,25 @@ abstract class moodle_database {
      * @param int $type bound param type SQL_PARAMS_QM or SQL_PARAMS_NAMED
      * @param string named param placeholder start
      * @param bool true means equal, false not equal
+     * @param mixed $onemptyitems defines the behavior when the array of items is empty. Defaults to false,
+     *              meaning throw exceptions. Other values will become part of the returned SQL fragment.
      * @return array - $sql and $params
      */
-    public function get_in_or_equal($items, $type=SQL_PARAMS_QM, $start='param0000', $equal=true) {
-        if (is_array($items) and empty($items)) {
+    public function get_in_or_equal($items, $type=SQL_PARAMS_QM, $start='param0000', $equal=true, $onemptyitems=false) {
+        // default behavior, throw exception on empty array
+        if (is_array($items) and empty($items) and $onemptyitems === false) {
             throw new coding_exception('moodle_database::get_in_or_equal() does not accept empty arrays');
         }
+        // handle $onemptyitems on empty array of items
+        if (is_array($items) and empty($items)) {
+            if (is_null($onemptyitems)) {             // Special case, NULL value
+                $sql = $equal ? ' IS NULL' : ' IS NOT NULL';
+                return (array($sql, array()));
+            } else {
+                $items = array($onemptyitems);        // Rest of cases, prepare $items for std processing
+            }
+        }
+
         if ($type == SQL_PARAMS_QM) {
             if (!is_array($items) or count($items) == 1) {
                 $sql = $equal ? '= ?' : '<> ?';
index 6a71f4e..f574bcd 100644 (file)
@@ -223,11 +223,81 @@ class dml_test extends UnitTestCase {
 
         // Correct usage of single value
         $in_value = 'value1';
-        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
+        list($usql, $params) = $DB->get_in_or_equal($in_value, SQL_PARAMS_NAMED, 'param01', false);
         $this->assertEqual("<> :param01", $usql);
         $this->assertEqual(1, count($params));
         $this->assertEqual($in_value, $params['param01']);
 
+        // Some incorrect tests
+
+        // Incorrect usage passing not-allowed params type
+        $in_values = array(1, 2, 3);
+        try {
+            list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_DOLLAR, 'param01', false);
+            $this->fail('An Exception is missing, expected due to not supported SQL_PARAMS_DOLLAR');
+        } catch (exception $e) {
+            $this->assertTrue($e instanceof dml_exception);
+            $this->assertEqual($e->errorcode, 'typenotimplement');
+        }
+
+        // Incorrect usage passing empty array
+        $in_values = array();
+        try {
+            list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
+            $this->fail('An Exception is missing, expected due to empty array of items');
+        } catch (exception $e) {
+            $this->assertTrue($e instanceof coding_exception);
+        }
+
+        // Test using $onemptyitems
+
+        // Correct usage passing empty array and $onemptyitems = NULL (equal = true, QM)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param01', true, NULL);
+        $this->assertEqual(' IS NULL', $usql);
+        $this->assertIdentical(array(), $params);
+
+        // Correct usage passing empty array and $onemptyitems = NULL (equal = false, NAMED)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false, NULL);
+        $this->assertEqual(' IS NOT NULL', $usql);
+        $this->assertIdentical(array(), $params);
+
+        // Correct usage passing empty array and $onemptyitems = true (equal = true, QM)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param01', true, true);
+        $this->assertEqual('= ?', $usql);
+        $this->assertIdentical(array(true), $params);
+
+        // Correct usage passing empty array and $onemptyitems = true (equal = false, NAMED)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false, true);
+        $this->assertEqual('<> :param01', $usql);
+        $this->assertIdentical(array('param01' => true), $params);
+
+        // Correct usage passing empty array and $onemptyitems = -1 (equal = true, QM)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param01', true, -1);
+        $this->assertEqual('= ?', $usql);
+        $this->assertIdentical(array(-1), $params);
+
+        // Correct usage passing empty array and $onemptyitems = -1 (equal = false, NAMED)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false, -1);
+        $this->assertEqual('<> :param01', $usql);
+        $this->assertIdentical(array('param01' => -1), $params);
+
+        // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = true, QM)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param01', true, 'onevalue');
+        $this->assertEqual('= ?', $usql);
+        $this->assertIdentical(array('onevalue'), $params);
+
+        // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = false, NAMED)
+        $in_values = array();
+        list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false, 'onevalue');
+        $this->assertEqual('<> :param01', $usql);
+        $this->assertIdentical(array('param01' => 'onevalue'), $params);
     }
 
     public function test_fix_table_names() {
index 6824ee6..4434d7c 100644 (file)
@@ -1653,8 +1653,8 @@ class global_navigation extends navigation_node {
             $usernode->add(get_string('messages', 'message'), $url, self::TYPE_SETTING, null, 'messages');
         }
 
-        // TODO: Private file capability check
-        if ($iscurrentuser) {
+        $context = get_context_instance(CONTEXT_USER, $USER->id);
+        if ($iscurrentuser && has_capability('moodle/user:manageownfiles', $context)) {
             $url = new moodle_url('/user/files.php');
             $usernode->add(get_string('myfiles'), $url, self::TYPE_SETTING);
         }
index de6f9ff..5c8bcac 100644 (file)
@@ -228,6 +228,14 @@ if (!defined('MOODLE_INTERNAL')) { // necessary because cli installer has to def
     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');
+    if (profiling_start()) {
+        register_shutdown_function('profiling_stop');
+    }
+}
+
 /**
  * Database connection. Used for all access to the database.
  * @global moodle_database $DB
@@ -669,11 +677,12 @@ session_get_instance();
 $SESSION = &$_SESSION['SESSION'];
 $USER    = &$_SESSION['USER'];
 
-// include and start profiling if needed, and register profiling_stop as shutdown function
+// Late profiling, only happening if early one wasn't started
 if (!empty($CFG->profilingenabled)) {
     require_once($CFG->libdir . '/xhprof/xhprof_moodle.php');
-    profiling_start();
-    register_shutdown_function('profiling_stop');
+    if (profiling_start()) {
+        register_shutdown_function('profiling_stop');
+    }
 }
 
 // Process theme change in the URL.
index a5918fc..13d1543 100644 (file)
@@ -58,6 +58,121 @@ class componentlib_test extends UnitTestCase {
         //check if correct files were downloaded
         $this->assertEqual('2af180e813dc3f446a9bb7b6af87ce24', md5_file($destpath.'/'.'test.jpg'));
         $this->assertEqual('47250a973d1b88d9445f94db4ef2c97a', md5_file($destpath.'/'.'test.html'));
+    }
+
+    /**
+     * Test the public API of the {@link lang_installer} class
+     */
+    public function test_lang_installer() {
+
+        // test the manipulation with the download queue
+        $installer = new testable_lang_installer();
+        $this->assertFalse($installer->protected_is_queued());
+        $installer->protected_add_to_queue('cs');
+        $installer->protected_add_to_queue(array('cs', 'sk'));
+        $this->assertTrue($installer->protected_is_queued());
+        $this->assertTrue($installer->protected_is_queued('cs'));
+        $this->assertTrue($installer->protected_is_queued('sk'));
+        $this->assertFalse($installer->protected_is_queued('de_kids'));
+        $installer->set_queue('de_kids');
+        $this->assertFalse($installer->protected_is_queued('cs'));
+        $this->assertFalse($installer->protected_is_queued('sk'));
+        $this->assertFalse($installer->protected_is_queued('de'));
+        $this->assertFalse($installer->protected_is_queued('de_du'));
+        $this->assertTrue($installer->protected_is_queued('de_kids'));
+        $installer->set_queue(array('cs', 'de_kids'));
+        $this->assertTrue($installer->protected_is_queued('cs'));
+        $this->assertFalse($installer->protected_is_queued('sk'));
+        $this->assertFalse($installer->protected_is_queued('de'));
+        $this->assertFalse($installer->protected_is_queued('de_du'));
+        $this->assertTrue($installer->protected_is_queued('de_kids'));
+        $installer->set_queue(array());
+        $this->assertFalse($installer->protected_is_queued());
+        unset($installer);
+
+        // install a set of lang packs
+        $installer = new testable_lang_installer(array('cs', 'de_kids', 'xx'));
+        $result = $installer->run();
+        $this->assertEqual($result['cs'], lang_installer::RESULT_UPTODATE);
+        $this->assertEqual($result['de_kids'], lang_installer::RESULT_INSTALLED);
+        $this->assertEqual($result['xx'], lang_installer::RESULT_DOWNLOADERROR);
+        // the following two were automatically added to the queue
+        $this->assertEqual($result['de_du'], lang_installer::RESULT_INSTALLED);
+        $this->assertEqual($result['de'], lang_installer::RESULT_UPTODATE);
+
+        // exception throwing
+        $installer = new testable_lang_installer(array('yy'));
+        $this->expectException('lang_installer_exception');
+        $installer->run();
+    }
+}
+
+/**
+ * Testable lang_installer subclass that does not actually install anything
+ * and provides access to the protected methods of the parent class
+ *
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class testable_lang_installer extends lang_installer {
+
+    /**
+     * @see parent::is_queued()
+     */
+    public function protected_is_queued($langcode = '') {
+        return $this->is_queued($langcode);
+    }
+
+    /**
+     * @see parent::add_to_queue()
+     */
+    public function protected_add_to_queue($langcodes) {
+        return $this->add_to_queue($langcodes);
+    }
+
+    /**
+     * Simulate lang pack installation via component_installer
+     *
+     * Language packages 'de_du' and 'de_kids' reported as installed
+     * Language packages 'cs' and 'de' reported as up-to-date
+     * Language package 'xx' returns download error
+     * All other language packages will throw an unknown exception
+     *
+     * @see parent::install_language_pack()
+     */
+    protected function install_language_pack($langcode) {
+
+        switch ($langcode) {
+        case 'de_du':
+        case 'de_kids':
+            return self::RESULT_INSTALLED;
+
+        case 'cs':
+        case 'de':
+            return self::RESULT_UPTODATE;
+
+        case 'xx':
+            return self::RESULT_DOWNLOADERROR;
+
+        default:
+            throw new lang_installer_exception('testing-unknown-exception', $langcode);
+        }
+    }
+
+    /**
+     * Simulate detection of parent languge
+     *
+     * @see parent::get_parent_language()
+     */
+    protected function get_parent_language($langcode) {
 
+        switch ($langcode) {
+        case 'de_kids':
+            return 'de_du';
+        case 'de_du':
+            return 'de';
+        default:
+            return '';
+        }
     }
 }
index e3d905d..efceb9c 100644 (file)
@@ -1346,6 +1346,7 @@ class table_sql extends flexible_table {
         if (!$this->is_downloading()) {
             if ($this->countsql === NULL) {
                 $this->countsql = 'SELECT COUNT(1) FROM '.$this->sql->from.' WHERE '.$this->sql->where;
+                $this->countparams = $this->sql->params;
             }
             if ($useinitialsbar && !$this->is_downloading()) {
                 $totalinitials = $DB->count_records_sql($this->countsql, $this->countparams);
index e0ba25c..a526068 100644 (file)
@@ -1259,11 +1259,10 @@ function upgrade_init_javascript() {
     $PAGE->requires->js_init_code($js);
 }
 
-
 /**
  * Try to upgrade the given language pack (or current language)
  *
- * @todo hardcoded Moodle version here - shall be provided by version.php or similar script
+ * @param string $lang the code of the language to update, defaults to the current language
  */
 function upgrade_language_pack($lang='') {
     global $CFG, $OUTPUT;
@@ -1286,16 +1285,19 @@ function upgrade_language_pack($lang='') {
 
     require_once($CFG->libdir.'/componentlib.class.php');
 
-    if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $lang.'.zip', 'languages.md5', 'lang')) {
-        $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
-
-        if ($status == COMPONENT_INSTALLED) {
-            if ($parentlang = get_parent_language($lang)) {
-                if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
-                    $cd->install();
-                }
-            }
-            echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
+    $installer = new lang_installer($pack);
+    $results = $installer->run();
+    foreach ($results as $langcode => $langstatus) {
+        switch ($langstatus) {
+        case lang_installer::RESULT_DOWNLOADERROR:
+            echo $OUTPUT->notification($pack . '.zip');
+            break;
+        case lang_installer::RESULT_INSTALLED:
+            echo $OUTPUT->notification(get_string('langpackinstalled', 'admin', $langcode), 'notifysuccess');
+            break;
+        case lang_installer::RESULT_UPTODATE:
+            echo $OUTPUT->notification(get_string('langpackuptodate', 'admin', $langcode), 'notifysuccess');
+            break;
         }
     }
 
index c75c3d4..6168abd 100644 (file)
@@ -25,9 +25,6 @@ TODO:
  * export/import profiling runs: Allow to pick any profile record, encapsulate
        it into some serialized/encoded way and allow download/upload. It requires
        DB changes in order to be able to specify the source of each record (own/imported).
- * move profiling start to earlier place: detect if all the needed $CFG->profilingXXX variables
-       have been defined in config.php file and if that condition is fullfilled, start profiling
-       @ the very first lines of setup.php (as early as possible).
  * improvements to the listing mode: various commodity details like:
        - allow to filter by various criteria
        - inline (and ajax) editing of reference/comment and deleting
@@ -38,4 +35,5 @@ TODO:
        - cpu times
        (all them are right now enabled for everybody by default)
 
-20101122 - Eloy Lafuente (stronk7): Original import of 0.9.2 release
+20101122 - MDL-24600 - Eloy Lafuente (stronk7): Original import of 0.9.2 release
+20110318 - MDL-26891 - Eloy Lafuente (stronk7): Implemented earlier profiling runs
index 26958c8..b268c32 100644 (file)
@@ -69,7 +69,7 @@ function profiling_start() {
     }
 
     // If profiling isn't enabled, nothing to start
-    if (!$CFG->profilingenabled) {
+    if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) {
         return false;
     }
 
@@ -78,19 +78,22 @@ function profiling_start() {
         return false;
     }
 
+    // Set script (from global if available, else our own)
+    $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script();
+
     // Get PGC variables
     $check = 'PROFILEME';
     $profileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
-    $profileme = $profileme && $CFG->profilingallowme;
+    $profileme = $profileme && !empty($CFG->profilingallowme);
     $check = 'DONTPROFILEME';
     $dontprofileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
-    $dontprofileme = $dontprofileme && $CFG->profilingallowme;
+    $dontprofileme = $dontprofileme && !empty($CFG->profilingallowme);
     $check = 'PROFILEALL';
     $profileall = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
-    $profileall = $profileall && $CFG->profilingallowall;
+    $profileall = $profileall && !empty($CFG->profilingallowall);
     $check = 'PROFILEALLSTOP';
     $profileallstop = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
-    $profileallstop = $profileallstop && $CFG->profilingallowall;
+    $profileallstop = $profileallstop && !empty($CFG->profilingallowall);
 
     // DONTPROFILEME detected, nothing to start
     if ($dontprofileme) {
@@ -98,12 +101,12 @@ function profiling_start() {
     }
 
     // PROFILEALLSTOP detected, clean the mark in seesion and continue
-    if ($profileallstop) {
+    if ($profileallstop && !empty($SESSION)) {
         unset($SESSION->profileall);
     }
 
     // PROFILEALL detected, set the mark in session and continue
-    if ($profileall) {
+    if ($profileall && !empty($SESSION)) {
         $SESSION->profileall = true;
 
     // SESSION->profileall detected, set $profileall
@@ -113,21 +116,23 @@ function profiling_start() {
 
     // Evaluate automatic (random) profiling if necessary
     $profileauto = false;
-    if ($CFG->profilingautofrec) {
+    if (!empty($CFG->profilingautofrec)) {
         $profileauto = (mt_rand(1, $CFG->profilingautofrec) === 1);
     }
 
-    // See if the $SCRIPT matches any of the included patterns
-    $profileincluded = profiling_string_matches($SCRIPT, $CFG->profilingincluded);
+    // See if the $script matches any of the included patterns
+    $included = empty($CFG->profilingincluded) ? '' : $CFG->profilingincluded;
+    $profileincluded = profiling_string_matches($script, $included);
 
-    // See if the $SCRIPT matches any of the excluded patterns
-    $profileexcluded = profiling_string_matches($SCRIPT, $CFG->profilingexcluded);
+    // See if the $script matches any of the excluded patterns
+    $excluded = empty($CFG->profilingexcluded) ? '' : $CFG->profilingexcluded;
+    $profileexcluded = profiling_string_matches($script, $excluded);
 
     // Decide if profile auto must happen (observe matchings)
     $profileauto = $profileauto && $profileincluded && !$profileexcluded;
 
     // Decide if profile by match must happen (only if profileauto is disabled)
-    $profilematch = $profileincluded && !$profileexcluded && !$CFG->profilingautofrec;
+    $profilematch = $profileincluded && !$profileexcluded && empty($CFG->profilingautofrec);
 
     // If not auto, me, all, match have been detected, nothing to do
     if (!$profileauto && !$profileme && !$profileall && !$profilematch) {
@@ -138,6 +143,9 @@ function profiling_start() {
     $ignore = array('call_user_func', 'call_user_func_array');
     xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY, array('ignored_functions' =>  $ignore));
     profiling_is_running(true);
+
+    // Started, return true
+    return true;
 }
 
 /**
@@ -152,7 +160,7 @@ function profiling_stop() {
     }
 
     // If profiling isn't enabled, nothing to stop
-    if (!$CFG->profilingenabled) {
+    if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) {
         return false;
     }
 
@@ -161,17 +169,23 @@ function profiling_stop() {
         return false;
     }
 
+    // Set script (from global if available, else our own)
+    $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script();
+
     // Arrived here, profiling is running, stop and save everything
     profiling_is_running(false);
     $data = xhprof_disable();
 
     $run = new moodle_xhprofrun();
-    $run->prepare_run($SCRIPT);
+    $run->prepare_run($script);
     $runid = $run->save_run($data, null);
     profiling_is_saved(true);
 
     // Prune old runs
     profiling_prune_old_runs($runid);
+
+    // Finished, return true
+    return true;
 }
 
 function profiling_prune_old_runs($exception = 0) {
@@ -190,6 +204,34 @@ function profiling_prune_old_runs($exception = 0) {
                                              runid != :exception', $params);
 }
 
+/**
+ * Returns the path to the php script being requested
+ *
+ * Note this function is a partial copy of initialise_fullme() and
+ * setup_get_remote_url(), in charge of setting $FULLME, $SCRIPT and
+ * friends. To be used by early profiling runs in situations where
+ * $SCRIPT isn't defined yet
+ *
+ * @return string absolute path (wwwroot based) of the script being executed
+ */
+function profiling_get_script() {
+    global $CFG;
+
+    $wwwroot = parse_url($CFG->wwwroot);
+
+    if (!isset($wwwroot['path'])) {
+        $wwwroot['path'] = '';
+    }
+    $wwwroot['path'] .= '/';
+
+    $path = $_SERVER['SCRIPT_NAME'];
+
+    if (strpos($path, $wwwroot['path']) === 0) {
+        return substr($path, strlen($wwwroot['path']) - 1);
+    }
+    return '';
+}
+
 function profiling_urls($report, $runid, $runid2 = null) {
     global $CFG;
 
index dff4874..0445fbe 100644 (file)
@@ -46,18 +46,8 @@ class message_output_email extends message_output {
             return true;
         }
 
-        //hold onto email preference because /admin/cron.php sends a lot of messages at once
-        static $useremailaddresses = array();
-
         //check user preference for where user wants email sent
-        if (!array_key_exists($eventdata->userto->id, $useremailaddresses)) {
-            $useremailaddresses[$eventdata->userto->id] = get_user_preferences('message_processor_email_email', $eventdata->userto->email, $eventdata->userto->id);
-        }
-        $usertoemailaddress = $useremailaddresses[$eventdata->userto->id];
-
-        if ( !empty($usertoemailaddress)) {
-            $userto->email = $usertoemailaddress;
-        }
+        $eventdata->userto->email = get_user_preferences('message_processor_email_email', $eventdata->userto->email, $eventdata->userto->id);
 
         $result = email_to_user($eventdata->userto, $eventdata->userfrom,
             $eventdata->subject, $eventdata->fullmessage, $eventdata->fullmessagehtml);
index 19770e4..448e676 100644 (file)
@@ -7,6 +7,7 @@ body {
     margin: 10px 5%;
     background: #5b7439;
     padding: 5px;
+    min-width: 930px; /* fixes minimum page width */
 }
 
 #page {
@@ -16,6 +17,10 @@ body {
     
 }
 
+#page-content {
+       min-width: inherit;
+}
+
 a:link,
 a:visited {
     color: #69804e;