diff --git a/lib/questionlib.php b/lib/questionlib.php index 389270109f2..30e043303aa 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -120,16 +120,6 @@ define('QUESTION_PREVIEW_POPUP_OPTIONS', 'scrollbars=yes&resizable=yes&width=700 define('QUESTION_ADAPTIVE', 1); /**#@-*/ -/**#@+ - * Options used in forms that move files. - */ -define('QUESTION_FILENOTHINGSELECTED', 0); -define('QUESTION_FILEDONOTHING', 1); -define('QUESTION_FILECOPY', 2); -define('QUESTION_FILEMOVE', 3); -define('QUESTION_FILEMOVELINKSONLY', 4); -/**#@-*/ - /**#@+ * Options for whether flags are shown/editable when rendering questions. */ @@ -718,7 +708,7 @@ function question_delete_course_category($category, $newcategory, $feedback=true // added to a course, and then that course is moved to another category (MDL-14802). $questionids = $DB->get_records_menu('question', array('category'=>$category->id), '', 'id,1'); if (!empty($questionids)) { - if (!$rescueqcategory = question_save_from_deletion(implode(',', array_keys($questionids)), + if (!$rescueqcategory = question_save_from_deletion(array_keys($questionids), get_parent_contextid($context), print_context_name($context), $rescueqcategory)) { return false; } @@ -854,32 +844,57 @@ function question_delete_activity($cm, $feedback=true) { function question_move_questions_to_category($questionids, $newcategoryid) { global $DB, $QTYPES; - $ids = explode(',', $questionids); - foreach ($ids as $questionid) { - $questionid = (int)$questionid; - $params = array(); - $params[] = $questionid; - $sql = 'SELECT q.*, c.id AS contextid, c.contextlevel, c.instanceid, c.path, c.depth - FROM {question} q, {question_categories} qc, {context} c - WHERE q.category=qc.id AND q.id=? AND qc.contextid=c.id'; - $question = $DB->get_record_sql($sql, $params); - $category = $DB->get_record('question_categories', array('id'=>$newcategoryid)); - // process files - $QTYPES[$question->qtype]->move_files($question, $category); + $newcontextid = $DB->get_field('question_categories', 'contextid', + array('id' => $newcategoryid)); + list($questionidcondition, $params) = $DB->get_in_or_equal($questionids); + $questions = $DB->get_records_sql(" + SELECT q.id, q.qtype, qc.contextid + FROM {question} q + JOIN {question_categories} qc ON q.category = qc.id + WHERE q.id $questionidcondition", $params); + foreach ($questions as $question) { + if ($newcontextid != $question->contextid) { + $QTYPES[$question->qtype]->move_files($question->id, + $question->contextid, $newcontextid); + } } - // Move the questions themselves. - $DB->set_field_select('question', 'category', $newcategoryid, "id IN ($questionids)"); + $DB->set_field_select('question', 'category', $newcategoryid, "id $questionidcondition", $params); // Move any subquestions belonging to them. - $DB->set_field_select('question', 'category', $newcategoryid, "parent IN ($questionids)"); + $DB->set_field_select('question', 'category', $newcategoryid, "parent $questionidcondition", $params); // TODO Deal with datasets. return true; } +/** + * This function helps move a question cateogry to a new context by moving all + * the files belonging to all the questions to the new context. + * Also moves subcategories. + * @param integer $categoryid the id of the category being moved. + * @param integer $oldcontextid the old context id. + * @param integer $newcontextid the new context id. + */ +function question_move_category_to_context($categoryid, $oldcontextid, $newcontextid) { + global $DB, $QTYPES; + + $questionids = $DB->get_records_menu('question', + array('category' => $categoryid), '', 'id,qtype'); + foreach ($questionids as $questionid => $qtype) { + $QTYPES[$qtype]->move_files($questionid, $oldcontextid, $newcontextid); + } + + $subcatids = $DB->get_records_menu('question_categories', + array('parent' => $categoryid), '', 'id,1'); + foreach ($subcatids as $subcatid => $notused) { + $DB->set_field('question_categories', 'contextid', $newcontextid, array('id' => $subcatid)); + question_move_category_to_context($subcatid, $oldcontextid, $newcontextid); + } +} + /** * Given a list of ids, load the basic information about a set of questions from the questions table. * The $join and $extrafields arguments can be used together to pull in extra data. @@ -1850,37 +1865,11 @@ function print_question_icon($question, $return = false) { } /** -* Returns a html link to the question image if there is one -* - * @global object - * @global object -* @return string The html image tag or the empy string if there is no image. -* @param object $question The question object -*/ -function get_question_image($question) { - global $CFG, $DB; - $img = ''; - - if (!$category = $DB->get_record('question_categories', array('id'=>$question->category))) { - print_error('invalidcategory'); - } - $coursefilesdir = get_filesdir_from_context(get_context_instance_by_id($category->contextid)); - - if ($question->image) { - - if (substr(strtolower($question->image), 0, 7) == 'http://') { - $img .= $question->image; - - } else { - require_once($CFG->libdir .'/filelib.php'); - $img = get_file_url("$coursefilesdir/{$question->image}"); - } - } - return $img; -} - -/** - * @global array + * @param $question + * @param $state + * @param $prefix + * @param $cmoptions + * @param $caption */ function question_print_comment_fields($question, $state, $prefix, $cmoptions, $caption = '') { global $QTYPES; @@ -2826,117 +2815,6 @@ function question_require_capability_on($question, $cap){ return true; } -/** - * @global object - */ -function question_file_links_base_url($courseid){ - global $CFG; - $baseurl = preg_quote("$CFG->wwwroot/file.php", '!'); - $baseurl .= '('.preg_quote('?file=', '!').')?';//may or may not - //be using slasharguments, accept either - $baseurl .= "/$courseid/";//course directory - return $baseurl; -} - -/** - * Find all course / site files linked to in a piece of html. - * @global object - * @param string html the html to search - * @param int course search for files for courseid course or set to siteid for - * finding site files. - * @return array files with keys being files. - */ -function question_find_file_links_from_html($html, $courseid){ - global $CFG; - $baseurl = question_file_links_base_url($courseid); - $searchfor = '!'. - '(<\s*(a|img)\s[^>]*(href|src)\s*=\s*")'.$baseurl.'([^"]*)"'. - '|'. - '(<\s*(a|img)\s[^>]*(href|src)\s*=\s*\')'.$baseurl.'([^\']*)\''. - '!i'; - $matches = array(); - $no = preg_match_all($searchfor, $html, $matches); - if ($no){ - $rawurls = array_filter(array_merge($matches[5], $matches[10]));//array_filter removes empty elements - //remove any links that point somewhere they shouldn't - foreach (array_keys($rawurls) as $rawurlkey){ - if (!$cleanedurl = question_url_check($rawurls[$rawurlkey])){ - unset($rawurls[$rawurlkey]); - } else { - $rawurls[$rawurlkey] = $cleanedurl; - } - - } - $urls = array_flip($rawurls);// array_flip removes duplicate files - // and when we merge arrays will continue to automatically remove duplicates - } else { - $urls = array(); - } - return $urls; -} - -/** - * Check that url doesn't point anywhere it shouldn't - * - * @global object - * @param $url string relative url within course files directory - * @return mixed boolean false if not OK or cleaned URL as string if OK - */ -function question_url_check($url){ - global $CFG; - if ((substr(strtolower($url), 0, strlen($CFG->moddata)) == strtolower($CFG->moddata)) || - (substr(strtolower($url), 0, 10) == 'backupdata')){ - return false; - } else { - return clean_param($url, PARAM_PATH); - } -} - -/** - * Find all course / site files linked to in a piece of html. - * - * @global object - * @param string html the html to search - * @param int course search for files for courseid course or set to siteid for - * finding site files. - * @return array files with keys being files. - */ -function question_replace_file_links_in_html($html, $fromcourseid, $tocourseid, $url, $destination, &$changed){ - global $CFG; - require_once($CFG->libdir .'/filelib.php'); - $tourl = get_file_url("$tocourseid/$destination"); - $fromurl = question_file_links_base_url($fromcourseid).preg_quote($url, '!'); - $searchfor = array('!(<\s*(a|img)\s[^>]*(href|src)\s*=\s*")'.$fromurl.'(")!i', - '!(<\s*(a|img)\s[^>]*(href|src)\s*=\s*\')'.$fromurl.'(\')!i'); - $newhtml = preg_replace($searchfor, '\\1'.$tourl.'\\5', $html); - if ($newhtml != $html){ - $changed = true; - } - return $newhtml; -} - -/** - * @global object - */ -function get_filesdir_from_context($context){ - global $DB; - - switch ($context->contextlevel){ - case CONTEXT_COURSE : - $courseid = $context->instanceid; - break; - case CONTEXT_MODULE : - $courseid = $DB->get_field('course_modules', 'course', array('id'=>$context->instanceid)); - break; - case CONTEXT_COURSECAT : - case CONTEXT_SYSTEM : - $courseid = SITEID; - break; - default : - print_error('invalidcontext'); - } - return $courseid; -} /** * Get the real state - the correct question id and answer - for a random * question. @@ -2944,7 +2822,7 @@ function get_filesdir_from_context($context){ * @return mixed return integer real question id or false if there was an * error.. */ -function question_get_real_state($state){ +function question_get_real_state($state) { global $OUTPUT; $realstate = clone($state); $matches = array(); diff --git a/question/category_class.php b/question/category_class.php index ac5903fac54..46842d43c09 100644 --- a/question/category_class.php +++ b/question/category_class.php @@ -38,24 +38,6 @@ class question_category_list extends moodle_list { public function get_records() { $this->records = get_categories_for_contexts($this->context->id, $this->sortby); } - public function process_actions($left, $right, $moveup, $movedown, $moveupcontext, $movedowncontext, $tocontext){ - global $CFG; - //parent::procces_actions redirects after any action - parent::process_actions($left, $right, $moveup, $movedown); - if ($tocontext == $this->context->id){ - //only called on toplevel list - if ($moveupcontext){ - $cattomove = $moveupcontext; - $totop = 0; - } elseif ($movedowncontext){ - $cattomove = $movedowncontext; - $totop = 1; - } - $toparent = "0,{$this->context->id}"; - $url = new moodle_url('/question/contextmove.php?', $this->pageurl->params() + compact('cattomove', 'totop', 'toparent')); - redirect($url); - } - } } class question_category_list_item extends list_item { @@ -87,12 +69,13 @@ class question_category_list_item extends list_item { /// Each section adds html to be displayed as part of this list item $questionbankurl = new moodle_url("/question/edit.php", ($this->parentlist->pageurl->params() + array('category'=>"$category->id,$category->contextid"))); - $catediturl = $this->parentlist->pageurl->out(true, array('edit'=>$this->id)); + $catediturl = $this->parentlist->pageurl->out(true, array('edit' => $this->id)); $item = "edit}\" href=\"$catediturl\">".$category->name ." ".'('.$category->questioncount.')'; $item .= ' '. $category->info; - if (count($this->parentlist->records)!=1){ // don't allow delete if this is the last category in this context. + // don't allow delete if this is the last category in this context. + if (count($this->parentlist->records) != 1) { $item .= ' ' .$str->delete. ''; } @@ -374,11 +357,9 @@ class question_category_object { public function move_questions($oldcat, $newcat){ global $DB; - $questionids = $DB->get_records_select_menu('question', "category = ? AND (parent = 0 OR parent = id)", array($oldcat), '', 'id,1'); - $ids = implode(',', array_keys($questionids)); - if (!question_move_questions_to_category($ids, $newcat)) { - print_error('errormovingquestions', 'question', $this->pageurl->out(), $ids); - } + $questionids = $DB->get_records_select_menu('question', + 'category = ? AND (parent = 0 OR parent = id)', array($oldcat), '', 'id,1'); + question_move_questions_to_category($questionids, $newcat); } /** @@ -439,7 +420,7 @@ class question_category_object { require_capability('moodle/question:managecategory', $fromcontext); // If moving to another context, check permissions some more. - if ($oldcat->contextid != $tocontextid){ + if ($oldcat->contextid != $tocontextid) { $tocontext = get_context_instance_by_id($tocontextid); require_capability('moodle/question:managecategory', $tocontext); } @@ -450,7 +431,7 @@ class question_category_object { $cat->name = $newname; $cat->info = $newinfo; $cat->parent = $parentid; - // We don't change $cat->contextid here, if necessary we redirect to contextmove.php later. + $cat->contextid = $tocontextid; $DB->update_record('question_categories', $cat); // If the category name has changed, rename any random questions in that category. @@ -464,41 +445,11 @@ class question_category_object { $DB->set_field_select('question', 'name', $randomqname, $where, array($cat->id, '1')); } - // Then redirect to an appropriate place. - if ($oldcat->contextid == $tocontextid) { // not moving contexts - redirect($this->pageurl); - } else { - $url = new moodle_url('/question/contextmove.php', ($this->pageurl->params() + array('cattomove' => $updateid, 'toparent'=>$newparent))); - redirect($url); + if ($oldcat->contextid != $tocontextid) { + // Moving to a new context. Must move files belonging to questions. + question_move_category_to_context($cat->id, $oldcat->contextid, $tocontextid); } + + redirect($this->pageurl); } - - public function move_question_from_cat_confirm($fromcat, $fromcourse, $tocat=null, $question=null){ - global $QTYPES, $DB; - if (!$question){ - $questions[] = $question; - } else { - $questions = $DB->get_records('question', array('category' => $tocat->id)); - } - $urls = array(); - foreach ($questions as $question){ - $urls = array_merge($urls, $QTYPES[$question->qtype]->find_file_links_in_question($question)); - } - if ($fromcourse){ - $append = 'tocourse'; - } else { - $append = 'tosite'; - } - if ($tocat){ - echo '

'.get_string('needtomovethesefilesincat','question').'

'; - } else { - echo '

'.get_string('needtomovethesefilesinquestion','question').'

'; - } - } - - - - } - - diff --git a/question/contextmove.php b/question/contextmove.php deleted file mode 100644 index 88544546638..00000000000 --- a/question/contextmove.php +++ /dev/null @@ -1,219 +0,0 @@ -dirroot."/question/editlib.php"); - require_once($CFG->dirroot."/question/contextmove_form.php"); - - //TODO: MDL-16094 - throw new coding_exception('contextmove.php was not converted to new file api yet, sorry - see MDL-16094'); - - list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = - question_edit_setup('categories', '/question/contextmove.php'); - - // get values from form for actions on this page - $toparent = required_param('toparent', PARAM_SEQUENCE); - $cattomove = required_param('cattomove', PARAM_INT); - $totop = optional_param('totop', 0, PARAM_INT); // optional param moves category to top of peers. Default is - //to add it to the bottom. - - - - $onerrorurl = new moodle_url('/question/category.php', $thispageurl->params()); - list($toparent, $contextto) = explode(',', $toparent); - if (!empty($toparent)){//not top level category, make it a child of $toparent - if (!$toparent = $DB->get_record('question_categories', array('id' => $toparent))){ - print_error('invalidcategoryidforparent', 'question', $onerrorurl); - } - $contextto = $toparent->contextid; - } else { - $toparent = new stdClass(); - $toparent->id = 0; - $toparent->contextid = $contextto; - } - if (!$cattomove = $DB->get_record('question_categories', array('id' => $cattomove))){ - print_error('invalidcategoryidtomove', 'question', $onerrorurl); - } - if ($cattomove->contextid == $contextto){ - print_error('contexterror', '', $onerrorurl); - } - $cattomove->categorylist = question_categorylist($cattomove->id); - - $thispageurl->params(array('cattomove'=>$cattomove->id, - 'toparent'=>"{$toparent->id},{$toparent->contextid}", - 'totop'=>$totop)); - - $contextfrom = get_context_instance_by_id($cattomove->contextid); - $contextto = get_context_instance_by_id($contextto); - $contexttostring = print_context_name($contextto); - - require_capability('moodle/question:managecategory', $contextfrom); - require_capability('moodle/question:managecategory', $contextto); - - - $fromcoursefilesid = get_filesdir_from_context($contextfrom);//siteid or courseid - $tocoursefilesid = get_filesdir_from_context($contextto);//siteid or courseid - if ($fromcoursefilesid != $tocoursefilesid){ - list($usql, $params) = $DB->get_in_or_equal(explode(',', $cattomove->categorylist)); - $questions = $DB->get_records_select('question', "category $usql", $params); - $urls = array(); - if ($questions){ - foreach ($questions as $id => $question){ - $QTYPES[$questions[$id]->qtype]->get_question_options($questions[$id]); - $urls = array_merge_recursive($urls, $QTYPES[$questions[$id]->qtype]->find_file_links($questions[$id], $fromcoursefilesid)); - } - } - ksort($urls); - } else { - $urls = array(); - } - $brokenurls = array(); - foreach (array_keys($urls) as $url){ - if (!file_exists($CFG->dataroot."/$fromcoursefilesid/".$url)){ - $brokenurls[] = $url; - } - } - if ($fromcoursefilesid == SITEID){ - $fromareaname = get_string('filesareasite', 'question'); - } else { - $fromareaname = get_string('filesareacourse', 'question'); - } - if ($tocoursefilesid == SITEID){ - $toareaname = get_string('filesareasite', 'question'); - } else { - $toareaname = get_string('filesareacourse', 'question'); - } - $contextmoveform = new question_context_move_form($thispageurl, - compact('urls', 'fromareaname', 'toareaname', 'brokenurls', - 'fromcoursefilesid', 'tocoursefilesid')); - if ($contextmoveform->is_cancelled()){ - $thispageurl->remove_params('cattomove', 'toparent', 'totop'); - redirect(new moodle_url("/question/category.php".$thispageurl->params())); - }elseif ($moveformdata = $contextmoveform->get_data()) { - if (isset($moveformdata->urls) && is_array($moveformdata->urls)){ - check_dir_exists($CFG->dataroot."/$tocoursefilesid/", true); - $flipurls = array_keys($urls); - foreach ($moveformdata->urls as $key => $urlaction){ - $source = $CFG->dataroot."/$fromcoursefilesid/".$flipurls[$key]; - $destination = $flipurls[$key]; - if (($urlaction != QUESTION_FILEDONOTHING) && ($urlaction != QUESTION_FILEMOVELINKSONLY)){ - // Ensure the target folder exists. - check_dir_exists(dirname($CFG->dataroot."/$tocoursefilesid/".$destination), true); - - // Then make sure the destination file name does not exist. If it does, change the name to be unique. - while (file_exists($CFG->dataroot."/$tocoursefilesid/".$destination)){ - $matches = array(); - //check for '_'. copyno after filename, before extension. - if (preg_match('!\_([0-9]+)(\.[^\.\\/]+)?$!', $destination, $matches)){ - $copyno = $matches[1]+1; - } else { - $copyno = 1; - } - //replace old copy no with incremented one. - $destination = preg_replace('!(\_[0-9]+)?(\.[^\.\\/]+)?$!', '_'.$copyno.'\\2', $destination, 1); - } - } - switch ($urlaction){ - case QUESTION_FILECOPY : - if (!copy($source, $CFG->dataroot."/$tocoursefilesid/".$destination)){ - print_error('errorfilecannotbecopied', 'question', $onerrorurl, $source); - } - break; - case QUESTION_FILEMOVE : - if (!rename($source, $CFG->dataroot."/$tocoursefilesid/".$destination)){ - print_error('errorfilecannotbemoved', 'question', $onerrorurl, $source); - } - break; - case QUESTION_FILEDONOTHING : - case QUESTION_FILEMOVELINKSONLY : - break; - default : - print_error('invalidaction', '', $onerrorurl); - } - switch ($urlaction){ - //now search and replace urls in questions. - case QUESTION_FILECOPY : - case QUESTION_FILEMOVE : - case QUESTION_FILEMOVELINKSONLY : - $url = $flipurls[$key]; - $questionids = array_unique($urls[$url]); - foreach ($questionids as $questionid){ - $question = $questions[$questionid]; - $QTYPES[$question->qtype]->replace_file_links($question, $fromcoursefilesid, $tocoursefilesid, $url, $destination); - } - break; - case QUESTION_FILEDONOTHING : - default : - break; - } - - - } - } - - //adjust sortorder before we make the cat a peer of it's new peers - $peers = $DB->get_records_select_menu('question_categories', - 'contextid = ? AND parent = ?', array($toparent->contextid, $toparent->id), - 'sortorder ASC', 'id, 1'); - $peers = array_keys($peers); - if ($totop){ - array_unshift($peers, $cattomove->id); - } else { - $peers[] = $cattomove->id; - } - $sortorder = 0; - foreach ($peers as $peer) { - $DB->set_field('question_categories', "sortorder", $sortorder, array("id" => $peer)); - $sortorder++; - } - //now move category - $cat = new stdClass(); - $cat->id = $cattomove->id; - $cat->parent = $toparent->id; - //set context of category we are moving and all children also! - list($usql, $params) = $DB->get_in_or_equal(explode(',', $cattomove->categorylist)); - $params = array_merge(array($contextto->id), $params); - - $DB->execute("UPDATE {question_categories} SET contextid = ? WHERE id $usql", $params); - //finally set the new parent id - $DB->update_record("question_categories", $cat); - $thispageurl->remove_params('cattomove', 'toparent', 'totop'); - $url = new moodle_url('/question/category.php', ($thispageurl->params() + array('cat'=>"{$cattomove->id},{$contextto->id}"))); - redirect($url); - } - - $streditingcategories = get_string('editcategories', 'quiz'); - - $PAGE->set_url($thispageurl->out()); - $PAGE->navbar->add($streditingcategories, $thispageurl->out()); - $PAGE->navbar->add(get_string('movingcategory', 'question')); - $PAGE->set_heading($COURSE->fullname); - echo $OUTPUT->header(); - - //parameter for get_string - $cattomove->contextto = $contexttostring; - if (count($urls)){ - $defaults = array(); - for ($default_key = 0; $default_key < count($urls); $default_key++){ - $defaults['urls'][$default_key] = QUESTION_FILECOPY; - } - $contextmoveform->set_data($defaults); - //some parameters for get_string - $cattomove->urlcount = count($urls); - $cattomove->toareaname = $toareaname; - $cattomove->fromareaname = $fromareaname; - - echo $OUTPUT->box(get_string('movingcategoryandfiles', 'question', $cattomove), 'boxwidthnarrow boxaligncenter generalbox'); - } else { - echo $OUTPUT->box(get_string('movingcategorynofiles', 'question', $cattomove), 'boxwidthnarrow boxaligncenter generalbox'); - } - $contextmoveform->display(); - echo $OUTPUT->footer(); - diff --git a/question/contextmove_form.php b/question/contextmove_form.php deleted file mode 100644 index 9a16a9730f7..00000000000 --- a/question/contextmove_form.php +++ /dev/null @@ -1,107 +0,0 @@ -libdir.'/formslib.php'); - -class question_context_move_form extends moodleform { - - function definition() { - global $CFG, $OUTPUT; - $mform =& $this->_form; - -//-------------------------------------------------------------------------------- - $urls = $this->_customdata['urls']; - $fromareaname = $this->_customdata['fromareaname']; - $toareaname = $this->_customdata['toareaname']; - $fileoptions = array(QUESTION_FILEDONOTHING=>get_string('donothing', 'question'), - QUESTION_FILECOPY=>get_string('copy', 'question', $fromareaname), - QUESTION_FILEMOVE=>get_string('move', 'question', $fromareaname), - QUESTION_FILEMOVELINKSONLY=>get_string('movelinksonly', 'question', $fromareaname)); - $brokenfileoptions = array(QUESTION_FILEDONOTHING=>get_string('donothing', 'question'), - QUESTION_FILEMOVELINKSONLY=>get_string('movelinksonly', 'question', $fromareaname)); - $brokenurls = $this->_customdata['brokenurls']; - if (count($urls)){ - - $mform->addElement('header','general', get_string('filestomove', 'question', $toareaname)); - - $i = 0; - foreach (array_keys($urls) as $url){ - $icontype = mimeinfo('type', $url); - $img = "pix_url(file_extension_icon($url)) . "\" class=\"icon\" alt=\"$icontype\" />"; - if (in_array($url, $brokenurls)){ - $mform->addElement('select', "urls[$i]", $img.$url, $brokenfileoptions); - } else { - $mform->addElement('select', "urls[$i]", $img.$url, $fileoptions); - } - $i++; - } - - } - if (count($brokenurls)){ - $mform->addElement('advcheckbox','ignorebroken', get_string('ignorebroken', 'question')); - } - //-------------------------------------------------------------------------------- - $this->add_action_buttons(true, get_string('movecategory', 'question')); - - } - - function validation($data, $files) { - $errors = parent::validation($data, $files); - $tocoursefilesid = $this->_customdata['tocoursefilesid']; - $fromcoursefilesid = $this->_customdata['fromcoursefilesid']; - if (isset($data['urls']) && (count($data['urls']))){ - foreach ($data['urls'] as $key => $urlaction){ - switch ($urlaction){ - case QUESTION_FILEMOVE : - if (!has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_COURSE, $fromcoursefilesid))){ - $errors["urls[$key]"] = get_string('filecantmovefrom', 'question'); - } - //no break; COPY check is also applied to MOVE action - case QUESTION_FILECOPY : - if (!has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_COURSE, $tocoursefilesid))){ - $errors["urls[$key]"] = get_string('filecantmoveto', 'question'); - } - break; - case QUESTION_FILEMOVELINKSONLY : - case QUESTION_FILEDONOTHING : - break; - } - } - } - //check that there hasn't been any changes in files between time form was displayed - //and now when it has been submitted. - if (isset($data['urls']) && - (count($data['urls']) - != count($this->_customdata['urls']))){ - $errors['urls[0]'] = get_string('errorfileschanged', 'question'); - } - return $errors; - } - /* - * We want these errors to show up on first loading the form which is not the default for - * validation method which is not run until submission. - */ - function definition_after_data(){ - $mform = $this->_form; - $brokenurls = $this->_customdata['brokenurls']; - if (count($brokenurls)){ - $ignoreval = $mform->getElementValue('ignorebroken'); - if (!$ignoreval){ - $urls = $this->_customdata['urls']; - $i = 0; - foreach (array_keys($urls) as $url){ - if (in_array($url, $brokenurls)){ - $mform->setElementError("urls[$i]", get_string('broken', 'question')); - } else { - $mform->setElementError("urls[$i]", ''); - } - $i++; - } - } - } - } -} - diff --git a/question/contextmoveq.php b/question/contextmoveq.php deleted file mode 100644 index 0ad72f73137..00000000000 --- a/question/contextmoveq.php +++ /dev/null @@ -1,224 +0,0 @@ -dirroot.'/question/contextmoveq_form.php'); - -//TODO: MDL-16094 -throw new coding_exception('contextmoveq.php was not converted to new file api yet, sorry - see MDL-16094'); - -$ids = required_param('ids', PARAM_SEQUENCE); // question ids - -if (!$cmid = optional_param('cmid', 0, PARAM_INT)){ - $courseid = required_param('courseid', PARAM_INT); -} - -$tocatid = required_param('tocatid', PARAM_INT); -$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL); - -$thispageurl = new moodle_url('/question/contextmoveq.php'); -$thispageurl->params(compact('tocatid', 'ids', 'returnurl')); - -if ($cmid){ - list($module, $cm) = get_module_from_cmid($cmid); - require_login($cm->course, false, $cm); - $thiscontext = get_context_instance(CONTEXT_MODULE, $cmid); - if (!$returnurl) { - $returnurl = "{$CFG->wwwroot}/question/edit.php?cmid={$cm->id}"; - } - $thispageurl->param('cmid', $cmid); -} elseif ($courseid) { - require_login($courseid, false); - $thiscontext = get_context_instance(CONTEXT_COURSE, $courseid); - $module = null; - $cm = null; - if (!$returnurl) { - $returnurl = "{$CFG->wwwroot}/question/edit.php?courseid={$COURSE->id}"; - } - $thispageurl->param('courseid', $COURSE->id); -} else { - print_error('missingcourseorcmid', 'question'); -} -$contexts = new question_edit_contexts($thiscontext); - -list($usql, $params) = $DB->get_in_or_equal(explode(',', $ids)); - -if (!$questions = $DB->get_records_sql("SELECT q.*, c.contextid FROM {question} q, {question_categories} c WHERE q.id $usql AND c.id = q.category", $params)) { - print_error('questiondoesnotexist', 'question', $returnurl); -} -if (!$tocat = $DB->get_record('question_categories', array('id' => $tocatid))){ - print_error('categorydoesnotexist', 'question', $returnurl); -} -$tocat->context = get_context_instance_by_id($tocat->contextid); -require_capability('moodle/question:add', $tocat->context); -$tocoursefilesid = get_filesdir_from_context($tocat->context); -$urls = array(); - -if ($tocoursefilesid == SITEID){ - $toareaname = get_string('filesareasite', 'question'); -} else { - $toareaname = get_string('filesareacourse', 'question'); -} -$fromcoursefilesid = 0; -foreach (array_keys($questions) as $id){ - question_require_capability_on($questions[$id], 'move'); - get_question_options($questions[$id]); - $questions[$id]->context = get_context_instance_by_id($questions[$id]->contextid); - $thisfilesid = get_filesdir_from_context($questions[$id]->context); - if ($fromcoursefilesid && $thisfilesid != $fromcoursefilesid){ - print_error('cannotmovequestion', 'question'); - } else { - $fromcoursefilesid = $thisfilesid; - } - if ($tocoursefilesid != $fromcoursefilesid){ - $urls = array_merge_recursive($urls, $QTYPES[$questions[$id]->qtype]->find_file_links($questions[$id], $fromcoursefilesid)); - } -} - -$brokenurls = array(); -foreach (array_keys($urls) as $url){ - if (!file_exists($CFG->dataroot."/$fromcoursefilesid/".$url)){ - $brokenurls[] = $url; - } -} -if ($fromcoursefilesid == SITEID){ - $fromareaname = get_string('filesareasite', 'question'); -} else { - $fromareaname = get_string('filesareacourse', 'question'); -} - -$contextmoveform = new question_context_move_question_form($thispageurl, - compact('urls', 'fromareaname', 'toareaname', 'brokenurls', - 'fromcoursefilesid', 'tocoursefilesid')); -if ($contextmoveform->is_cancelled()){ - redirect($returnurl); -}elseif ($moveformdata = $contextmoveform->get_data()) { - if (isset($moveformdata->urls) && is_array($moveformdata->urls)){ - check_dir_exists($CFG->dataroot."/$tocoursefilesid/", true); - $flipurls = array_keys($urls); - //actions on files - foreach ($moveformdata->urls as $key => $urlaction){ - $source = $CFG->dataroot."/$fromcoursefilesid/".$flipurls[$key]; - $destination = $flipurls[$key]; - if (($urlaction != QUESTION_FILEDONOTHING) && ($urlaction != QUESTION_FILEMOVELINKSONLY)){ - // Ensure the target folder exists. - check_dir_exists(dirname($CFG->dataroot."/$tocoursefilesid/".$destination), true); - - // Then make sure the destination file name does not exist. If it does, change the name to be unique. - while (file_exists($CFG->dataroot."/$tocoursefilesid/".$destination)){ - $matches = array(); - //check for '_'. copyno after filename, before extension. - if (preg_match('!\_([0-9]+)(\.[^\.\\/]+)?$!', $destination, $matches)){ - $copyno = $matches[1]+1; - } else { - $copyno = 1; - } - //replace old copy no with incremented one. - $destination = preg_replace('!(\_[0-9]+)?(\.[^\.\\/]+)?$!', '_'.$copyno.'\\2', $destination, 1); - } - } - switch ($urlaction){ - case QUESTION_FILECOPY : - if (!copy($source, $CFG->dataroot."/$tocoursefilesid/".$destination)){ - print_error('errorfilecannotbecopied', 'question', $returnurl, $source); - } - break; - case QUESTION_FILEMOVE : - if (!rename($source, $CFG->dataroot."/$tocoursefilesid/".$destination)){ - print_error('errorfilecannotbemoved', 'question', $returnurl, $source); - } - break; - case QUESTION_FILEMOVELINKSONLY : - case QUESTION_FILEDONOTHING : - break; - default : - print_error('invalidaction', '', $returnurl); - } - //now search and replace urls in questions. - switch ($urlaction){ - case QUESTION_FILECOPY : - case QUESTION_FILEMOVE : - case QUESTION_FILEMOVELINKSONLY : - $url = $flipurls[$key]; - $questionswithlinks = array_unique($urls[$url]); - foreach ($questionswithlinks as $questionid){ - $QTYPES[$questions[$questionid]->qtype]->replace_file_links($questions[$questionid], $fromcoursefilesid, $tocoursefilesid, $url, $destination); - } - break; - case QUESTION_FILEDONOTHING : - break; - default : - print_error('invalidaction', '', $returnurl); - break; - } - - - } - } - -/// Now move questions. - if (!question_move_questions_to_category($ids, $tocat->id)) { - print_error('errormovingquestions', 'question', $returnurl, $ids); - } - if ($returnurl) { - $returnurl = new moodle_url('/' . $returnurl); - } - redirect($returnurl); -} - -$streditingcategories = get_string('editcategories', 'quiz'); -$strmovingquestions = get_string('movingquestions', 'question'); -$PAGE->set_url($thispageurl->out()); -$PAGE->navbar->add($strmovingquestions); -$PAGE->set_title($strmovingquestions); -$PAGE->set_heading($COURSE->fullname); -echo $OUTPUT->header(); - -//parameter for get_string -$questionsstr = new stdClass(); -$questionsstr->tocontext = print_context_name($tocat->context); -$questionsstr->fromareaname = $fromareaname; - -//comma seperated string "'xx', 'cx', 'sdf' and 'fgdhfg'" -$questionnamestojoin = array(); -foreach ($questions as $question){ - $questionnamestojoin[] = $question->name; -} -$tojoincount = count($questionnamestojoin); - -if ($tojoincount > 1){ - $a = new stdClass(); - $a->one = $questionnamestojoin[$tojoincount -2].'"'; - $a->two = '"'.$questionnamestojoin[$tojoincount -1]; - $questionnamestojoin[$tojoincount -2] = get_string('and', '', $a); - unset($questionnamestojoin[$tojoincount -1]); -} -$questionsstr->questions = '"'.join($questionnamestojoin, '", "').'"'; - -if (count($urls)){ - $defaults = array(); - for ($default_key = 0; $default_key < count($urls); $default_key++){ - $defaults['urls'][$default_key] = QUESTION_FILECOPY; - } - $contextmoveform->set_data($defaults); - - //some parameters for get_string - $questionsstr->urlcount = count($urls); - - $questionsstr->toareaname = $toareaname; - - echo $OUTPUT->box(get_string('movingquestionsandfiles', 'question', $questionsstr), 'boxwidthnarrow boxaligncenter generalbox'); -} else { - echo $OUTPUT->box(get_string('movingquestionsnofiles', 'question', $questionsstr), 'boxwidthnarrow boxaligncenter generalbox'); -} -$contextmoveform->display(); -echo $OUTPUT->footer(); - diff --git a/question/contextmoveq_form.php b/question/contextmoveq_form.php deleted file mode 100644 index 2af39a52a93..00000000000 --- a/question/contextmoveq_form.php +++ /dev/null @@ -1,111 +0,0 @@ -libdir.'/formslib.php'); - -class question_context_move_question_form extends moodleform { - - function definition() { - global $CFG, $OUTPUT; - $mform =& $this->_form; - -//-------------------------------------------------------------------------------- - $urls = $this->_customdata['urls']; - $fromareaname = $this->_customdata['fromareaname']; - $toareaname = $this->_customdata['toareaname']; - $fileoptions = array(QUESTION_FILEDONOTHING=>get_string('donothing', 'question'), - QUESTION_FILECOPY=>get_string('copy', 'question', $fromareaname), - QUESTION_FILEMOVE=>get_string('move', 'question', $fromareaname), - QUESTION_FILEMOVELINKSONLY=>get_string('movelinksonly', 'question', $fromareaname)); - $brokenfileoptions = array(QUESTION_FILEDONOTHING=>get_string('donothing', 'question'), - QUESTION_FILEMOVELINKSONLY=>get_string('movelinksonly', 'question', $fromareaname)); - - $brokenurls = $this->_customdata['brokenurls']; - if (count($urls)){ - - $mform->addElement('header','general', get_string('filestomove', 'question', $toareaname)); - - $i = 0; - foreach (array_keys($urls) as $url){ - $icontype = mimeinfo('type', $url); - $img = "pix_url(file_extension_icon($url)) . "\" class=\"icon\" alt=\"$icontype\" />"; - if (in_array($url, $brokenurls)){ - $mform->addElement('select', "urls[$i]", $img.$url, $brokenfileoptions); - } else { - $mform->addElement('select', "urls[$i]", $img.$url, $fileoptions); - } - $i++; - } - - } - if (count($brokenurls)){ - $mform->addElement('advcheckbox','ignorebroken', get_string('ignorebroken', 'question')); - } -//-------------------------------------------------------------------------------- - $this->add_action_buttons(true, get_string('moveq', 'question')); - } - - function validation($data, $files) { - $errors = parent::validation($data, $files); - $tocoursefilesid = $this->_customdata['tocoursefilesid']; - $fromcoursefilesid = $this->_customdata['fromcoursefilesid']; - if (isset($data['urls']) && (count($data['urls']))){ - foreach ($data['urls'] as $key => $urlaction){ - switch ($urlaction){ - case QUESTION_FILEMOVE : - if (!has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_COURSE, $fromcoursefilesid))){ - $errors["urls[$key]"] = get_string('filecantmovefrom', 'question'); - } - case QUESTION_FILECOPY : - if (!has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_COURSE, $tocoursefilesid))){ - $errors["urls[$key]"] = get_string('filecantmoveto', 'question'); - } - break; - case QUESTION_FILEMOVELINKSONLY : - case QUESTION_FILEDONOTHING : - break; - } - } - } - //check that there hasn't been any changes in files between time form was displayed - //and now when it has been submitted. - if (isset($data['urls']) && - (count($data['urls']) - != count($this->_customdata['urls']))){ - $errors['urls[0]'] = get_string('errorfileschanged', 'question'); - - } - return $errors; - } - /* - * We want these errors to show up on first loading the form which is not the default for - * validation method which is not run until submission. - */ - function definition_after_data(){ - static $done = false; - if (!$done){ - $mform = $this->_form; - $brokenurls = $this->_customdata['brokenurls']; - if (count($brokenurls)){ - $ignoreval = $mform->getElementValue('ignorebroken'); - if (!$ignoreval){ - $urls = $this->_customdata['urls']; - $i = 0; - foreach (array_keys($urls) as $url){ - if (in_array($url, $brokenurls)){ - $mform->setElementError("urls[$i]", get_string('broken', 'question')); - } else { - $mform->setElementError("urls[$i]", ''); - } - $i++; - } - } - } - $done = true; - } - } -} - diff --git a/question/editlib.php b/question/editlib.php index ba51bbb93c9..41bcaee1086 100644 --- a/question/editlib.php +++ b/question/editlib.php @@ -1385,7 +1385,8 @@ class question_bank_view { public function process_actions() { global $CFG, $DB; /// Now, check for commands on this page and modify variables as necessary - if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { /// Move selected questions to new category + if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { + // Move selected questions to new category $category = required_param('category', PARAM_SEQUENCE); list($tocategoryid, $contextid) = explode(',', $category); if (! $tocategory = $DB->get_record('question_categories', array('id' => $tocategoryid, 'contextid' => $contextid))) { @@ -1403,38 +1404,18 @@ class question_bank_view { } if ($questionids) { list($usql, $params) = $DB->get_in_or_equal($questionids); - $sql = "SELECT q.*, c.contextid FROM {question} q, {question_categories} c WHERE q.id $usql AND c.id = q.category"; - if (!$questions = $DB->get_records_sql($sql, $params)){ - print_error('questiondoesnotexist', 'question', $pageurl->out()); - } - $checkforfiles = false; + $sql = ""; + $questions = $DB->get_records_sql(" + SELECT q.*, c.contextid + FROM {question} q + JOIN {question_categories} c ON c.id = q.category + WHERE q.id $usql", $params); foreach ($questions as $question){ - //check capabilities question_require_capability_on($question, 'move'); - $fromcontext = get_context_instance_by_id($question->contextid); - if (get_filesdir_from_context($fromcontext) != get_filesdir_from_context($tocontext)){ - $checkforfiles = true; - } - } - $returnurl = $this->baseurl->out(false, array('category' => "$tocategoryid,$contextid")); - if (!$checkforfiles){ - if (!question_move_questions_to_category(implode(',', $questionids), $tocategory->id)) { - print_error('errormovingquestions', 'question', $returnurl, $questionids); - } - redirect($returnurl); - } else { - $returnurl = str_replace($CFG->wwwroot . '/', '', $returnurl); - $movecontexturl = new moodle_url('/question/contextmoveq.php', - array('returnurl' => $returnurl, - 'ids' => implode(',', $questionids), - 'tocatid' => $tocategoryid)); - if (!empty($cm->id)){ - $movecontexturl->param('cmid', $cm->id); - } else { - $movecontexturl->param('courseid', $this->course->id); - } - redirect($movecontexturl); } + question_move_questions_to_category($questionids, $tocategory->id); + redirect($this->baseurl->out(false, + array('category' => "$tocategoryid,$contextid"))); } } diff --git a/question/question.php b/question/question.php index 8402cbb9eef..efdb1f62da8 100644 --- a/question/question.php +++ b/question/question.php @@ -211,7 +211,7 @@ if ($mform->is_cancelled()){ } redirect($returnurl->out(false)); } -} elseif ($fromform = $mform->get_data()) { +} else if ($fromform = $mform->get_data()) { /// If we are saving as a copy, break the connection to the old question. if (!empty($fromform->makecopy)) { $question->id = 0; @@ -237,36 +237,27 @@ if ($mform->is_cancelled()){ question_require_capability_on($question, 'move'); } - /// Ensure we redirect back to the category the question is being saved into. + // Ensure we redirect back to the category the question is being saved into. $returnurl->param('category', $fromform->category); - /// Call the appropriate method. if ($movecontext) { + // We are just moving the question to a different context. list($tocatid, $tocontextid) = explode(',', $fromform->categorymoveto); - $tocontext = get_context_instance_by_id($tocontextid); - require_capability('moodle/question:add', $tocontext); - if (get_filesdir_from_context($categorycontext) != get_filesdir_from_context($tocontext)){ - $movecontexturl = new moodle_url('/question/contextmoveq.php', array( - 'returnurl' => str_replace($CFG->wwwroot, '', $returnurl->out(false)), - 'ids' => $question->id, - 'tocatid' => $tocatid)); - if ($cmid){ - $movecontexturl->param('cmid', $cmid); - } else { - $movecontexturl->param('courseid', $courseid); - } - redirect($movecontexturl); + require_capability('moodle/question:add', get_context_instance_by_id($tocontextid)); + question_move_questions_to_category(array($question->id), $tocatid); + + } else { + // We are acutally saving the question. + $question = $QTYPES[$question->qtype]->save_question($question, $fromform, $COURSE, $wizardnow, true); + if (!empty($CFG->usetags) && isset($fromform->tags)) { + // A wizardpage from multipe pages questiontype like calculated may not + // allow editing the question tags, hence the isset($fromform->tags) test. + require_once($CFG->dirroot.'/tag/lib.php'); + tag_set('question', $question->id, $fromform->tags); } } - $question = $QTYPES[$question->qtype]->save_question($question, $fromform, $COURSE, $wizardnow, true); - // a wizardpage from multipe pages questiontype like calculated may not allow editing the question tags - if (!empty($CFG->usetags) && isset($fromform->tags)) { - require_once($CFG->dirroot.'/tag/lib.php'); - tag_set('question', $question->id, $fromform->tags); - } - - if (($QTYPES[$question->qtype]->finished_edit_wizard($fromform)) || $movecontext){ + if (($QTYPES[$question->qtype]->finished_edit_wizard($fromform)) || $movecontext) { if ($inpopup) { echo $OUTPUT->notification(get_string('changessaved'), ''); close_window(3); @@ -279,6 +270,7 @@ if ($mform->is_cancelled()){ } redirect($returnurl); } + } else { $nexturlparams = array( 'returnurl' => $originalreturnurl, @@ -297,8 +289,8 @@ if ($mform->is_cancelled()){ } redirect($nexturl); } -} else { +} else { $streditingquestion = $QTYPES[$question->qtype]->get_heading(); $PAGE->set_title($streditingquestion); $PAGE->set_heading($COURSE->fullname); @@ -316,7 +308,7 @@ if ($mform->is_cancelled()){ } else { $strediting = ''.get_string("editquestions", "quiz").' -> '.$streditingquestion; - $PAGE->navbar->add(get_string('editquestions', "quiz"), $returnurl); + $PAGE->navbar->add(get_string('editquestions', 'quiz'), $returnurl); $PAGE->navbar->add($streditingquestion); echo $OUTPUT->header(); } diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php index 9e646a47aa9..847bf598d9c 100644 --- a/question/type/calculated/questiontype.php +++ b/question/type/calculated/questiontype.php @@ -2108,44 +2108,14 @@ class question_calculated_qtype extends default_questiontype { return $new_question; } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); - + function move_files($questionid, $oldcontextid, $newcontextid) { $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - $component = 'qtype_numerical'; - $filearea = 'instruction'; - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } + + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); + + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_numerical', 'instruction', $questionid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/calculatedmulti/questiontype.php b/question/type/calculatedmulti/questiontype.php index d7a4ec059d7..e4f3abffc82 100644 --- a/question/type/calculatedmulti/questiontype.php +++ b/question/type/calculatedmulti/questiontype.php @@ -548,48 +548,18 @@ class question_calculatedmulti_qtype extends question_calculated_qtype { return $new_question; } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - // move files belonging to question component - parent::move_files($question, $newcategory); - - // move files belonging to qtype_calculatedmulti + function move_files($questionid, $oldcontextid, $newcontextid) { $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - $component = 'qtype_calculatedmulti'; - foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid, true); + + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_calculatedmulti', 'correctfeedback', $questionid); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_calculatedmulti', 'partiallycorrectfeedback', $questionid); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_calculatedmulti', 'incorrectfeedback', $questionid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/calculatedsimple/questiontype.php b/question/type/calculatedsimple/questiontype.php index ea9d6cb7d7a..621bd2750ea 100644 --- a/question/type/calculatedsimple/questiontype.php +++ b/question/type/calculatedsimple/questiontype.php @@ -341,45 +341,15 @@ class question_calculatedsimple_qtype extends question_calculated_qtype { return $new_question; } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); + function move_files($questionid, $oldcontextid, $newcontextid) { $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'feedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - $component = 'qtype_calculatedsimple'; - $filearea = 'feedback'; - $filearea = 'instruction'; - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } + + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); + + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_calculatedsimple', 'instruction', $questionid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/edit_question_form.php b/question/type/edit_question_form.php index c6df77c3675..3ae83d86c40 100644 --- a/question/type/edit_question_form.php +++ b/question/type/edit_question_form.php @@ -46,7 +46,6 @@ class question_edit_form extends moodleform { public $contexts; public $category; public $categorycontext; - public $coursefilesid; /** @var object current context */ public $context; @@ -64,25 +63,20 @@ class question_edit_form extends moodleform { $this->contexts = $contexts; - $record = $DB->get_record('question_categories', array('id'=>$question->category), 'contextid'); + $record = $DB->get_record('question_categories', array('id' => $question->category), 'contextid'); $this->context = get_context_instance_by_id($record->contextid); - $this->editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'context'=>$this->context); - $this->fileoptions = array('subdir'=>true, 'maxfiles'=>-1, 'maxbytes'=>-1); + $this->editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'context' => $this->context); + $this->fileoptions = array('subdir' => true, 'maxfiles' => -1, 'maxbytes' => -1); $this->category = $category; $this->categorycontext = get_context_instance_by_id($category->contextid); - //** * - //course id or site id depending on question cat context - $this->coursefilesid = get_filesdir_from_context(get_context_instance_by_id($category->contextid)); if (!empty($question->id)) { - $question->id = (int)$question->id; - //$this->instance = new + $question->id = (int) $question->id; } parent::moodleform($submiturl, null, 'post', '', null, $formeditable); - } /** @@ -104,20 +98,20 @@ class question_edit_form extends moodleform { $mform->addElement('header', 'generalheader', get_string("general", 'form')); if (!isset($this->question->id)){ - //adding question + // Adding question $mform->addElement('questioncategory', 'category', get_string('category', 'quiz'), array('contexts' => $this->contexts->having_cap('moodle/question:add'))); } elseif (!($this->question->formoptions->canmove || $this->question->formoptions->cansaveasnew)){ - //editing question with no permission to move from category. + // Editing question with no permission to move from category. $mform->addElement('questioncategory', 'category', get_string('category', 'quiz'), array('contexts' => array($this->categorycontext))); } elseif ($this->question->formoptions->movecontext){ - //moving question to another context. + // Moving question to another context. $mform->addElement('questioncategory', 'categorymoveto', get_string('category', 'quiz'), array('contexts' => $this->contexts->having_cap('moodle/question:add'))); } else { - //editing question with permission to move from category or save as new q + // Editing question with permission to move from category or save as new q $currentgrp = array(); $currentgrp[0] =& $mform->createElement('questioncategory', 'category', get_string('categorycurrent', 'question'), array('contexts' => array($this->categorycontext))); @@ -143,7 +137,7 @@ class question_edit_form extends moodleform { $mform->addRule('name', null, 'required', null, 'client'); $mform->addElement('editor', 'questiontext', get_string('questiontext', 'quiz'), - array('rows' => 15, 'course' => $this->coursefilesid), $this->editoroptions); + array('rows' => 15), $this->editoroptions); $mform->setType('questiontext', PARAM_RAW); $mform->addElement('text', 'defaultgrade', get_string('defaultgrade', 'quiz'), @@ -160,7 +154,7 @@ class question_edit_form extends moodleform { $mform->setDefault('penalty', 0.1); $mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'quiz'), - array('rows' => 10, 'course' => $this->coursefilesid), $this->editoroptions); + array('rows' => 10), $this->editoroptions); $mform->setType('generalfeedback', PARAM_RAW); $mform->addHelpButton('generalfeedback', 'generalfeedback', 'quiz'); @@ -243,15 +237,15 @@ class question_edit_form extends moodleform { $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false); $mform->closeHeaderBefore('buttonar'); - if ($this->question->formoptions->movecontext){ + if ($this->question->formoptions->movecontext) { $mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar')); - } elseif ((!empty($this->question->id)) && (!($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew))){ + } else if ((!empty($this->question->id)) && (!($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew))){ $mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar', 'currentgrp')); } } function validation($fromform, $files) { - $errors= parent::validation($fromform, $files); + $errors = parent::validation($fromform, $files); if (empty($fromform->makecopy) && isset($this->question->id) && ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew) && empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove) { @@ -284,7 +278,7 @@ class question_edit_form extends moodleform { $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 80)); $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions); $repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), - array('course' => $this->coursefilesid), $this->editoroptions); + array('rows' => 5), $this->editoroptions); $repeatedoptions['answer']['type'] = PARAM_RAW; $repeatedoptions['fraction']['default'] = 0; $answersoption = 'answers'; diff --git a/question/type/essay/questiontype.php b/question/type/essay/questiontype.php index 8fb9a8c871b..55dfaeb56f7 100644 --- a/question/type/essay/questiontype.php +++ b/question/type/essay/questiontype.php @@ -156,33 +156,9 @@ class question_essay_qtype extends default_questiontype { return $this->save_question($question, $form, $course); } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); - - $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } + function move_files($questionid, $oldcontextid, $newcontextid) { + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/match/questiontype.php b/question/type/match/questiontype.php index 9ca99cae2fb..a8656663d71 100644 --- a/question/type/match/questiontype.php +++ b/question/type/match/questiontype.php @@ -492,39 +492,6 @@ class question_match_qtype extends default_questiontype { return 1 / count($question->options->subquestions); } - function find_file_links($question, $courseid){ - // find links in the question_match_sub table. - $urls = array(); - if (isset($question->options->subquestions)){ - foreach ($question->options->subquestions as $subquestion) { - $urls += question_find_file_links_from_html($subquestion->questiontext, $courseid); - } - - //set all the values of the array to the question object - if ($urls){ - $urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id))); - } - } - $urls = array_merge_recursive($urls, parent::find_file_links($question, $courseid)); - - return $urls; - } - - function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){ - global $DB; - parent::replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination); - // replace links in the question_match_sub table. - if (isset($question->options->subquestions)){ - foreach ($question->options->subquestions as $subquestion) { - $subquestionchanged = false; - $subquestion->questiontext = question_replace_file_links_in_html($subquestion->questiontext, $fromcourseid, $tocourseid, $url, $destination, $subquestionchanged); - if ($subquestionchanged){//need to update rec in db - $DB->update_record('question_match_sub', $subquestion); - } - } - } - } - /** * Runs all the code required to set up and save an essay question for testing purposes. * Alternate DB table prefix may be used to facilitate data deletion. @@ -544,36 +511,20 @@ class question_match_qtype extends default_questiontype { return $this->save_question($question, $form, $course); } - function move_files($question, $newcategory) { + function move_files($questionid, $oldcontextid, $newcontextid) { global $DB; - // move files belonging to question component - parent::move_files($question, $newcategory); - - // move files belonging to qtype_multichoice $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - // process files in sub questions - if (!$subquestions = $DB->get_records('question_match_sub', array('question' => $question->id), 'id ASC')) { - $subquestions = array(); - } - $component = 'qtype_match'; - $filearea = 'subquestion'; - foreach ($subquestions as $sub) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $sub->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } + parent::move_files($questionid, $oldcontextid, $newcontextid); + + $subquestionids = $DB->get_records_menu('question_match_sub', + array('question' => $questionid), 'id', 'id,1'); + foreach ($subquestionids as $subquestionid => $notused) { + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_match', 'subquestion', $subquestionid); } } + function check_file_access($question, $state, $options, $contextid, $component, $filearea, $args) { diff --git a/question/type/multichoice/edit_multichoice_form.php b/question/type/multichoice/edit_multichoice_form.php index e062fc68126..ed4484c71c8 100644 --- a/question/type/multichoice/edit_multichoice_form.php +++ b/question/type/multichoice/edit_multichoice_form.php @@ -66,7 +66,7 @@ class question_edit_multichoice_form extends question_edit_form { foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) { $mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), - array('course' => $this->coursefilesid), $this->editoroptions); + array('rows' => 10), $this->editoroptions); $mform->setType($feedbackname, PARAM_RAW); } diff --git a/question/type/multichoice/questiontype.php b/question/type/multichoice/questiontype.php index ee3e506f232..88c189bd949 100644 --- a/question/type/multichoice/questiontype.php +++ b/question/type/multichoice/questiontype.php @@ -14,10 +14,6 @@ class question_multichoice_qtype extends default_questiontype { return 'multichoice'; } - function has_html_answers() { - return true; - } - function get_question_options(&$question) { global $DB, $OUTPUT; // Get additional information from database @@ -489,48 +485,6 @@ class question_multichoice_qtype extends default_questiontype { } } - function find_file_links($question, $courseid){ - $urls = array(); - // find links in the answers table. - $urls += question_find_file_links_from_html($question->options->correctfeedback, $courseid); - $urls += question_find_file_links_from_html($question->options->partiallycorrectfeedback, $courseid); - $urls += question_find_file_links_from_html($question->options->incorrectfeedback, $courseid); - foreach ($question->options->answers as $answer) { - $urls += question_find_file_links_from_html($answer->answer, $courseid); - } - //set all the values of the array to the question id - if ($urls){ - $urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id))); - } - $urls = array_merge_recursive($urls, parent::find_file_links($question, $courseid)); - return $urls; - } - - function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){ - global $DB; - parent::replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination); - // replace links in the question_match_sub table. - // We need to use a separate object, because in load_question_options, $question->options->answers - // is changed from a comma-separated list of ids to an array, so calling $DB->update_record on - // $question->options stores 'Array' in that column, breaking the question. - $optionschanged = false; - $newoptions = new stdClass; - $newoptions->id = $question->options->id; - $newoptions->correctfeedback = question_replace_file_links_in_html($question->options->correctfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged); - $newoptions->partiallycorrectfeedback = question_replace_file_links_in_html($question->options->partiallycorrectfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged); - $newoptions->incorrectfeedback = question_replace_file_links_in_html($question->options->incorrectfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged); - if ($optionschanged){ - $DB->update_record('question_multichoice', $newoptions); - } - $answerchanged = false; - foreach ($question->options->answers as $answer) { - $answer->answer = question_replace_file_links_in_html($answer->answer, $fromcourseid, $tocourseid, $url, $destination, $answerchanged); - if ($answerchanged){ - $DB->update_record('question_answers', $answer); - } - } - } - /** * Runs all the code required to set up and save an essay question for testing purposes. * Alternate DB table prefix may be used to facilitate data deletion. @@ -559,48 +513,19 @@ class question_multichoice_qtype extends default_questiontype { return $this->save_question($question, $form, $course); } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - // move files belonging to question component - parent::move_files($question, $newcategory); - // move files belonging to qtype_multichoice + function move_files($questionid, $oldcontextid, $newcontextid) { $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - $component = 'qtype_multichoice'; - foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid, true); + + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_multichoice', 'correctfeedback', $questionid); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_multichoice', 'partiallycorrectfeedback', $questionid); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_multichoice', 'incorrectfeedback', $questionid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index 52cc955774f..6edb3ed011a 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -754,7 +754,7 @@ class question_numerical_qtype extends question_shortanswer_qtype { // The student did type a number, so check it with tolerances. $this->get_tolerance_interval($answer); return ($answer->min <= $response && $response <= $answer->max); - }else { // $question->options->unitgradingtype > 0 + } else { // $question->options->unitgradingtype > 0 /* testing with unitgradingtype $question->options->unitgradingtype > 0 * if the response is at least patially true * if the numerical value agree in the interval @@ -1089,10 +1089,10 @@ class question_numerical_qtype extends question_shortanswer_qtype { } /** - * function used in function definition_inner() - * of edit_..._form.php for - * numerical, calculated, calculatedsimple - */ + * function used in function definition_inner() + * of edit_..._form.php for + * numerical, calculated, calculatedsimple + */ function add_units_options(&$mform, &$that){ // Units are graded $mform->addElement('header', 'unithandling', get_string('unitshandling', 'qtype_numerical')); @@ -1113,10 +1113,9 @@ class question_numerical_qtype extends question_shortanswer_qtype { $mform->addGroup($multichoicedisplaygrp, 'multichoicedisplaygrp', get_string('studentunitanswer', 'qtype_numerical'),' OR ' , false); $unitslefts = array('0' => get_string('rightexample', 'qtype_numerical'),'1' => get_string('leftexample', 'qtype_numerical')); $mform->addElement('select', 'unitsleft', get_string('unitposition', 'qtype_numerical') , $unitslefts ); - + $mform->addElement('static', 'separator2', '
', '
'); - - + $mform->addElement('editor', 'instructions', get_string('instructions', 'qtype_numerical'), null, $that->editoroptions); $showunits1grp = array(); $mform->addElement('static', 'separator2', '
', '
'); @@ -1131,12 +1130,10 @@ class question_numerical_qtype extends question_shortanswer_qtype { $mform->disabledIf('penaltygrp', 'unitrole','eq','0'); $mform->disabledIf('penaltygrp', 'unitrole','eq','1'); $mform->disabledIf('penaltygrp', 'unitrole','eq','2'); - $mform->disabledIf('unitsleft', 'unitrole','eq','0'); - $mform->disabledIf('multichoicedisplay','unitrole','eq','0'); - $mform->disabledIf('multichoicedisplay','unitrole','eq','1'); - $mform->disabledIf('multichoicedisplay','unitrole','eq','2'); - - + $mform->disabledIf('unitsleft', 'unitrole','eq','0'); + $mform->disabledIf('multichoicedisplay','unitrole','eq','0'); + $mform->disabledIf('multichoicedisplay','unitrole','eq','1'); + $mform->disabledIf('multichoicedisplay','unitrole','eq','2'); } /** @@ -1383,44 +1380,15 @@ class question_numerical_qtype extends question_shortanswer_qtype { return $this->save_question($question, $form, $course); } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); + function move_files($questionid, $oldcontextid, $newcontextid) { $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - $component = 'qtype_numerical'; - $filearea = 'instruction'; - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } + + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); + + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'qtype_numerical', 'instruction', $questionid); } function check_file_access($question, $state, $options, $contextid, $component, diff --git a/question/type/questiontype.php b/question/type/questiontype.php index 761a572ed5f..de46af65142 100644 --- a/question/type/questiontype.php +++ b/question/type/questiontype.php @@ -154,14 +154,6 @@ class default_questiontype { return false; } - /** - * @return whether the question_answers.answer field needs to have - * restore_decode_content_links_worker called on it. - */ - function has_html_answers() { - return false; - } - /** * If your question type has a table that extends the question table, and * you want the base class to automatically save, backup and restore the extra fields, @@ -1529,93 +1521,6 @@ class default_questiontype { return format_text($text, $textformat, $formatoptions, $cmoptions === NULL ? NULL : $cmoptions->course); } - /* - * Find all course / site files linked from a question. - * - * Need to check for links to files in question_answers.answer and feedback - * and in question table in generalfeedback and questiontext fields. Methods - * on child classes will also check extra question specific fields. - * - * Needs to be overriden for child classes that have extra fields containing - * html. - * - * @param string html the html to search - * @param int courseid search for files for courseid course or set to siteid for - * finding site files. - * @return array of url, relative url is key and array with one item = question id as value - * relative url is relative to course/site files directory root. - */ - function find_file_links($question, $courseid){ - $urls = array(); - /// Questiontext and general feedback. - $urls += question_find_file_links_from_html($question->questiontext, $courseid); - $urls += question_find_file_links_from_html($question->generalfeedback, $courseid); - - /// Answers, if this question uses them. - if (isset($question->options->answers)){ - foreach ($question->options->answers as $answerkey => $answer){ - /// URLs in the answers themselves, if appropriate. - if ($this->has_html_answers()) { - $urls += question_find_file_links_from_html($answer->answer, $courseid); - } - /// URLs in the answer feedback. - $urls += question_find_file_links_from_html($answer->feedback, $courseid); - } - } - - /// Set all the values of the array to the question object - if ($urls){ - $urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id))); - } - return $urls; - } - /* - * Find all course / site files linked from a question. - * - * Need to check for links to files in question_answers.answer and feedback - * and in question table in generalfeedback and questiontext fields. Methods - * on child classes will also check extra question specific fields. - * - * Needs to be overriden for child classes that have extra fields containing - * html. - * - * @param string html the html to search - * @param int course search for files for courseid course or set to siteid for - * finding site files. - * @return array of files, file name is key and array with one item = question id as value - */ - function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){ - global $CFG, $DB; - $updateqrec = false; - /// Questiontext and general feedback. - $question->questiontext = question_replace_file_links_in_html($question->questiontext, $fromcourseid, $tocourseid, $url, $destination, $updateqrec); - $question->generalfeedback = question_replace_file_links_in_html($question->generalfeedback, $fromcourseid, $tocourseid, $url, $destination, $updateqrec); - - /// If anything has changed, update it in the database. - if ($updateqrec){ - $DB->update_record('question', $question); - } - - - /// Answers, if this question uses them. - if (isset($question->options->answers)){ - //answers that do not need updating have been unset - foreach ($question->options->answers as $answer){ - $answerchanged = false; - /// URLs in the answers themselves, if appropriate. - if ($this->has_html_answers()) { - $answer->answer = question_replace_file_links_in_html($answer->answer, $fromcourseid, $tocourseid, $url, $destination, $answerchanged); - } - /// URLs in the answer feedback. - $answer->feedback = question_replace_file_links_in_html($answer->feedback, $fromcourseid, $tocourseid, $url, $destination, $answerchanged); - /// If anything has changed, update it in the database. - if ($answerchanged){ - $DB->update_record('question_answers', $answer); - } - } - } - } - /** * @return the best link to pass to print_error. * @param $cmoptions as passed in from outside. @@ -1755,31 +1660,39 @@ class default_questiontype { } /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information + * Move all the files belonging to this question from one context to another. + * @param object $question the question to move. + * @param integer $oldcontextid the context it is moving from. + * @param integer $newcontextid the context it is moving to. */ - function move_files($question, $newcategory) { + public function move_files($questionid, $oldcontextid, $newcontextid) { + $fs = get_file_storage(); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'question', 'questiontext', $questionid); + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'question', 'generalfeedback', $questionid); + } + + /** + * + * @param object $question the question to move. + * @param integer $oldcontextid the context it is moving from. + * @param integer $newcontextid the context it is moving to. + * @param boolean $answerstoo whether there is an 'answer' question area, + * as well as an 'answerfeedback' one. Default false. + */ + protected function move_files_in_answers($questionid, $oldcontextid, $newcontextid, $answerstoo = false) { global $DB; $fs = get_file_storage(); - $component = 'question'; - // process general question files - // Currently we have questiontext and generalfeedback areas - foreach (array('questiontext', 'generalfeedback') as $filearea) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - if ($newcategory->contextid == $question->contextid) { - continue; - } - $newfile = new stdClass(); - // only contextid changed - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - // delete old files - $storedfile->delete(); - } + $answerids = $DB->get_records_menu('question_answers', + array('question' => $questionid), 'id', 'id,1'); + foreach ($answerids as $answerid => $notused) { + if ($answerstoo) { + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'question', 'answer', $answerid); } + $fs->move_area_files_to_new_context($oldcontextid, + $newcontextid, 'question', 'answerfeedback', $answerid); } } diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php index 63ebbffe6b0..76eba7b21cb 100644 --- a/question/type/shortanswer/questiontype.php +++ b/question/type/shortanswer/questiontype.php @@ -49,33 +49,9 @@ class question_shortanswer_qtype extends default_questiontype { return 'question'; } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); - - $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } + function move_files($questionid, $oldcontextid, $newcontextid) { + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); } function save_question_options($question) { diff --git a/question/type/truefalse/questiontype.php b/question/type/truefalse/questiontype.php index 7663b0ee308..f4d73e3b893 100644 --- a/question/type/truefalse/questiontype.php +++ b/question/type/truefalse/questiontype.php @@ -257,6 +257,11 @@ class question_truefalse_qtype extends default_questiontype { include("$CFG->dirroot/question/type/truefalse/display.html"); } + function move_files($questionid, $oldcontextid, $newcontextid) { + parent::move_files($questionid, $oldcontextid, $newcontextid); + $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid); + } + function check_file_access($question, $state, $options, $contextid, $component, $filearea, $args) { if ($component == 'question' && $filearea == 'answerfeedback') { @@ -332,34 +337,6 @@ class question_truefalse_qtype extends default_questiontype { return $this->save_question($question, $form, $course); } - /** - * When move the category of questions, the belonging files should be moved as well - * @param object $question, question information - * @param object $newcategory, target category information - */ - function move_files($question, $newcategory) { - global $DB; - parent::move_files($question, $newcategory); - - $fs = get_file_storage(); - // process files in answer - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - $component = 'question'; - $filearea = 'answerfeedback'; - foreach ($oldanswers as $answer) { - $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id); - foreach ($files as $storedfile) { - if (!$storedfile->is_directory()) { - $newfile = new stdClass(); - $newfile->contextid = (int)$newcategory->contextid; - $fs->create_file_from_storedfile($newfile, $storedfile); - $storedfile->delete(); - } - } - } - } } //// END OF CLASS ////