Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.7.x will end 11 May 2020 (12 months).
  • Bug fixes for security issues in 3.7.x will end 9 November 2020 (18 months) - Support has ended.
  • minimum PHP 7.1.0 Note: minimum PHP version has increased since Moodle 3.6. PHP 7.2.x and 7.3.x are supported too. PHP 7.x could have some engine limitations.
  • Differences Between: [Versions 35 and 37] [Versions 36 and 37]

       1  <?php
       2  
       3  // This file is part of Moodle - http://moodle.org/
       4  //
       5  // Moodle is free software: you can redistribute it and/or modify
       6  // it under the terms of the GNU General Public License as published by
       7  // the Free Software Foundation, either version 3 of the License, or
       8  // (at your option) any later version.
       9  //
      10  // Moodle is distributed in the hope that it will be useful,
      11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13  // GNU General Public License for more details.
      14  //
      15  // You should have received a copy of the GNU General Public License
      16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      17  
      18  require_once($CFG->libdir.'/gradelib.php');
      19  
      20  /**
      21   * Returns new improtcode for current user
      22   * @return int importcode
      23   */
      24  function get_new_importcode() {
      25      global $USER, $DB;
      26  
      27      $importcode = time();
      28      while ($DB->get_record('grade_import_values', array('importcode' => $importcode, 'importer' => $USER->id))) {
      29          $importcode--;
      30      }
      31  
      32      return $importcode;
      33  }
      34  
      35  /**
      36   * given an import code, commits all entries in buffer tables
      37   * (grade_import_value and grade_import_newitem)
      38   * If this function is called, we assume that all data collected
      39   * up to this point is fine and we can go ahead and commit
      40   * @param int $courseid - ID of the course.
      41   * @param int $importcode - Import batch identifier.
      42   * @param bool $importfeedback - Whether to import feedback as well.
      43   * @param bool $verbose - Print feedback and continue button.
      44   * @return bool success
      45   */
      46  function grade_import_commit($courseid, $importcode, $importfeedback=true, $verbose=true) {
      47      global $CFG, $USER, $DB, $OUTPUT;
      48  
      49      $failed = false;
      50      $executionerrors = false;
      51      $commitstart = time(); // start time in case we need to roll back
      52      $newitemids = array(); // array to hold new grade_item ids from grade_import_newitem table, mapping array
      53  
      54      /// first select distinct new grade_items with this batch
      55      $params = array($importcode, $USER->id);
      56      if ($newitems = $DB->get_records_sql("SELECT *
      57                                             FROM {grade_import_newitem}
      58                                            WHERE importcode = ? AND importer=?", $params)) {
      59  
      60          // instances of the new grade_items created, cached
      61          // in case grade_update fails, so that we can remove them
      62          $instances = array();
      63          foreach ($newitems as $newitem) {
      64              // get all grades with this item
      65  
      66              $gradeimportparams = array('newgradeitem' => $newitem->id, 'importcode' => $importcode, 'importer' => $USER->id);
      67              if ($grades = $DB->get_records('grade_import_values', $gradeimportparams)) {
      68                  /// create a new grade item for this - must use false as second param!
      69                  /// TODO: we need some bounds here too
      70                  $gradeitem = new grade_item(array('courseid'=>$courseid, 'itemtype'=>'manual', 'itemname'=>$newitem->itemname), false);
      71                  $gradeitem->insert('import');
      72                  $instances[] = $gradeitem;
      73  
      74                  // insert each individual grade to this new grade item
      75                  foreach ($grades as $grade) {
      76                      if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, 'import', $grade->feedback, FORMAT_MOODLE)) {
      77                          $failed = true;
      78                          break 2;
      79                      }
      80                  }
      81              }
      82          }
      83  
      84          if ($failed) {
      85              foreach ($instances as $instance) {
      86                  $gradeitem->delete('import');
      87              }
      88              import_cleanup($importcode);
      89              return false;
      90          }
      91      }
      92  
      93      /// then find all existing items
      94  
      95      if ($gradeitems = $DB->get_records_sql("SELECT DISTINCT (itemid)
      96                                               FROM {grade_import_values}
      97                                              WHERE importcode = ? AND importer=? AND itemid > 0",
      98                                              array($importcode, $USER->id))) {
      99  
     100          $modifieditems = array();
     101  
     102          foreach ($gradeitems as $itemid=>$notused) {
     103  
     104              if (!$gradeitem = new grade_item(array('id'=>$itemid))) {
     105                  // not supposed to happen, but just in case
     106                  import_cleanup($importcode);
     107                  return false;
     108              }
     109              // get all grades with this item
     110              $gradeimportparams = array('itemid' => $itemid, 'importcode' => $importcode, 'importer' => $USER->id);
     111              if ($grades = $DB->get_records('grade_import_values', $gradeimportparams)) {
     112  
     113                  // make the grades array for update_grade
     114                  foreach ($grades as $grade) {
     115                      if (!$importfeedback || $grade->feedback === null) {
     116                          $grade->feedback = false; // ignore it
     117                      }
     118                      if ($grade->importonlyfeedback) {
     119                          // False means do not change. See grade_itme::update_final_grade().
     120                          $grade->finalgrade = false;
     121                      }
     122                      if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, 'import', $grade->feedback)) {
     123                          $errordata = new stdClass();
     124                          $errordata->itemname = $gradeitem->itemname;
     125                          $errordata->userid = $grade->userid;
     126                          $executionerrors[] = get_string('errorsettinggrade', 'grades', $errordata);
     127                          $failed = true;
     128                          break 2;
     129                      }
     130                  }
     131                  //$itemdetails -> idnumber = $gradeitem->idnumber;
     132                  $modifieditems[] = $itemid;
     133  
     134              }
     135          }
     136  
     137          if ($failed) {
     138              if ($executionerrors && $verbose) {
     139                  echo $OUTPUT->notification(get_string('gradeimportfailed', 'grades'));
     140                  foreach ($executionerrors as $errorstr) {
     141                      echo $OUTPUT->notification($errorstr);
     142                  }
     143              }
     144              import_cleanup($importcode);
     145              return false;
     146          }
     147      }
     148  
     149      if ($verbose) {
     150          echo $OUTPUT->notification(get_string('importsuccess', 'grades'), 'notifysuccess');
     151          $unenrolledusers = get_unenrolled_users_in_import($importcode, $courseid);
     152          if ($unenrolledusers) {
     153              $list = array();
     154              foreach ($unenrolledusers as $u) {
     155                  $u->fullname = fullname($u);
     156                  $list[] = get_string('usergrade', 'grades', $u);
     157              }
     158              echo $OUTPUT->notification(get_string('unenrolledusersinimport', 'grades', html_writer::alist($list)), 'notifysuccess');
     159          }
     160          echo $OUTPUT->continue_button($CFG->wwwroot.'/grade/index.php?id='.$courseid);
     161      }
     162      // clean up
     163      import_cleanup($importcode);
     164  
     165      return true;
     166  }
     167  
     168  /**
     169   * This function returns an array of grades that were included in the import,
     170   * but where the user does not currently have a graded role on the course. These grades
     171   * are still stored in the database, but will not be visible in the gradebook unless
     172   * this user subsequently enrols on the course in a graded roles.
     173   *
     174   * The returned objects have fields user firstname, lastname and useridnumber, and gradeidnumber.
     175   *
     176   * @param integer $importcode import batch identifier
     177   * @param integer $courseid the course we are importing to.
     178   * @return mixed and array of user objects, or false if none.
     179   */
     180  function get_unenrolled_users_in_import($importcode, $courseid) {
     181      global $CFG, $DB;
     182  
     183      $coursecontext = context_course::instance($courseid);
     184  
     185      // We want to query both the current context and parent contexts.
     186      list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($coursecontext->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx');
     187  
     188      // Users with a gradeable role.
     189      list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr');
     190  
     191      // Enrolled users.
     192      $context = context_course::instance($courseid);
     193      list($enrolledsql, $enrolledparams) = get_enrolled_sql($context);
     194      list($sort, $sortparams) = users_order_by_sql('u');
     195  
     196      $sql = "SELECT giv.id, u.firstname, u.lastname, u.idnumber AS useridnumber,
     197                     COALESCE(gi.idnumber, gin.itemname) AS gradeidnumber
     198                FROM {grade_import_values} giv
     199                JOIN {user} u
     200                     ON giv.userid = u.id
     201                LEFT JOIN {grade_items} gi
     202                          ON gi.id = giv.itemid
     203                LEFT JOIN {grade_import_newitem} gin
     204                          ON gin.id = giv.newgradeitem
     205                LEFT JOIN ($enrolledsql) je
     206                          ON je.id = u.id
     207                LEFT JOIN {role_assignments} ra
     208                          ON (giv.userid = ra.userid AND ra.roleid $gradebookrolessql AND ra.contextid $relatedctxsql)
     209               WHERE giv.importcode = :importcode
     210                     AND (ra.id IS NULL OR je.id IS NULL)
     211            ORDER BY gradeidnumber, $sort";
     212      $params = array_merge($gradebookrolesparams, $enrolledparams, $sortparams, $relatedctxparams);
     213      $params['importcode'] = $importcode;
     214  
     215      return $DB->get_records_sql($sql, $params);
     216  }
     217  
     218  /**
     219   * removes entries from grade import buffer tables grade_import_value and grade_import_newitem
     220   * after a successful import, or during an import abort
     221   * @param string importcode - import batch identifier
     222   */
     223  function import_cleanup($importcode) {
     224      global $USER, $DB;
     225  
     226      // remove entries from buffer table
     227      $DB->delete_records('grade_import_values', array('importcode' => $importcode, 'importer' => $USER->id));
     228      $DB->delete_records('grade_import_newitem', array('importcode' => $importcode, 'importer' => $USER->id));
     229  }
     230  
     231