public function execute()
 {
     if (!$this->execute_condition()) {
         // Check any condition to execute this
         return;
     }
     $fullpath = $this->task->get_taskbasepath();
     // We MUST have one fullpath here, else, error
     if (empty($fullpath)) {
         throw new backup_step_exception('backup_structure_step_undefined_fullpath');
     }
     // Append the filename to the fullpath
     $fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
     // Create output, transformer, writer, processor
     $xo = new file_xml_output($fullpath);
     $xt = null;
     if (class_exists('backup_xml_transformer')) {
         $xt = new backup_xml_transformer($this->get_courseid());
         $this->contenttransformer = $xt;
         // Save the reference to the transformer
         // as far as we are going to need it out
         // from xml_writer (blame serialized data!)
     }
     $xw = new xml_writer($xo, $xt);
     $progress = $this->task->get_progress();
     $progress->start_progress($this->get_name());
     $pr = new backup_structure_processor($xw, $progress);
     // Set processor variables from settings
     foreach ($this->get_settings() as $setting) {
         $pr->set_var($setting->get_name(), $setting->get_value());
     }
     // Add backupid as one more var for processor
     $pr->set_var(backup::VAR_BACKUPID, $this->get_backupid());
     // Get structure definition
     $structure = $this->define_structure();
     if (!$structure instanceof backup_nested_element) {
         throw new backup_step_exception('backup_structure_step_wrong_structure');
     }
     // Start writer
     $xw->start();
     // Process structure definition
     $structure->process($pr);
     // Get the results from the nested elements
     $results = $structure->get_results();
     // Get the log messages to append to the log
     $logs = $structure->get_logs();
     foreach ($logs as $log) {
         $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
     }
     // Close everything
     $xw->stop();
     $progress->end_progress();
     // Destroy the structure. It helps PHP 5.2 memory a lot!
     $structure->destroy();
     return $results;
 }
 /**
  * Backup structures wrong tests (trying to do things the wrong way)
  */
 function test_backup_structure_wrong()
 {
     // Instantiate the backup processor
     $processor = new backup_structure_processor(new xml_writer(new memory_xml_output()));
     $this->assertTrue($processor instanceof base_processor);
     // Set one var twice
     $processor->set_var('onenewvariable', 999);
     try {
         $processor->set_var('onenewvariable', 999);
         $this->assertTrue(false, 'backup_processor_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof backup_processor_exception);
         $this->assertEquals($e->errorcode, 'processorvariablealreadyset');
         $this->assertEquals($e->a, 'onenewvariable');
     }
     // Get non-existing var
     try {
         $var = $processor->get_var('nonexistingvar');
         $this->assertTrue(false, 'backup_processor_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof backup_processor_exception);
         $this->assertEquals($e->errorcode, 'processorvariablenotfound');
         $this->assertEquals($e->a, 'nonexistingvar');
     }
     // Create nested element and try ro get its parent id (doesn't exisit => exception)
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     try {
         $ne->set_source_table('forum', array('id' => backup::VAR_PARENTID));
         $ne->process($processor);
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'cannotfindparentidforelement');
     }
     // Try to process one nested/final/attribute elements without processor
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     try {
         $ne->process(new stdclass());
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'incorrect_processor');
     }
     $fe = new backup_final_element('test');
     try {
         $fe->process(new stdclass());
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'incorrect_processor');
     }
     $at = new backup_attribute('test');
     try {
         $at->process(new stdclass());
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'incorrect_processor');
     }
     // Try to put an incorrect alias
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     try {
         $ne->set_source_alias('last', 'nonexisting');
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'incorrectaliasfinalnamenotfound');
         $this->assertEquals($e->a, 'nonexisting');
     }
     // Try various incorrect paths specifying source
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     try {
         $ne->set_source_table('forum', array('/test/subtest'));
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'baseelementincorrectfinalorattribute');
         $this->assertEquals($e->a, 'subtest');
     }
     try {
         $ne->set_source_table('forum', array('/wrongtest'));
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'baseelementincorrectgrandparent');
         $this->assertEquals($e->a, 'wrongtest');
     }
     try {
         $ne->set_source_table('forum', array('../nonexisting'));
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'baseelementincorrectparent');
         $this->assertEquals($e->a, '..');
     }
     // Try various incorrect file annotations
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     $ne->annotate_files('test', 'filearea', null);
     try {
         $ne->annotate_files('test', 'filearea', null);
         // Try to add annotations twice
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'annotate_files_duplicate_annotation');
         $this->assertEquals($e->a, 'test/filearea/');
     }
     $ne = new backup_nested_element('test', 'one', 'two', 'three');
     try {
         $ne->annotate_files('test', 'filearea', 'four');
         // Incorrect element
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'baseelementincorrectfinalorattribute');
         $this->assertEquals($e->a, 'four');
     }
     // Try to add incorrect element to backup_optigroup
     $bog = new backup_optigroup('test');
     try {
         $bog->add_child(new backup_nested_element('test2'));
         $this->assertTrue(false, 'base_optigroup_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_optigroup_exception);
         $this->assertEquals($e->errorcode, 'optigroup_element_incorrect');
         $this->assertEquals($e->a, 'backup_nested_element');
     }
     $bog = new backup_optigroup('test');
     try {
         $bog->add_child('test2');
         $this->assertTrue(false, 'base_optigroup_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_optigroup_exception);
         $this->assertEquals($e->errorcode, 'optigroup_element_incorrect');
         $this->assertEquals($e->a, 'non object');
     }
     try {
         $bog = new backup_optigroup('test', new stdclass());
         $this->assertTrue(false, 'base_optigroup_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_optigroup_exception);
         $this->assertEquals($e->errorcode, 'optigroup_elements_incorrect');
     }
     // Try a wrong processor with backup_optigroup
     $bog = new backup_optigroup('test');
     try {
         $bog->process(new stdclass());
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'incorrect_processor');
     }
     // Try duplicating used elements with backup_optigroup
     // Adding top->down
     $bog = new backup_optigroup('test', null, true);
     $boge1 = new backup_optigroup_element('boge1');
     $boge2 = new backup_optigroup_element('boge2');
     $ne1 = new backup_nested_element('ne1');
     $ne2 = new backup_nested_element('ne1');
     $bog->add_child($boge1);
     $bog->add_child($boge2);
     $boge1->add_child($ne1);
     try {
         $boge2->add_child($ne2);
         $this->assertTrue(false, 'base_optigroup_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_optigroup_exception);
         $this->assertEquals($e->errorcode, 'multiple_optigroup_duplicate_element');
         $this->assertEquals($e->a, 'ne1');
     }
     // Adding down->top
     $bog = new backup_optigroup('test', null, true);
     $boge1 = new backup_optigroup_element('boge1');
     $boge2 = new backup_optigroup_element('boge2');
     $ne1 = new backup_nested_element('ne1');
     $ne2 = new backup_nested_element('ne1');
     $boge1->add_child($ne1);
     $boge2->add_child($ne2);
     $bog->add_child($boge1);
     try {
         $bog->add_child($boge2);
         $this->assertTrue(false, 'base_element_struct_exception expected');
     } catch (exception $e) {
         $this->assertTrue($e instanceof base_element_struct_exception);
         $this->assertEquals($e->errorcode, 'baseelementexisting');
         $this->assertEquals($e->a, 'ne1');
     }
 }