diff --git a/backup/backuplib.php b/backup/backuplib.php index 150526a720c..d5043575502 100644 --- a/backup/backuplib.php +++ b/backup/backuplib.php @@ -929,27 +929,31 @@ $pages = array(); $pages[] = page_create_object(PAGE_COURSE_VIEW, $preferences->backup_course); - // Let's see if we have to backup blocks from modules - $modulerecords = get_records_sql('SELECT name, id FROM '.$CFG->prefix.'modules'); + if (!empty($CFG->showblocksonmodpages)) { + // get course structure + $course = get_record('course', 'id', $preferences->backup_course); + $modinfo =& get_fast_modinfo($course); - foreach($preferences->mods as $module) { - if(!$module->backup) { - continue; - } + foreach($preferences->mods as $module) { + if (!$module->backup) { + continue; + } - $cmods = get_records_select('course_modules', 'course = '.$preferences->backup_course.' AND module = '.$modulerecords[$module->name]->id); - if(empty($cmods)) { - continue; - } + if (empty($modinfo->instances[$module->name])) { + continue; + } - $pagetypes = page_import_types('mod/'.$module->name.'/'); - if(empty($pagetypes)) { - continue; - } + $pagetypes = page_import_types('mod/'.$module->name.'/'); + if (empty($pagetypes)) { + continue; + } - foreach($pagetypes as $pagetype) { - foreach($cmods as $cmod) { - $pages[] = page_create_object($pagetype, $cmod->instance); + foreach($pagetypes as $pagetype) { + foreach($modinfo->instances[$module->name] as $cm) { + if (!empty($module->instances[$cm->instance]->backup)) { + $pages[] = page_create_object($pagetype, $cm->instance); + } + } } } } @@ -957,7 +961,7 @@ //Blocks open tag fwrite ($bf,start_tag('BLOCKS',2,true)); - while($page = array_pop($pages)) { + foreach($pages as $page) { if ($instances = blocks_get_by_page($page)) { //Iterate over every block foreach ($instances as $position) { @@ -967,26 +971,32 @@ if(empty($blocks[$instance->blockid]->name)) { continue; } + $blockname = $blocks[$instance->blockid]->name; - //Give the block a chance to process any links in configdata. - if (!isset($blocks[$instance->blockid]->blockobject)) { - $blocks[$instance->blockid]->blockobject = block_instance($blocks[$instance->blockid]->name); + if (!$blockobj = block_instance($blockname, $instance)) { + // Invalid block + continue; } - $config = unserialize(base64_decode($instance->configdata)); - $blocks[$instance->blockid]->blockobject->backup_encode_absolute_links_in_config($config); - $instance->configdata = base64_encode(serialize($config)); + + // encode absolute links in block config + $instance->configdata = $blockobj->get_backup_encoded_config(); //Begin Block fwrite ($bf,start_tag('BLOCK',3,true)); fwrite ($bf,full_tag('ID', 4, false,$instance->id)); - fwrite ($bf,full_tag('NAME',4,false,$blocks[$instance->blockid]->name)); + fwrite ($bf,full_tag('NAME',4,false,$blockname)); fwrite ($bf,full_tag('PAGEID',4,false,$instance->pageid)); fwrite ($bf,full_tag('PAGETYPE',4,false,$instance->pagetype)); fwrite ($bf,full_tag('POSITION',4,false,$instance->position)); fwrite ($bf,full_tag('WEIGHT',4,false,$instance->weight)); fwrite ($bf,full_tag('VISIBLE',4,false,$instance->visible)); fwrite ($bf,full_tag('CONFIGDATA',4,false,$instance->configdata)); - + // Write instance data if needed + if ($blockobj->backuprestore_instancedata_used()) { + fwrite ($bf,start_tag('INSTANCEDATA',4,true)); + $status = $blockobj->instance_backup($bf, $preferences); + fwrite ($bf,end_tag('INSTANCEDATA',4,true)); + } $context = get_context_instance(CONTEXT_BLOCK, $instance->id); write_role_overrides_xml($bf, $context, 4); /// write role_assign code here @@ -1484,7 +1494,7 @@ JOIN {$CFG->prefix}grade_items gi ON (gi.iteminstance = gc.id) WHERE gc.courseid = $preferences->backup_course - AND (gi.itemtype='course' OR gi.itemtype='category') + AND (gi.itemtype='course' OR gi.itemtype='category') ORDER BY gi.sortorder ASC"); if ($grade_categories) { @@ -2227,6 +2237,25 @@ } } + // For each block, call its encode_content_links method. + // This encodes forexample links to blocks/something/viewphp?id=666 + // that are stored in other activities. + static $blockobjects = null; + if (!isset($blockobjects)) { + $blockobjects = array(); + if ($blocks = get_records('block', 'visible', 1)) { + foreach ($blocks as $block) { + if ($blockobject = block_instance($block->name)) { + $blockobjects[] = $blockobject; + } + } + } + } + + foreach ($blockobjects as $blockobject) { + $result = $blockobject->encode_content_links($result,$mypreferences); + } + if ($result != $content) { debugging('

'.s($content).'
changed to
'.s($result).'

'); } diff --git a/backup/restorelib.php b/backup/restorelib.php index 45a6f5d4651..09b0e47f4b8 100644 --- a/backup/restorelib.php +++ b/backup/restorelib.php @@ -104,7 +104,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); if (!defined('RESTORE_SILENTLY')) { echo "
  • ".get_string ("from")." ".get_string("modulenameplural",$name); } - $status = $function_name($restore); + $status = $function_name($restore) && $status; if (!defined('RESTORE_SILENTLY')) { echo '
  • '; } @@ -114,22 +114,16 @@ define('RESTORE_GROUPS_GROUPINGS', 3); // Process all html text also in blocks too if (!defined('RESTORE_SILENTLY')) { - echo '
  • ' . get_string ('from') . ' ' . get_string('blocks'); + echo '
  • '.get_string ('from').' '.get_string('blocks'); } - if (!empty($restore->blockinstanceids)) { - $blocks = blocks_get_record(); - $instances = get_records_list('block_instance', 'id', implode(',', $restore->blockinstanceids), '', 'id,blockid,configdata'); - foreach ($instances as $instance) { - if (!isset($blocks[$instance->blockid]->blockobject)) { - $blocks[$instance->blockid]->blockobject = block_instance($blocks[$instance->blockid]->name); - } - $config = unserialize(base64_decode($instance->configdata)); - if ($blocks[$instance->blockid]->blockobject->restore_decode_absolute_links_in_config($config)) { - $instance->configdata = base64_encode(serialize($config)); - $status = $status && update_record('block_instance', $instance); - } + + if ($blocks = get_records('block', 'visible', 1)) { + foreach ($blocks as $block) { + $blockobject = block_instance($block->name); + $blockobject->decode_content_links_caller($restore); } } + if (!defined('RESTORE_SILENTLY')) { echo '
  • '; } @@ -139,7 +133,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); if (!defined('RESTORE_SILENTLY')) { echo '
  • ' . get_string('from') . ' ' . get_string('questions', 'quiz'); } - $status = question_decode_content_links_caller($restore); + $status = question_decode_content_links_caller($restore) && $status; if (!defined('RESTORE_SILENTLY')) { echo '
  • '; } @@ -161,6 +155,24 @@ define('RESTORE_GROUPS_GROUPINGS', 3); $content = $function_name($content,$restore); } } + + // For each block, call its encode_content_links method + static $blockobjects = null; + if (!isset($blockobjects)) { + $blockobjects = array(); + if ($blocks = get_records('block', 'visible', 1)) { + foreach ($blocks as $block) { + if ($blockobject = block_instance($block->name)) { + $blockobjects[] = $blockobject; + } + } + } + } + + foreach ($blockobjects as $blockobject) { + $content = $blockobject->decode_content_links($content,$restore); + } + return $content; } @@ -248,10 +260,10 @@ define('RESTORE_GROUPS_GROUPINGS', 3); } //This function read the xml file and store its data from the blocks in a object - function restore_read_xml_blocks ($xml_file) { + function restore_read_xml_blocks ($restore, $xml_file) { //We call the main read_xml function, with todo = BLOCKS - $info = restore_read_xml ($xml_file,'BLOCKS',false); + $info = restore_read_xml ($xml_file,'BLOCKS',$restore); return $info; } @@ -762,7 +774,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); // Looks like it's from Moodle < 1.3. Let's give the course default blocks... $newpage = page_create_object(PAGE_COURSE_VIEW, $restore->course_id); blocks_repopulate_page($newpage); - } else { + } else if (!empty($CFG->showblocksonmodpages)) { // We just have a blockinfo field, this is a legacy 1.4 or 1.3 backup $blockrecords = get_records_select('block', '', '', 'name, id'); $temp_blocks_l = array(); @@ -810,17 +822,13 @@ define('RESTORE_GROUPS_GROUPINGS', 3); $status = true; - // Tracks which blocks we create during the restore. - // This is used in restore_decode_content_links. - $restore->blockinstanceids = array(); - //Check it exists if (!file_exists($xml_file)) { $status = false; } //Get info from xml if ($status) { - $info = restore_read_xml_blocks($xml_file); + $info = restore_read_xml_blocks($restore,$xml_file); } if(empty($info->instances)) { @@ -838,8 +846,8 @@ define('RESTORE_GROUPS_GROUPINGS', 3); if($instance->pagetype == PAGE_COURSE_VIEW) { // This one's easy... $instance->pageid = $restore->course_id; - } - else { + + } else if (!empty($CFG->showblocksonmodpages)) { $parts = explode('-', $instance->pagetype); if($parts[0] == 'mod') { if(!$restore->mods[$parts[1]]->restore) { @@ -857,6 +865,10 @@ define('RESTORE_GROUPS_GROUPINGS', 3); // Not invented here ;-) continue; } + + } else { + // do not restore activity blocks if disabled + continue; } if(!isset($pageinstances[$instance->pagetype])) { @@ -869,7 +881,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); $pageinstances[$instance->pagetype][$instance->pageid][] = $instance; } - $blocks = get_records_select('block', '', '', 'name, id, multiple'); + $blocks = get_records_select('block', 'visible = 1', '', 'name, id, multiple'); // For each type of page we have restored foreach($pageinstances as $thistypeinstances) { @@ -907,11 +919,35 @@ define('RESTORE_GROUPS_GROUPINGS', 3); //Add this instance $instance->blockid = $blocks[$instance->name]->id; - if ($newid = insert_record('block_instance', $instance)) { - if (!empty($instance->id)) { // this will only be set if we come from 1.7 and above backups - backup_putid ($restore->backup_unique_code,"block_instance",$instance->id,$newid); + // This will only be set if we come from 1.7 and above backups + // Also, must do this before insert (insert_record unsets id) + if (!empty($instance->id)) { + $oldid = $instance->id; + } else { + $oldid = 0; + } + + if ($instance->id = insert_record('block_instance', $instance)) { + // Create block instance + if (!$blockobj = block_instance($instance->name, $instance)) { + $status = false; + break; } - $restore->blockinstanceids[] = $newid; + // Run the block restore if needed + if ($blockobj->backuprestore_instancedata_used()) { + // Get restore information + $data = backup_getid($restore->backup_unique_code,'block_instance',$oldid); + $data->new_id = $instance->id; // For completeness + if (!$blockobj->instance_restore($restore, $data)) { + $status = false; + break; + } + } + // Save oldid after block restore process because info will be over-written with blank string + if ($oldid) { + backup_putid ($restore->backup_unique_code,"block_instance",$oldid,$instance->id); + } + } else { $status = false; break; @@ -919,8 +955,9 @@ define('RESTORE_GROUPS_GROUPINGS', 3); //Get an object for the block and tell it it's been restored so it can update dates //etc. if necessary - $blockobj=block_instance($instance->name,$instance); - $blockobj->after_restore($restore); + if ($blockobj = block_instance($instance->name,$instance)) { + $blockobj->after_restore($restore); + } //Now we can increment the weight counter ++$maxweights[$instance->position]; @@ -4286,6 +4323,16 @@ define('RESTORE_GROUPS_GROUPINGS', 3); //Check if we are into BLOCKS zone //if ($this->tree[3] == "BLOCKS") //Debug // echo $this->level.str_repeat(" ",$this->level*2)."<".$tagName.">
    \n"; //Debug + + //If we are under a BLOCK tag under a BLOCKS zone, accumule it + if (isset($this->tree[4]) and isset($this->tree[3])) { // + if ($this->tree[4] == "BLOCK" and $this->tree[3] == "BLOCKS") { + if (!isset($this->temp)) { + $this->temp = ""; + } + $this->temp .= "<".$tagName.">"; + } + } } //This is the startTag handler we use where we are reading the sections zone (todo="SECTIONS") @@ -5077,6 +5124,13 @@ define('RESTORE_GROUPS_GROUPINGS', 3); //if (trim($this->content)) //Debug // echo "C".str_repeat(" ",($this->level+2)*2).$this->getContents()."
    \n"; //Debug //echo $this->level.str_repeat(" ",$this->level*2)."</".$tagName.">
    \n"; //Debug + + // Collect everything into $this->temp + if (!isset($this->temp)) { + $this->temp = ""; + } + $this->temp .= htmlspecialchars(trim($this->content)).""; + //Dependig of different combinations, do different things if ($this->level == 4) { switch ($tagName) { @@ -5084,6 +5138,37 @@ define('RESTORE_GROUPS_GROUPINGS', 3); //We've finalized a block, get it $this->info->instances[] = $this->info->tempinstance; unset($this->info->tempinstance); + + //Also, xmlize INSTANCEDATA and save to db + //Prepend XML standard header to info gathered + $xml_data = "\n".$this->temp; + //Call to xmlize for this portion of xml data (one BLOCK) + //echo "-XMLIZE: ".strftime ("%X",time()),"-"; //Debug + $data = xmlize($xml_data,0); + //echo strftime ("%X",time())."

    "; //Debug + //traverse_xmlize($data); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + //Check for instancedata, is exists, then save to DB + if (isset($data['BLOCK']['#']['INSTANCEDATA']['0']['#'])) { + //Get old id + $oldid = $data['BLOCK']['#']['ID']['0']['#']; + //Get instancedata + + if ($data = $data['BLOCK']['#']['INSTANCEDATA']['0']['#']) { + //Restore code calls this multiple times - so might already have the newid + if ($newid = backup_getid($this->preferences->backup_unique_code,'block_instance',$oldid)) { + $newid = $newid->new_id; + } else { + $newid = null; + } + //Save to DB, we will use it later + $status = backup_putid($this->preferences->backup_unique_code,'block_instance',$oldid,$newid,$data); + } + } + //Reset temp + unset($this->temp); + break; default: die($tagName); @@ -8105,7 +8190,7 @@ define('RESTORE_GROUPS_GROUPINGS', 3); if (!defined('RESTORE_SILENTLY')) { echo "

  • ".get_string("creatingblocksroles").'
  • '; } - $blocks = restore_read_xml_blocks($xmlfile); + $blocks = restore_read_xml_blocks($restore, $xmlfile); if (isset($blocks->instances)) { foreach ($blocks->instances as $instance) { if (isset($instance->roleassignments) && !$isimport) { diff --git a/blocks/html/block_html.php b/blocks/html/block_html.php index 8e610049fe8..f0a60ef8b8b 100755 --- a/blocks/html/block_html.php +++ b/blocks/html/block_html.php @@ -36,14 +36,51 @@ class block_html extends block_base { return $this->content; } - function backup_encode_absolute_links_in_config(&$config) { - $config->text = backup_encode_absolute_links($config->text); + /** + * Will be called before an instance of this block is backed up, so that any links in + * any links in any HTML fields on config can be encoded. + * @return string + */ + function get_backup_encoded_config() { + $data = clone($this->config); + $data->text = backup_encode_absolute_links($data->text); + return base64_encode(serialize($data)); } - function restore_decode_absolute_links_in_config(&$config) { - $oldtext = $config->text; - $config->text = restore_decode_absolute_links($oldtext); - return $config->text != $oldtext; + /** + * This function makes all the necessary calls to {@link restore_decode_content_links_worker()} + * function in order to decode contents of this block from the backup + * format to destination site/course in order to mantain inter-activities + * working in the backup/restore process. + * + * This is called from {@link restore_decode_content_links()} function in the restore process. + * + * NOTE: There is no block instance when this method is called. + * + * @param object $restore Standard restore object + * @return boolean + **/ + function decode_content_links_caller($restore) { + global $CFG; + + if ($restored_blocks = get_records_select("backup_ids","table_name = 'block_instance' AND backup_code = $restore->backup_unique_code AND new_id > 0", "", "new_id")) { + $restored_blocks = implode(',', array_keys($restored_blocks)); + $sql = "SELECT bi.* + FROM {$CFG->prefix}block_instance bi + JOIN {$CFG->prefix}block b ON b.id = bi.blockid + WHERE b.name = 'html' AND bi.id IN ($restored_blocks)"; + + if ($instances = get_records_sql($sql)) { + foreach ($instances as $instance) { + $blockobject = block_instance('html', $instance); + $blockobject->config->text = restore_decode_absolute_links($blockobject->config->text); + $blockobject->config->text = restore_decode_content_links_worker($blockobject->config->text, $restore); + $blockobject->instance_config_commit($blockobject->pinned); + } + } + } + + return true; } } ?> diff --git a/blocks/moodleblock.class.php b/blocks/moodleblock.class.php index 3fdc945ae53..4afe7d79757 100644 --- a/blocks/moodleblock.class.php +++ b/blocks/moodleblock.class.php @@ -130,25 +130,102 @@ class block_base { } /** - * Will be called before an instance of this block is backed up, so that any links in - * any links in any HTML fields on config can be encoded. For example, for the HTML block - * we need to do $config->text = backup_encode_absolute_links($config->text);. + * Enable custom instance data section in backup and restore. + * + * If return true, then {@link instance_backup()} and + * {@link instance_restore()} will be called during + * backup/restore routines. * - * @param object $config the config field for an insance of this class. - */ - function backup_encode_absolute_links_in_config(&$config) { + * @return boolean + **/ + function backuprestore_instancedata_used() { + return false; } /** - * Undo the effect of backup_encode_absolute_links_in_config. For exmaple, in the - * HTML block we need to do $config->text = restore_decode_absolute_links($config->text); + * Allows the block class to have a backup routine. Handy + * when the block has its own tables that have foreign keys to + * other tables (example: user table). + * + * Note: at the time of writing this comment, the indent level + * for the {@link full_tag()} should start at 5. * - * @param object $config the config field for an insance of this class. - * @return boolean return true if something has changed, so the database can be updated, - * false if not, for efficiency reasons. + * @param resource $bf Backup File + * @param object $preferences Backup preferences + * @return boolean + **/ + function instance_backup($bf, $preferences) { + return true; + } + + /** + * Allows the block class to restore its backup routine. + * + * Should not return false if data is empty + * because old backups would not contain block instance backup data. + * + * @param object $restore Standard restore object + * @param object $data Object from backup_getid for this block instance + * @return boolean + **/ + function instance_restore($restore, $data) { + return true; + } + + /** + * Will be called before an instance of this block is backed up, so that any links in + * in config can be encoded. For example config->text, for the HTML block + * @return string */ - function restore_decode_absolute_links_in_config(&$config) { - return false; + function get_backup_encoded_config() { + return base64_encode(serialize($this->config)); + } + + /** + * Return the content encoded to support interactivities linking. This function is + * called automatically from the backup procedure by {@link backup_encode_absolute_links()}. + * + * NOTE: There is no block instance when this method is called. + * + * @param string $content Content to be encoded + * @param object $restore Restore preferences object + * @return string The encoded content + **/ + function encode_content_links($content, $restore) { + return $content; + } + + /** + * This function makes all the necessary calls to {@link restore_decode_content_links_worker()} + * function in order to decode contents of this block from the backup + * format to destination site/course in order to mantain inter-activities + * working in the backup/restore process. + * + * This is called from {@link restore_decode_content_links()} function in the restore process. + * + * NOTE: There is no block instance when this method is called. + * + * @param object $restore Standard restore object + * @return boolean + **/ + function decode_content_links_caller($restore) { + return true; + } + + /** + * Return content decoded to support interactivities linking. + * This is called automatically from + * {@link restore_decode_content_links_worker()} function + * in the restore process. + * + * NOTE: There is no block instance when this method is called. + * + * @param string $content Content to be dencoded + * @param object $restore Restore preferences object + * @return string The dencoded content + **/ + function decode_content_links($content, $restore) { + return $content; } /**