Commit 557554f9 authored by sam marshall's avatar sam marshall
Browse files

MDL-58957 Global search: Add time fields to block_instances

parent 5a651b43
......@@ -1410,8 +1410,9 @@ class backup_block_instance_structure_step extends backup_structure_step {
// Define each element separated
$block = new backup_nested_element('block', array('id', 'contextid', 'version'), array(
'blockname', 'parentcontextid', 'showinsubcontexts', 'pagetypepattern',
'subpagepattern', 'defaultregion', 'defaultweight', 'configdata'));
'blockname', 'parentcontextid', 'showinsubcontexts', 'pagetypepattern',
'subpagepattern', 'defaultregion', 'defaultweight', 'configdata',
'timecreated', 'timemodified'));
$positions = new backup_nested_element('block_positions');
......
......@@ -3937,6 +3937,14 @@ class restore_block_instance_structure_step extends restore_structure_step {
$data->configdata = base64_encode(serialize((object)$configdata));
}
// Set timecreated, timemodified if not included (older backup).
if (empty($data->timecreated)) {
$data->timecreated = time();
}
if (empty($data->timemodified)) {
$data->timemodified = $data->timecreated;
}
// Create the block instance
$newitemid = $DB->insert_record('block_instances', $data);
// Save the mapping (with restorefiles support)
......
......@@ -464,9 +464,10 @@ class core_backup_moodle2_testcase extends advanced_testcase {
*
* @param stdClass $course Course object to backup
* @param int $newdate If non-zero, specifies custom date for new course
* @param callable|null $inbetween If specified, function that is called before restore
* @return int ID of newly restored course
*/
protected function backup_and_restore($course, $newdate = 0) {
protected function backup_and_restore($course, $newdate = 0, $inbetween = null) {
global $USER, $CFG;
// Turn off file logging, otherwise it can't delete the file (Windows).
......@@ -481,6 +482,10 @@ class core_backup_moodle2_testcase extends advanced_testcase {
$bc->execute_plan();
$bc->destroy();
if ($inbetween) {
$inbetween($backupid);
}
// Do restore to new course with default settings.
$newcourseid = restore_dbops::create_new_course(
$course->fullname, $course->shortname . '_2', $course->category);
......@@ -802,4 +807,64 @@ class core_backup_moodle2_testcase extends advanced_testcase {
$enrolment = reset($enrolments);
$this->assertEquals('self', $enrolment->enrol);
}
/**
* Test the block instance time fields (timecreated, timemodified) through a backup and restore.
*/
public function test_block_instance_times_backup() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$generator = $this->getDataGenerator();
// Create course and add HTML block.
$course = $generator->create_course();
$context = context_course::instance($course->id);
$page = new moodle_page();
$page->set_context($context);
$page->set_course($course);
$page->set_pagelayout('standard');
$page->set_pagetype('course-view');
$page->blocks->load_blocks();
$page->blocks->add_block_at_end_of_default_region('html');
// Update (hack in database) timemodified and timecreated to specific values for testing.
$blockdata = $DB->get_record('block_instances',
['blockname' => 'html', 'parentcontextid' => $context->id]);
$originalblockid = $blockdata->id;
$blockdata->timecreated = 12345;
$blockdata->timemodified = 67890;
$DB->update_record('block_instances', $blockdata);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
// Confirm that values were transferred correctly into HTML block on new course.
$newcontext = context_course::instance($newcourseid);
$blockdata = $DB->get_record('block_instances',
['blockname' => 'html', 'parentcontextid' => $newcontext->id]);
$this->assertEquals(12345, $blockdata->timecreated);
$this->assertEquals(67890, $blockdata->timemodified);
// Simulate what happens with an older backup that doesn't have those fields, by removing
// them from the backup before doing a restore.
$before = time();
$newcourseid = $this->backup_and_restore($course, 0, function($backupid) use($originalblockid) {
global $CFG;
$path = $CFG->dataroot . '/temp/backup/' . $backupid . '/course/blocks/html_' .
$originalblockid . '/block.xml';
$xml = file_get_contents($path);
$xml = preg_replace('~<timecreated>.*?</timemodified>~s', '', $xml);
file_put_contents($path, $xml);
});
$after = time();
// The fields not specified should default to current time.
$newcontext = context_course::instance($newcourseid);
$blockdata = $DB->get_record('block_instances',
['blockname' => 'html', 'parentcontextid' => $newcontext->id]);
$this->assertTrue($before <= $blockdata->timecreated && $after >= $blockdata->timecreated);
$this->assertTrue($before <= $blockdata->timemodified && $after >= $blockdata->timemodified);
}
}
......@@ -104,7 +104,8 @@ function block_html_global_db_replace($search, $replace) {
$config = unserialize(base64_decode($instance->configdata));
if (isset($config->text) and is_string($config->text)) {
$config->text = str_replace($search, $replace, $config->text);
$DB->set_field('block_instances', 'configdata', base64_encode(serialize($config)), array('id' => $instance->id));
$DB->update_record('block_instances', ['id' => $instance->id,
'configdata' => base64_encode(serialize($config)), 'timemodified' => time()]);
}
}
$instances->close();
......
......@@ -474,8 +474,8 @@ class block_base {
*/
function instance_config_save($data, $nolongerused = false) {
global $DB;
$DB->set_field('block_instances', 'configdata', base64_encode(serialize($data)),
array('id' => $this->instance->id));
$DB->update_record('block_instances', ['id' => $this->instance->id,
'configdata' => base64_encode(serialize($data)), 'timemodified' => time()]);
}
/**
......
This files describes API changes in /blocks/* - activity modules,
information provided here is intended especially for developers.
=== 3.4 ===
* The block_instances table now contains fields timecreated and timemodified. If third-party code
creates or updates these rows (without using the standard API), it should be modified to set
these fields as appropriate.
=== 3.3 ===
* block_manager::get_required_by_theme_block_types() is no longer static.
......
......@@ -833,6 +833,8 @@ class block_manager {
$blockinstance->defaultregion = $region;
$blockinstance->defaultweight = $weight;
$blockinstance->configdata = '';
$blockinstance->timecreated = time();
$blockinstance->timemodified = $blockinstance->timecreated;
$blockinstance->id = $DB->insert_record('block_instances', $blockinstance);
// Ensure the block context is created.
......@@ -940,6 +942,7 @@ class block_manager {
$newbi->id = $bi->id;
$newbi->defaultregion = $newregion;
$newbi->defaultweight = $newweight;
$newbi->timemodified = time();
$DB->update_record('block_instances', $newbi);
if ($bi->blockpositionid) {
......@@ -1162,6 +1165,8 @@ class block_manager {
$blockinstance->defaultregion = $defaultregion;
$blockinstance->defaultweight = 0;
$blockinstance->configdata = '';
$blockinstance->timecreated = time();
$blockinstance->timemodified = $blockinstance->timecreated;
$blockinstance->id = $DB->insert_record('block_instances', $blockinstance);
// Ensure the block context is created.
......@@ -1723,6 +1728,7 @@ class block_manager {
$bi->defaultregion = $data->bui_defaultregion;
$bi->defaultweight = $data->bui_defaultweight;
$bi->timemodified = time();
$DB->update_record('block_instances', $bi);
if (!empty($block->config)) {
......
......@@ -2493,6 +2493,8 @@
<FIELD NAME="defaultregion" TYPE="char" LENGTH="16" NOTNULL="true" SEQUENCE="false" COMMENT="Which block region this block should appear in on each page, in the absence of a specific position in the block_positions table."/>
<FIELD NAME="defaultweight" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Used to order the blocks within a block region. Again, may be overridden by the block_positions table for a specific page where this block appears."/>
<FIELD NAME="configdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="A serialized blob of configuration data for this block instance."/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time at which this block instance was originally created"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time at which block instance was last modified."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
......@@ -2500,6 +2502,7 @@
</KEYS>
<INDEXES>
<INDEX NAME="parentcontextid-showinsubcontexts-pagetypepattern-subpagepattern" UNIQUE="false" FIELDS="parentcontextid, showinsubcontexts, pagetypepattern, subpagepattern"/>
<INDEX NAME="timemodified" UNIQUE="false" FIELDS="timemodified"/>
</INDEXES>
</TABLE>
<TABLE NAME="block_positions" COMMENT="Stores the position of a sticky block_instance on a another page than the one where it was added.">
......
......@@ -2887,5 +2887,58 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2017061301.00);
}
if ($oldversion < 2017062900.01) {
// Define field timemodified to be added to block_instances.
$table = new xmldb_table('block_instances');
$field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null,
null, null, 'configdata');
// Conditionally launch add field timemodified.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
// Set field to current time.
$DB->set_field('block_instances', 'timemodified', time());
// Changing nullability of field timemodified on table block_instances to not null.
$field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL,
null, null, 'configdata');
// Launch change of nullability for field timemodified.
$dbman->change_field_notnull($table, $field);
// Define index timemodified (not unique) to be added to block_instances.
$index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
// Conditionally launch add index timemodified.
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
}
// Define field timecreated to be added to block_instances.
$field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null,
null, null, 'configdata');
// Conditionally launch add field timecreated.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
// Set field to current time.
$DB->set_field('block_instances', 'timecreated', time());
// Changing nullability of field timecreated on table block_instances to not null.
$field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL,
null, null, 'configdata');
// Launch change of nullability for field timecreated.
$dbman->change_field_notnull($table, $field);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2017062900.01);
}
return true;
}
......@@ -122,6 +122,13 @@ abstract class testing_block_generator extends component_generator_base {
$this->preprocess_record($record, $options);
$record = $this->prepare_record($record);
if (empty($record->timecreated)) {
$record->timecreated = time();
}
if (empty($record->timemodified)) {
$record->timemodified = time();
}
$id = $DB->insert_record('block_instances', $record);
context_block::instance($id);
......
......@@ -622,6 +622,72 @@ class core_blocklib_testcase extends advanced_testcase {
}
}
/**
* Test the block instance time fields (timecreated, timemodified).
*/
public function test_block_instance_times() {
global $DB;
$this->purge_blocks();
// Set up fixture.
$regionname = 'a-region';
$blockname = 'html';
$context = context_system::instance();
list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
$context, 'page-type');
// Add block to page.
$before = time();
$blockmanager->add_block($blockname, $regionname, 0, false);
$after = time();
// Check database table to ensure it contains created/modified times.
$blockdata = $DB->get_record('block_instances', ['blockname' => 'html']);
$this->assertTrue($blockdata->timemodified >= $before && $blockdata->timemodified <= $after);
$this->assertTrue($blockdata->timecreated >= $before && $blockdata->timecreated <= $after);
// Get block from manager.
$blockmanager->load_blocks();
$blocks = $blockmanager->get_blocks_for_region($regionname);
$block = reset($blocks);
// Wait until at least the next second.
while (time() === $after) {
usleep(100000);
}
// Update block settings.
$this->setAdminUser();
$data = (object)['text' => ['text' => 'New text', 'itemid' => 0, 'format' => FORMAT_HTML]];
$before = time();
$block->instance_config_save($data);
$after = time();
// Check time modified updated, but time created didn't.
$newblockdata = $DB->get_record('block_instances', ['blockname' => 'html']);
$this->assertTrue(
$newblockdata->timemodified >= $before &&
$newblockdata->timemodified <= $after &&
$newblockdata->timemodified > $blockdata->timemodified);
$this->assertEquals($blockdata->timecreated, $newblockdata->timecreated);
// Also try repositioning the block.
while (time() === $after) {
usleep(100000);
}
$before = time();
$blockmanager->reposition_block($blockdata->id, $regionname, 10);
$after = time();
$blockdata = $newblockdata;
$newblockdata = $DB->get_record('block_instances', ['blockname' => 'html']);
$this->assertTrue(
$newblockdata->timemodified >= $before &&
$newblockdata->timemodified <= $after &&
$newblockdata->timemodified > $blockdata->timemodified);
$this->assertEquals($blockdata->timecreated, $newblockdata->timecreated);
}
}
/**
......
......@@ -86,6 +86,8 @@ function my_copy_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index') {
unset($instance->id);
$instance->parentcontextid = $usercontext->id;
$instance->subpagepattern = $page->id;
$instance->timecreated = time();
$instance->timemodified = $instance->timecreated;
$instance->id = $DB->insert_record('block_instances', $instance);
$newblockinstanceids[$originalid] = $instance->id;
$blockcontext = context_block::instance($instance->id); // Just creates the context record
......
......@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2017062900.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2017062900.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment