Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

       1  <?php
       2  // This file is part of Moodle - http://moodle.org/
       3  //
       4  // Moodle is free software: you can redistribute it and/or modify
       5  // it under the terms of the GNU General Public License as published by
       6  // the Free Software Foundation, either version 3 of the License, or
       7  // (at your option) any later version.
       8  //
       9  // Moodle is distributed in the hope that it will be useful,
      10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12  // GNU General Public License for more details.
      13  //
      14  // You should have received a copy of the GNU General Public License
      15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      16  
      17  /**
      18   * Page for editing questions.
      19   *
      20   * @package    moodlecore
      21   * @subpackage questionbank
      22   * @copyright  1999 onwards Martin Dougiamas {@link http://moodle.com}
      23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      24   */
      25  
      26  
      27  require_once(dirname(__FILE__) . '/../config.php');
      28  require_once(dirname(__FILE__) . '/editlib.php');
      29  require_once($CFG->libdir . '/filelib.php');
      30  require_once($CFG->libdir . '/formslib.php');
      31  
      32  // Read URL parameters telling us which question to edit.
      33  $id = optional_param('id', 0, PARAM_INT); // question id
      34  $makecopy = optional_param('makecopy', 0, PARAM_BOOL);
      35  $qtype = optional_param('qtype', '', PARAM_FILE);
      36  $categoryid = optional_param('category', 0, PARAM_INT);
      37  $cmid = optional_param('cmid', 0, PARAM_INT);
      38  $courseid = optional_param('courseid', 0, PARAM_INT);
      39  $wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
      40  $originalreturnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
      41  $appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
      42  $inpopup = optional_param('inpopup', 0, PARAM_BOOL);
      43  $scrollpos = optional_param('scrollpos', 0, PARAM_INT);
      44  
      45  $url = new moodle_url('/question/question.php');
      46  if ($id !== 0) {
      47      $url->param('id', $id);
      48  }
      49  if ($makecopy) {
      50      $url->param('makecopy', $makecopy);
      51  }
      52  if ($qtype !== '') {
      53      $url->param('qtype', $qtype);
      54  }
      55  if ($categoryid !== 0) {
      56      $url->param('category', $categoryid);
      57  }
      58  if ($cmid !== 0) {
      59      $url->param('cmid', $cmid);
      60  }
      61  if ($courseid !== 0) {
      62      $url->param('courseid', $courseid);
      63  }
      64  if ($wizardnow !== '') {
      65      $url->param('wizardnow', $wizardnow);
      66  }
      67  if ($originalreturnurl !== 0) {
      68      $url->param('returnurl', $originalreturnurl);
      69  }
      70  if ($appendqnumstring !== '') {
      71      $url->param('appendqnumstring', $appendqnumstring);
      72  }
      73  if ($inpopup !== 0) {
      74      $url->param('inpopup', $inpopup);
      75  }
      76  if ($scrollpos) {
      77      $url->param('scrollpos', $scrollpos);
      78  }
      79  $PAGE->set_url($url);
      80  
      81  if ($cmid) {
      82      $questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
      83  } else {
      84      $questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
      85  }
      86  navigation_node::override_active_url($questionbankurl);
      87  
      88  if ($originalreturnurl) {
      89      if (strpos($originalreturnurl, '/') !== 0) {
      90          throw new coding_exception("returnurl must be a local URL starting with '/'. $originalreturnurl was given.");
      91      }
      92      $returnurl = new moodle_url($originalreturnurl);
      93  } else {
      94      $returnurl = $questionbankurl;
      95  }
      96  if ($scrollpos) {
      97      $returnurl->param('scrollpos', $scrollpos);
      98  }
      99  
     100  if ($cmid){
     101      list($module, $cm) = get_module_from_cmid($cmid);
     102      require_login($cm->course, false, $cm);
     103      $thiscontext = context_module::instance($cmid);
     104  } elseif ($courseid) {
     105      require_login($courseid, false);
     106      $thiscontext = context_course::instance($courseid);
     107      $module = null;
     108      $cm = null;
     109  } else {
     110      print_error('missingcourseorcmid', 'question');
     111  }
     112  $contexts = new question_edit_contexts($thiscontext);
     113  $PAGE->set_pagelayout('admin');
     114  
     115  if (optional_param('addcancel', false, PARAM_BOOL)) {
     116      redirect($returnurl);
     117  }
     118  
     119  if ($id) {
     120      if (!$question = $DB->get_record('question', array('id' => $id))) {
     121          print_error('questiondoesnotexist', 'question', $returnurl);
     122      }
     123      get_question_options($question, true);
     124  
     125  } else if ($categoryid && $qtype) { // only for creating new questions
     126      $question = new stdClass();
     127      $question->category = $categoryid;
     128      $question->qtype = $qtype;
     129      $question->createdby = $USER->id;
     130  
     131      // Check that users are allowed to create this question type at the moment.
     132      if (!question_bank::qtype_enabled($qtype)) {
     133          print_error('cannotenable', 'question', $returnurl, $qtype);
     134      }
     135  
     136  } else if ($categoryid) {
     137      // Category, but no qtype. They probably came from the addquestion.php
     138      // script without choosing a question type. Send them back.
     139      $addurl = new moodle_url('/question/addquestion.php', $url->params());
     140      $addurl->param('validationerror', 1);
     141      redirect($addurl);
     142  
     143  } else {
     144      print_error('notenoughdatatoeditaquestion', 'question', $returnurl);
     145  }
     146  
     147  $qtypeobj = question_bank::get_qtype($question->qtype);
     148  
     149  // Validate the question category.
     150  if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
     151      print_error('categorydoesnotexist', 'question', $returnurl);
     152  }
     153  
     154  // Check permissions
     155  $question->formoptions = new stdClass();
     156  
     157  $categorycontext = context::instance_by_id($category->contextid);
     158  $addpermission = has_capability('moodle/question:add', $categorycontext);
     159  
     160  if ($id) {
     161      $question->formoptions->canedit = question_has_capability_on($question, 'edit');
     162      $question->formoptions->canmove = $addpermission && question_has_capability_on($question, 'move');
     163      $question->formoptions->cansaveasnew = $addpermission &&
     164              (question_has_capability_on($question, 'view') || $question->formoptions->canedit);
     165      $question->formoptions->repeatelements = $question->formoptions->canedit || $question->formoptions->cansaveasnew;
     166      $formeditable =  $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove;
     167      if (!$formeditable) {
     168          question_require_capability_on($question, 'view');
     169      }
     170      if ($makecopy) {
     171          // If we are duplicating a question, add some indication to the question name.
     172          $question->name = get_string('questionnamecopy', 'question', $question->name);
     173          $question->beingcopied = true;
     174      }
     175  
     176  } else  { // creating a new question
     177      $question->formoptions->canedit = question_has_capability_on($question, 'edit');
     178      $question->formoptions->canmove = (question_has_capability_on($question, 'move') && $addpermission);
     179      $question->formoptions->cansaveasnew = false;
     180      $question->formoptions->repeatelements = true;
     181      $formeditable = true;
     182      require_capability('moodle/question:add', $categorycontext);
     183  }
     184  $question->formoptions->mustbeusable = (bool) $appendqnumstring;
     185  
     186  // Validate the question type.
     187  $PAGE->set_pagetype('question-type-' . $question->qtype);
     188  
     189  // Create the question editing form.
     190  if ($wizardnow !== '') {
     191      $mform = $qtypeobj->next_wizard_form('question.php', $question, $wizardnow, $formeditable);
     192  } else {
     193      $mform = $qtypeobj->create_editing_form('question.php', $question, $category, $contexts, $formeditable);
     194  }
     195  $toform = fullclone($question); // send the question object and a few more parameters to the form
     196  $toform->category = "{$category->id},{$category->contextid}";
     197  $toform->scrollpos = $scrollpos;
     198  if ($formeditable && $id){
     199      $toform->categorymoveto = $toform->category;
     200  }
     201  
     202  $toform->appendqnumstring = $appendqnumstring;
     203  $toform->returnurl = $originalreturnurl;
     204  $toform->makecopy = $makecopy;
     205  if ($cm !== null){
     206      $toform->cmid = $cm->id;
     207      $toform->courseid = $cm->course;
     208  } else {
     209      $toform->courseid = $COURSE->id;
     210  }
     211  
     212  $toform->inpopup = $inpopup;
     213  
     214  $mform->set_data($toform);
     215  
     216  if ($mform->is_cancelled()) {
     217      if ($inpopup) {
     218          close_window();
     219      } else {
     220          redirect($returnurl);
     221      }
     222  
     223  } else if ($fromform = $mform->get_data()) {
     224      // If we are saving as a copy, break the connection to the old question.
     225      if ($makecopy) {
     226          $question->id = 0;
     227          $question->hidden = 0; // Copies should not be hidden.
     228      }
     229  
     230      /// Process the combination of usecurrentcat, categorymoveto and category form
     231      /// fields, so the save_question method only has to consider $fromform->category
     232      if (!empty($fromform->usecurrentcat)) {
     233          // $fromform->category is the right category to save in.
     234      } else {
     235          if (!empty($fromform->categorymoveto)) {
     236              $fromform->category = $fromform->categorymoveto;
     237          } else {
     238              // $fromform->category is the right category to save in.
     239          }
     240      }
     241  
     242      /// If we are moving a question, check we have permission to move it from
     243      /// whence it came. (Where we are moving to is validated by the form.)
     244      list($newcatid, $newcontextid) = explode(',', $fromform->category);
     245      if (!empty($question->id) && $newcatid != $question->category) {
     246          $contextid = $newcontextid;
     247          question_require_capability_on($question, 'move');
     248      } else {
     249          $contextid = $category->contextid;
     250      }
     251  
     252      // Ensure we redirect back to the category the question is being saved into.
     253      $returnurl->param('category', $fromform->category);
     254  
     255      // We are acutally saving the question.
     256      if (!empty($question->id)) {
     257          question_require_capability_on($question, 'edit');
     258      } else {
     259          require_capability('moodle/question:add', context::instance_by_id($contextid));
     260          if (!empty($fromform->makecopy) && !$question->formoptions->cansaveasnew) {
     261              print_error('nopermissions', '', '', 'edit');
     262          }
     263      }
     264      $question = $qtypeobj->save_question($question, $fromform);
     265      if (!empty($CFG->usetags) && isset($fromform->tags)) {
     266          // A wizardpage from multipe pages questiontype like calculated may not
     267          // allow editing the question tags, hence the isset($fromform->tags) test.
     268          require_once($CFG->dirroot.'/tag/lib.php');
     269          tag_set('question', $question->id, $fromform->tags, 'core_question', $contextid);
     270      }
     271  
     272      // Purge this question from the cache.
     273      question_bank::notify_question_edited($question->id);
     274  
     275      // If we are saving and continuing to edit the question.
     276      if (!empty($fromform->updatebutton)) {
     277          $url->param('id', $question->id);
     278          $url->remove_params('makecopy');
     279          redirect($url);
     280      }
     281  
     282      if ($qtypeobj->finished_edit_wizard($fromform)) {
     283          if ($inpopup) {
     284              echo $OUTPUT->notification(get_string('changessaved'), '');
     285              close_window(3);
     286          } else {
     287              $returnurl->param('lastchanged', $question->id);
     288              if ($appendqnumstring) {
     289                  $returnurl->param($appendqnumstring, $question->id);
     290                  $returnurl->param('sesskey', sesskey());
     291                  $returnurl->param('cmid', $cmid);
     292              }
     293              redirect($returnurl);
     294          }
     295  
     296      } else {
     297          $nexturlparams = array(
     298                  'returnurl' => $originalreturnurl,
     299                  'appendqnumstring' => $appendqnumstring,
     300                  'scrollpos' => $scrollpos);
     301          if (isset($fromform->nextpageparam) && is_array($fromform->nextpageparam)){
     302              //useful for passing data to the next page which is not saved in the database.
     303              $nexturlparams += $fromform->nextpageparam;
     304          }
     305          $nexturlparams['id'] = $question->id;
     306          $nexturlparams['wizardnow'] = $fromform->wizard;
     307          $nexturl = new moodle_url('/question/question.php', $nexturlparams);
     308          if ($cmid){
     309              $nexturl->param('cmid', $cmid);
     310          } else {
     311              $nexturl->param('courseid', $COURSE->id);
     312          }
     313          redirect($nexturl);
     314      }
     315  
     316  }
     317  
     318  $streditingquestion = $qtypeobj->get_heading();
     319  $PAGE->set_title($streditingquestion);
     320  $PAGE->set_heading($COURSE->fullname);
     321  $PAGE->navbar->add($streditingquestion);
     322  
     323  // Display a heading, question editing form and possibly some extra content needed for
     324  // for this question type.
     325  echo $OUTPUT->header();
     326  $qtypeobj->display_question_editing_page($mform, $question, $wizardnow);
     327  echo $OUTPUT->footer();
    

    Search This Site: