MDL-23478 backup - restore blocks (instances an positions)
This commit is contained in:
@@ -31,12 +31,22 @@
|
||||
abstract class restore_block_task extends restore_task {
|
||||
|
||||
protected $taskbasepath; // To store the basepath of this block
|
||||
protected $blockname; // Name of the block
|
||||
protected $contextid; // new (target) context of the block
|
||||
protected $oldcontextid;// old (original) context of the block
|
||||
protected $blockid; // new (target) id of the block
|
||||
protected $oldblockid; // old (original) id of the block
|
||||
|
||||
/**
|
||||
* Constructor - instantiates one object of this class
|
||||
*/
|
||||
public function __construct($name, $taskbasepath, $plan = null) {
|
||||
$this->taskbasepath = $taskbasepath;
|
||||
$this->blockname = '';
|
||||
$this->contextid = 0;
|
||||
$this->oldcontextid = 0;
|
||||
$this->blockid = 0;
|
||||
$this->oldblockid = 0;
|
||||
parent::__construct($name, $plan);
|
||||
}
|
||||
|
||||
@@ -58,15 +68,75 @@ abstract class restore_block_task extends restore_task {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: See backup. If "child" of activity task and it has been excluded, nothing to do
|
||||
// If "child" of activity task and it has been excluded, nothing to do
|
||||
$parent = basename(dirname(dirname($this->taskbasepath)));
|
||||
if ($parent != 'course') {
|
||||
$includedsetting = $parent . '_included';
|
||||
if (!$this->get_setting_value($includedsetting)) {
|
||||
$this->built = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the block.xml common file (instance + positions)
|
||||
$this->add_step(new restore_block_instance_structure_step('block_commons', 'block.xml'));
|
||||
|
||||
// TODO: Link all the activity steps here
|
||||
// Here we add all the common steps for any block and, in the point of interest
|
||||
// we call to define_my_steps() in order to get the particular ones inserted in place.
|
||||
$this->define_my_steps();
|
||||
|
||||
// Restore block role assignments and overrides (internally will observe the role_assignments setting)
|
||||
$this->add_step(new restore_ras_and_caps_structure_step('block_ras_and_caps', 'roles.xml'));
|
||||
|
||||
// Restore block comments (conditionally)
|
||||
if ($this->get_setting_value('comments')) {
|
||||
$this->add_step(new restore_comments_structure_step('block_comments', 'comments.xml'));
|
||||
}
|
||||
|
||||
// At the end, mark it as built
|
||||
$this->built = true;
|
||||
}
|
||||
|
||||
public function set_blockname($blockname) {
|
||||
$this->blockname = $blockname;
|
||||
}
|
||||
|
||||
public function get_blockname() {
|
||||
return $this->blockname;
|
||||
}
|
||||
|
||||
public function set_blockid($blockid) {
|
||||
$this->blockid = $blockid;
|
||||
}
|
||||
|
||||
public function get_blockid() {
|
||||
return $this->blockid;
|
||||
}
|
||||
|
||||
public function set_old_blockid($blockid) {
|
||||
$this->oldblockid = $blockid;
|
||||
}
|
||||
|
||||
public function get_old_blockid() {
|
||||
return $this->oldblockid;
|
||||
}
|
||||
|
||||
public function set_contextid($contextid) {
|
||||
$this->contextid = $contextid;
|
||||
}
|
||||
|
||||
public function get_contextid() {
|
||||
return $this->contextid;
|
||||
}
|
||||
|
||||
public function set_old_contextid($contextid) {
|
||||
$this->oldcontextid = $contextid;
|
||||
}
|
||||
|
||||
public function get_old_contextid() {
|
||||
return $this->oldcontextid;
|
||||
}
|
||||
|
||||
// Protected API starts here
|
||||
|
||||
/**
|
||||
@@ -90,6 +160,11 @@ abstract class restore_block_task extends restore_task {
|
||||
*/
|
||||
abstract protected function define_my_steps();
|
||||
|
||||
/**
|
||||
* Define one array() of fileareas that each block controls
|
||||
*/
|
||||
abstract public function get_fileareas();
|
||||
|
||||
/**
|
||||
* Define one array() of configdata attributes
|
||||
* that need to be decoded
|
||||
|
||||
@@ -37,6 +37,10 @@ class restore_default_block_task extends restore_block_task {
|
||||
protected function define_my_steps() {
|
||||
}
|
||||
|
||||
public function get_fileareas() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function get_configdata_encoded_attributes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -35,9 +35,15 @@ class restore_final_task extends restore_task {
|
||||
*/
|
||||
public function build() {
|
||||
|
||||
// Review all the block_position records in backup_ids in order
|
||||
// match them now that all the contexts are created populating DB
|
||||
// as needed. Only if we are restoring blocks.
|
||||
if ($this->get_setting_value('blocks')) {
|
||||
$this->add_step(new restore_review_pending_block_positions('review_block_positions'));
|
||||
}
|
||||
|
||||
// TODO: Gradebook
|
||||
// TODO: interlinks
|
||||
// TODO: Apply all the block_positions accumulated along the process
|
||||
|
||||
// Clean the temp dir (conditionally) and drop temp table
|
||||
$this->add_step(new restore_drop_and_clean_temp_stuff('drop_and_clean_temp_stuff'));
|
||||
|
||||
@@ -117,7 +117,7 @@ abstract class restore_plan_builder {
|
||||
$blocks = backup_general_helper::get_blocks_from_path($task->get_taskbasepath());
|
||||
foreach ($blocks as $basepath => $name) {
|
||||
if ($task = restore_factory::get_restore_block_task($name, $basepath)) {
|
||||
$plan->add_task($task);
|
||||
//$plan->add_task($task);
|
||||
} else {
|
||||
// TODO: Debug information about block not supported
|
||||
}
|
||||
|
||||
@@ -66,6 +66,37 @@ class restore_drop_and_clean_temp_stuff extends restore_execution_step {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Review all the (pending) block positions in backup_ids, matching by
|
||||
* contextid, creating positions as needed. This is executed by the
|
||||
* final task, once all the contexts have been created
|
||||
*/
|
||||
class restore_review_pending_block_positions extends restore_execution_step {
|
||||
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
// Get all the block_position objects pending to match
|
||||
$params = array('backupid' => $this->get_restoreid(), 'itemname' => 'block_position');
|
||||
$rs = $DB->get_recordset('backup_ids_temp', $params, '', 'itemid');
|
||||
// Process block positions, creating them or accumulating for final step
|
||||
foreach($rs as $posrec) {
|
||||
// Get the complete position object (stored as info)
|
||||
$position = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'block_position', $posrec->itemid)->info;
|
||||
// If position is for one already mapped (known) contextid
|
||||
// process it now, creating the position, else nothing to
|
||||
// do, position finally discarded
|
||||
if ($newctx = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $position->contextid)) {
|
||||
$position->contextid = $newctx->newitemid;
|
||||
// Create the block position
|
||||
$DB->insert_record('block_positions', $position);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Execution step that, *conditionally* (if there isn't preloaded information)
|
||||
* will load the inforef files for all the included course/section/activity tasks
|
||||
@@ -646,8 +677,8 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
|
||||
// Check roleid, userid are one of the mapped ones
|
||||
$newroleid = $this->get_mappingid('role', $data->roleid);
|
||||
$newuserid = $this->get_mappingid('user', $data->userid);
|
||||
// If newroleid and newuserid and component is empty assign via API (handles dupes and friends)
|
||||
if ($newroleid && $newuserid && empty($data->component)) {
|
||||
// If newroleid and newuserid and component is empty and context valid assign via API (handles dupes and friends)
|
||||
if ($newroleid && $newuserid && empty($data->component) && $this->task->get_contextid()) {
|
||||
// TODO: role_assign() needs one userid param to be able to specify our restore userid
|
||||
role_assign($newroleid, $newuserid, $this->task->get_contextid());
|
||||
}
|
||||
@@ -658,9 +689,10 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
|
||||
|
||||
// Check roleid is one of the mapped ones
|
||||
$newroleid = $this->get_mappingid('role', $data->roleid);
|
||||
// If newroleid is valid assign it via API (it handles dupes and so on)
|
||||
if ($newroleid) {
|
||||
// If newroleid and context are valid assign it via API (it handles dupes and so on)
|
||||
if ($newroleid && $this->task->get_contextid()) {
|
||||
// TODO: assign_capability() needs one userid param to be able to specify our restore userid
|
||||
// TODO: it seems that assign_capability() doesn't check for valid capabilities at all ???
|
||||
assign_capability($data->capability, $data->permission, $newroleid, $this->task->get_contextid());
|
||||
}
|
||||
}
|
||||
@@ -820,9 +852,128 @@ class restore_comments_structure_step extends restore_structure_step {
|
||||
}
|
||||
// Only restore the comment if has no mapping OR we have found the matching mapping
|
||||
if (!$mapping || $newitemid) {
|
||||
if ($data->userid = $this->get_mappingid('user', $data->userid)) {
|
||||
// Only if user mapping and context
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
if ($data->userid && $this->task->get_contextid()) {
|
||||
$data->contextid = $this->task->get_contextid();
|
||||
$DB->insert_record('comments', $data);
|
||||
// Only if there is another comment with same context/user/timecreated
|
||||
$params = array('contextid' => $data->contextid, 'userid' => $data->userid, 'timecreated' => $data->timecreated);
|
||||
if (!$DB->record_exists('comments', $params)) {
|
||||
$DB->insert_record('comments', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This structure steps restores one instance + positions of one block
|
||||
* Note: Positions corresponding to one existing context are restored
|
||||
* here, but all the ones having unknown contexts are sent to backup_ids
|
||||
* for a later chance to be restored at the end (final task)
|
||||
*/
|
||||
class restore_block_instance_structure_step extends restore_structure_step {
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
$paths = array();
|
||||
|
||||
$paths[] = new restore_path_element('block', '/block', true); // Get the whole XML together
|
||||
$paths[] = new restore_path_element('block_position', '/block/block_positions/block_position');
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
public function process_block($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data; // Handy
|
||||
$oldcontextid = $data->contextid;
|
||||
$oldid = $data->id;
|
||||
$positions = isset($data->block_positions['block_position']) ? $data->block_positions['block_position'] : array();
|
||||
|
||||
// Look for the parent contextid
|
||||
if (!$data->parentcontextid = $this->get_mappingid('context', $data->parentcontextid)) {
|
||||
throw new restore_step_exception('restore_block_missing_parent_ctx', $data->parentcontextid);
|
||||
}
|
||||
|
||||
// If there is already one block of that type in the parent context
|
||||
// and the block is not multiple, stop processing
|
||||
if ($DB->record_exists_sql("SELECT bi.id
|
||||
FROM {block_instances} bi
|
||||
JOIN {block} b ON b.name = bi.blockname
|
||||
WHERE bi.parentcontextid = ?
|
||||
AND bi.blockname = ?
|
||||
AND b.multiple = 0", array($data->parentcontextid, $data->blockname))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is already one block of that type in the parent context
|
||||
// with the same showincontexts, pagetypepattern, subpagepattern, defaultregion and configdata
|
||||
// stop processing
|
||||
$params = array(
|
||||
'blockname' => $data->blockname, 'parentcontextid' => $data->parentcontextid,
|
||||
'showinsubcontexts' => $data->showinsubcontexts, 'pagetypepattern' => $data->pagetypepattern,
|
||||
'subpagepattern' => $data->subpagepattern, 'defaultregion' => $data->defaultregion);
|
||||
if ($birecs = $DB->get_records('block_instances', $params)) {
|
||||
foreach($birecs as $birec) {
|
||||
if ($birec->configdata == $data->configdata) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set task old contextid, blockid and blockname once we know them
|
||||
$this->task->set_old_contextid($oldcontextid);
|
||||
$this->task->set_old_blockid($oldid);
|
||||
$this->task->set_blockname($data->blockname);
|
||||
|
||||
// Let's look for anything within configdata neededing processing
|
||||
// (nulls and uses of legacy file.php)
|
||||
if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
|
||||
$configdata = (array)unserialize(base64_decode($data->configdata));
|
||||
foreach ($configdata as $attribute => $value) {
|
||||
if (in_array($attribute, $attrstotransform)) {
|
||||
$configdata[$attribute] = $this->contentprocessor->process_cdata($value);
|
||||
}
|
||||
}
|
||||
$data->configdata = base64_encode(serialize((object)$configdata));
|
||||
}
|
||||
|
||||
// Create the block instance
|
||||
$newitemid = $DB->insert_record('block_instances', $data);
|
||||
// Save the mapping (with restorefiles support)
|
||||
$this->set_mapping('block_instance', $oldid, $newitemid, true);
|
||||
// Create the block context
|
||||
$newcontextid = get_context_instance(CONTEXT_BLOCK, $newitemid)->id;
|
||||
// Save the block contexts mapping and sent it to task
|
||||
$this->set_mapping('context', $oldcontextid, $newcontextid);
|
||||
$this->task->set_contextid($newcontextid);
|
||||
$this->task->set_blockid($newitemid);
|
||||
|
||||
// Restore block fileareas if declared
|
||||
$component = 'block_' . $this->task->get_blockname();
|
||||
foreach ($this->task->get_fileareas() as $filearea) { // Simple match by contextid. No itemname needed
|
||||
$this->add_related_files($component, $filearea, null);
|
||||
}
|
||||
|
||||
// Process block positions, creating them or accumulating for final step
|
||||
foreach($positions as $position) {
|
||||
$position = (object)$position;
|
||||
$position->blockinstanceid = $newitemid; // The instance is always the restored one
|
||||
// If position is for one already mapped (known) contextid
|
||||
// process it now, creating the position
|
||||
if ($newpositionctxid = $this->get_mappingid('context', $position->contextid)) {
|
||||
$position->contextid = $newpositionctxid;
|
||||
// Create the block position
|
||||
$DB->insert_record('block_positions', $position);
|
||||
|
||||
// The position belongs to an unknown context, send it to backup_ids
|
||||
// to process them as part of the final steps of restore. We send the
|
||||
// whole $position object there, hence use the low level method.
|
||||
} else {
|
||||
restore_dbops::set_backup_ids_record($this->get_restoreid(), 'block_position', $position->id, 0, null, $position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user