/** * Move a slot from its current location to a new location. * * After callig this method, this class will be in an invalid state, and * should be discarded if you want to manipulate the structure further. * * @param int $idmove id of slot to be moved * @param int $idbefore id of slot to come before slot being moved * @param int $page new page number of slot being moved * @return void */ public function move_slot($idmove, $idbefore, $page) { global $DB; $this->check_can_be_edited(); $movingslot = $this->slots[$idmove]; if (empty($movingslot)) { throw new moodle_exception('Bad slot ID ' . $idmove); } $movingslotnumber = (int) $movingslot->slot; // Empty target slot means move slot to first. if (empty($idbefore)) { $targetslotnumber = 0; } else { $targetslotnumber = (int) $this->slots[$idbefore]->slot; } // Work out how things are being moved. $slotreorder = array(); if ($targetslotnumber > $movingslotnumber) { $slotreorder[$movingslotnumber] = $targetslotnumber; for ($i = $movingslotnumber; $i < $targetslotnumber; $i++) { $slotreorder[$i + 1] = $i; } } else { if ($targetslotnumber < $movingslotnumber - 1) { $slotreorder[$movingslotnumber] = $targetslotnumber + 1; for ($i = $targetslotnumber + 1; $i < $movingslotnumber; $i++) { $slotreorder[$i] = $i + 1; } } } $trans = $DB->start_delegated_transaction(); // Slot has moved record new order. if ($slotreorder) { update_field_with_unique_index('quiz_slots', 'slot', $slotreorder, array('quizid' => $this->get_quizid())); } // Page has changed. Record it. if (!$page) { $page = 1; } if ($movingslot->page != $page) { $DB->set_field('quiz_slots', 'page', $page, array('id' => $movingslot->id)); } $emptypages = $DB->get_fieldset_sql("\n SELECT DISTINCT page - 1\n FROM {quiz_slots} slot\n WHERE quizid = ?\n AND page > 1\n AND NOT EXISTS (SELECT 1 FROM {quiz_slots} WHERE quizid = ? AND page = slot.page - 1)\n ORDER BY page - 1 DESC\n ", array($this->get_quizid(), $this->get_quizid())); foreach ($emptypages as $page) { $DB->execute("\n UPDATE {quiz_slots}\n SET page = page - 1\n WHERE quizid = ?\n AND page > ?\n ", array($this->get_quizid(), $page)); } $trans->allow_commit(); }
public function test_reorder_rows() { global $DB; $dbman = $DB->get_manager(); $this->resetAfterTest(); $table = new xmldb_table('test_table'); $table->setComment("This is a test'n drop table. You can drop it safely"); $tablename = $table->getName(); $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('otherid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); $table->add_field('otherdata', XMLDB_TYPE_TEXT, 'big', null, null, null); $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('unique', XMLDB_KEY_UNIQUE, array('otherid', 'sortorder')); $dbman->create_table($table); // Rows intentionally added in a slightly 'random' order. // Note we are testing hat the otherid = 1 rows don't get messed up, // as well as testing that the otherid = 2 rows are updated correctly. $DB->insert_record($tablename, array('otherid' => 2, 'sortorder' => 1, 'otherdata' => 'To become 4')); $DB->insert_record($tablename, array('otherid' => 2, 'sortorder' => 2, 'otherdata' => 'To become 1')); $DB->insert_record($tablename, array('otherid' => 1, 'sortorder' => 1, 'otherdata' => 'Other 1')); $DB->insert_record($tablename, array('otherid' => 1, 'sortorder' => 2, 'otherdata' => 'Other 2')); $DB->insert_record($tablename, array('otherid' => 2, 'sortorder' => 3, 'otherdata' => 'To stay at 3')); $DB->insert_record($tablename, array('otherid' => 2, 'sortorder' => 4, 'otherdata' => 'To become 2')); update_field_with_unique_index($tablename, 'sortorder', array(1 => 4, 2 => 1, 3 => 3, 4 => 2), array('otherid' => 2)); $this->assertEquals(array(3 => (object) array('id' => 3, 'otherid' => 1, 'sortorder' => 1, 'otherdata' => 'Other 1'), 4 => (object) array('id' => 4, 'otherid' => 1, 'sortorder' => 2, 'otherdata' => 'Other 2')), $DB->get_records($tablename, array('otherid' => 1), 'sortorder')); $this->assertEquals(array(2 => (object) array('id' => 2, 'otherid' => 2, 'sortorder' => 1, 'otherdata' => 'To become 1'), 6 => (object) array('id' => 6, 'otherid' => 2, 'sortorder' => 2, 'otherdata' => 'To become 2'), 5 => (object) array('id' => 5, 'otherid' => 2, 'sortorder' => 3, 'otherdata' => 'To stay at 3'), 1 => (object) array('id' => 1, 'otherid' => 2, 'sortorder' => 4, 'otherdata' => 'To become 4')), $DB->get_records($tablename, array('otherid' => 2), 'sortorder')); }
/** * Move a slot from its current location to a new location. * * After callig this method, this class will be in an invalid state, and * should be discarded if you want to manipulate the structure further. * * @param int $idmove id of slot to be moved * @param int $idmoveafter id of slot to come before slot being moved * @param int $page new page number of slot being moved * @param bool $insection if the question is moving to a place where a new * section starts, include it in that section. * @return void */ public function move_slot($idmove, $idmoveafter, $page) { global $DB; $this->check_can_be_edited(); $movingslot = $this->slots[$idmove]; if (empty($movingslot)) { throw new \moodle_exception('Bad slot ID ' . $idmove); } $movingslotnumber = (int) $movingslot->slot; // Empty target slot means move slot to first. if (empty($idmoveafter)) { $moveafterslotnumber = 0; } else { $moveafterslotnumber = (int) $this->slots[$idmoveafter]->slot; } // Check the target page number is OK. if ($page == 0) { $page = 1; } if ($moveafterslotnumber > 0 && $page < $this->get_page_number_for_slot($moveafterslotnumber) || $page < 1) { throw new \coding_exception('The target page number is too small.'); } else { if (!$this->is_last_slot_in_quiz($moveafterslotnumber) && $page > $this->get_page_number_for_slot($moveafterslotnumber + 1)) { throw new \coding_exception('The target page number is too large.'); } } // If the action came in as moving a slot to itself, normalise this to // moving the slot to after the previosu slot. if ($moveafterslotnumber == $movingslotnumber) { $moveafterslotnumber = $moveafterslotnumber - 1; } // Work out how things are being moved. $slotreorder = array(); if ($moveafterslotnumber > $movingslotnumber) { // Moving down. $slotreorder[$movingslotnumber] = $moveafterslotnumber; for ($i = $movingslotnumber; $i < $moveafterslotnumber; $i++) { $slotreorder[$i + 1] = $i; } $headingmoveafter = $movingslotnumber; if ($this->is_last_slot_in_quiz($moveafterslotnumber) || $page == $this->get_page_number_for_slot($moveafterslotnumber + 1)) { // We are moving to the start of a section, so that heading needs // to be included in the ones that move up. $headingmovebefore = $moveafterslotnumber + 1; } else { $headingmovebefore = $moveafterslotnumber; } $headingmovedirection = -1; } else { if ($moveafterslotnumber < $movingslotnumber - 1) { // Moving up. $slotreorder[$movingslotnumber] = $moveafterslotnumber + 1; for ($i = $moveafterslotnumber + 1; $i < $movingslotnumber; $i++) { $slotreorder[$i] = $i + 1; } if ($page == $this->get_page_number_for_slot($moveafterslotnumber + 1)) { // Moving to the start of a section, don't move that section. $headingmoveafter = $moveafterslotnumber + 1; } else { // Moving tot the end of the previous section, so move the heading down too. $headingmoveafter = $moveafterslotnumber; } $headingmovebefore = $movingslotnumber + 1; $headingmovedirection = 1; } else { // Staying in the same place, but possibly changing page/section. if ($page > $movingslot->page) { $headingmoveafter = $movingslotnumber; $headingmovebefore = $movingslotnumber + 2; $headingmovedirection = -1; } else { $headingmoveafter = $movingslotnumber - 1; $headingmovebefore = $movingslotnumber + 1; $headingmovedirection = 1; } } } if ($this->is_only_slot_in_section($movingslotnumber)) { throw new \coding_exception('You cannot remove the last slot in a section.'); } $trans = $DB->start_delegated_transaction(); // Slot has moved record new order. if ($slotreorder) { update_field_with_unique_index('quiz_slots', 'slot', $slotreorder, array('quizid' => $this->get_quizid())); } // Page has changed. Record it. if ($movingslot->page != $page) { $DB->set_field('quiz_slots', 'page', $page, array('id' => $movingslot->id)); } // Update section fist slots. $DB->execute("\n UPDATE {quiz_sections}\n SET firstslot = firstslot + ?\n WHERE quizid = ?\n AND firstslot > ?\n AND firstslot < ?\n ", array($headingmovedirection, $this->get_quizid(), $headingmoveafter, $headingmovebefore)); // If any pages are now empty, remove them. $emptypages = $DB->get_fieldset_sql("\n SELECT DISTINCT page - 1\n FROM {quiz_slots} slot\n WHERE quizid = ?\n AND page > 1\n AND NOT EXISTS (SELECT 1 FROM {quiz_slots} WHERE quizid = ? AND page = slot.page - 1)\n ORDER BY page - 1 DESC\n ", array($this->get_quizid(), $this->get_quizid())); foreach ($emptypages as $page) { $DB->execute("\n UPDATE {quiz_slots}\n SET page = page - 1\n WHERE quizid = ?\n AND page > ?\n ", array($this->get_quizid(), $page)); } $trans->allow_commit(); }
ksort($newslotorder); $currentpage = 1; $currentslot = 1; $slotreorder = array(); $slotpages = array(); foreach ($newslotorder as $slotnumber) { if ($slotnumber == 0) { $currentpage += 1; continue; } $slotreorder[$slotnumber] = $currentslot; $slotpages[$currentslot] = $currentpage; $currentslot += 1; } $trans = $DB->start_delegated_transaction(); update_field_with_unique_index('quiz_slots', 'slot', $slotreorder, array('quizid' => $quiz->id)); foreach ($slotpages as $slotnumber => $page) { $DB->set_field('quiz_slots', 'page', $page, array('quizid' => $quiz->id, 'slot' => $slotnumber)); } $trans->allow_commit(); $deletepreviews = true; } // If rescaling is required save the new maximum. $maxgrade = unformat_float(optional_param('maxgrade', -1, PARAM_RAW)); if ($maxgrade >= 0) { quiz_set_grade($maxgrade, $quiz); } if ($deletepreviews) { quiz_delete_previews($quiz);