MDL-75492 mod_data: Refactor code to get available importing information

This commit is contained in:
Amaia Anabitarte 2022-11-03 15:15:41 +01:00
parent 5a880405bf
commit b755cfa544
5 changed files with 631 additions and 119 deletions

View File

@ -36,6 +36,18 @@ abstract class preset_importer {
/** @var string directory where to find the preset. */
protected $directory;
/** @var array fields to remove. */
public $fieldstoremove;
/** @var array fields to update. */
public $fieldstoupdate;
/** @var array fields to create. */
public $fieldstocreate;
/** @var array settings to be imported. */
public $settings;
/**
* Constructor
*
@ -45,6 +57,9 @@ abstract class preset_importer {
public function __construct(manager $manager, string $directory) {
$this->manager = $manager;
$this->directory = $directory;
// Read the preset and saved result.
$this->settings = $this->get_preset_settings();
}
/**
@ -176,22 +191,33 @@ abstract class preset_importer {
}
// Now work out fields to user friendly array.
$fieldsarray = $parsedxml['preset']['#']['field'];
foreach ($fieldsarray as $field) {
if (!is_array($field)) {
continue;
}
$fieldstoimport = new StdClass();
foreach ($field['#'] as $param => $value) {
if (!is_array($value)) {
if (
array_key_exists('preset', $parsedxml) &&
array_key_exists('#', $parsedxml['preset']) &&
array_key_exists('field', $parsedxml['preset']['#'])) {
$fieldsarray = $parsedxml['preset']['#']['field'];
foreach ($fieldsarray as $field) {
if (!is_array($field)) {
continue;
}
$fieldstoimport->$param = $value[0]['#'];
$fieldstoimport = new StdClass();
foreach ($field['#'] as $param => $value) {
if (!is_array($value)) {
continue;
}
$fieldstoimport->$param = $value[0]['#'];
}
$fieldstoimport->dataid = $module->id;
$fieldstoimport->type = clean_param($fieldstoimport->type, PARAM_ALPHA);
$result->importfields[] = $fieldstoimport;
}
$fieldstoimport->dataid = $module->id;
$fieldstoimport->type = clean_param($fieldstoimport->type, PARAM_ALPHA);
$result->importfields[] = $fieldstoimport;
}
// Calculate default mapping.
if (is_null($this->fieldstoremove) && is_null($this->fieldstocreate) && is_null($this->fieldstoupdate)) {
$this->set_affected_fields($result->importfields, $result->currentfields);
}
// Now add the HTML templates to the settings array so we can update d.
foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) {
$result->settings->$templatename = $this->get_file_contents(
@ -215,63 +241,44 @@ abstract class preset_importer {
public function import(bool $overwritesettings): bool {
global $DB, $OUTPUT;
$params = $this->get_preset_settings();
$settings = $params->settings;
$newfields = $params->importfields;
$currentfields = $params->currentfields;
$preservedfields = [];
$settings = $this->settings->settings;
$currentfields = $this->settings->currentfields;
$missingfieldtypes = [];
$module = $this->manager->get_instance();
// Maps fields and makes new ones.
if (!empty($newfields)) {
// We require an injective mapping, and need to know what to protect.
foreach ($newfields as $newid => $newfield) {
$cid = optional_param("field_$newid", -1, PARAM_INT);
if ($cid == -1) {
continue;
}
if (array_key_exists($cid, $preservedfields)) {
throw new \moodle_exception('notinjectivemap', 'data');
} else {
$preservedfields[$cid] = true;
}
}
foreach ($newfields as $newid => $newfield) {
$cid = optional_param("field_$newid", -1, PARAM_INT);
/* A mapping. Just need to change field params. Data kept. */
if ($cid != -1 && isset($currentfields[$cid])) {
$fieldobject = data_get_field_from_id($currentfields[$cid]->id, $module);
foreach ($newfield as $param => $value) {
if ($param != "id") {
$fieldobject->field->$param = $value;
}
foreach ($this->fieldstoupdate as $currentid => $updatable) {
if ($currentid != -1 && isset($currentfields[$currentid])) {
$fieldobject = data_get_field_from_id($currentfields[$currentid]->id, $module);
foreach ($updatable as $param => $value) {
if ($param != "id") {
$fieldobject->field->$param = $value;
}
unset($fieldobject->field->similarfield);
$fieldobject->update_field();
unset($fieldobject);
} else {
/* Make a new field */
$filepath = "field/$newfield->type/field.class.php";
if (!file_exists($filepath)) {
$missingfieldtypes[] = $newfield->name;
continue;
}
include_once($filepath);
if (!isset($newfield->description)) {
$newfield->description = '';
}
$classname = 'data_field_'.$newfield->type;
$fieldclass = new $classname($newfield, $module);
$fieldclass->insert_field();
unset($fieldclass);
}
unset($fieldobject->field->similarfield);
$fieldobject->update_field();
unset($fieldobject);
}
if (!empty($missingfieldtypes)) {
echo $OUTPUT->notification(get_string('missingfieldtypeimport', 'data') . html_writer::alist($missingfieldtypes));
}
foreach ($this->fieldstocreate as $newfield) {
/* Make a new field */
$filepath = "field/$newfield->type/field.class.php";
if (!file_exists($filepath)) {
$missingfieldtypes[] = $newfield->name;
continue;
}
include_once($filepath);
if (!isset($newfield->description)) {
$newfield->description = '';
}
$classname = 'data_field_' . $newfield->type;
$fieldclass = new $classname($newfield, $module);
$fieldclass->insert_field();
unset($fieldclass);
}
if (!empty($missingfieldtypes)) {
echo $OUTPUT->notification(get_string('missingfieldtypeimport', 'data') . html_writer::alist($missingfieldtypes));
}
// Get rid of all old unused data.
@ -328,6 +335,59 @@ abstract class preset_importer {
return $this->cleanup();
}
/**
* Returns information about the fields needs to be removed, updated or created.
*
* @param array $newfields Array of new fields to be applied.
* @param array $currentfields Array of current fields on database activity.
* @return void
*/
public function set_affected_fields(array $newfields = [], array $currentfields = []): void {
$fieldstoremove = [];
$fieldstocreate = [];
$preservedfields = [];
// Maps fields and makes new ones.
if (!empty($newfields)) {
// We require an injective mapping, and need to know what to protect.
foreach ($newfields as $newid => $newfield) {
$preservedfieldid = optional_param("field_$newid", -1, PARAM_INT);
if (array_key_exists($preservedfieldid, $preservedfields)) {
throw new \moodle_exception('notinjectivemap', 'data');
}
if ($preservedfieldid == -1) {
// Let's check if there is any field with same type and name that we could map to.
foreach ($currentfields as $currentid => $currentfield) {
if (($currentfield->type == $newfield->type) &&
($currentfield->name == $newfield->name) && !array_key_exists($currentid, $preservedfields)) {
// We found a possible default map.
$preservedfieldid = $currentid;
$preservedfields[$currentid] = $newfield;
}
}
}
if ($preservedfieldid == -1) {
// We need to create a new field.
$fieldstocreate[] = $newfield;
} else {
$preservedfields[$preservedfieldid] = $newfield;
}
}
}
foreach ($currentfields as $currentid => $currentfield) {
if (!array_key_exists($currentid, $preservedfields)) {
$fieldstoremove[] = $currentfield;
}
}
$this->fieldstocreate = $fieldstocreate;
$this->fieldstoremove = $fieldstoremove;
$this->fieldstoupdate = $preservedfields;
}
/**
* Any clean up routines should go here
*
@ -343,7 +403,10 @@ abstract class preset_importer {
* @return bool True if the current database needs to map the fields imported.
*/
public function needs_mapping(): bool {
return $this->manager->has_fields();
if (!$this->manager->has_fields()) {
return false;
}
return (!empty($this->fieldstocreate) || !empty($this->fieldstoremove));
}
/**

View File

@ -59,7 +59,7 @@ class mod_data_renderer extends plugin_renderer_base {
$strwarning = get_string('mappingwarning', 'data');
$strfieldmappings = get_string('fieldmappings', 'data');
$params = $importer->get_preset_settings();
$params = $importer->settings;
$newfields = $params->importfields;
$currentfields = $params->currentfields;
@ -94,10 +94,18 @@ class mod_data_renderer extends plugin_renderer_base {
continue;
}
if ($currentfield->name == $newfield->name) {
$row[1] .= html_writer::tag('option', get_string('mapexistingfield', 'data', $currentfield->name), array('value'=>$cid, 'selected'=>'selected'));
$selected=true;
$row[1] .= html_writer::tag(
'option',
get_string('mapexistingfield', 'data', $currentfield->name),
['value' => $cid, 'selected' => 'selected']
);
$selected = true;
} else {
$row[1] .= html_writer::tag('option', get_string('mapexistingfield', 'data', $currentfield->name), array('value'=>$cid));
$row[1] .= html_writer::tag(
'option',
get_string('mapexistingfield', 'data', $currentfield->name),
['value' => $cid]
);
}
}

View File

@ -17,16 +17,11 @@ Feature: Users can import presets
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Mountain landscapes | n | C1 | data1 |
And the following "mod_data > presets" exist:
| database | name | description |
| data1 | Saved preset 1 | The preset1 has description |
| data1 | Saved preset 2 | |
Scenario: Teacher can import from preset page on an empty database
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Actions" "button"
And I choose "Import preset" in the open action menu
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
Then I should not see "Field mappings"
@ -38,8 +33,7 @@ Feature: Users can import presets
| data1 | text | Test field name | Test field description |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Actions" "button"
And I choose "Import preset" in the open action menu
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
Then I should see "Field mappings"
@ -62,8 +56,7 @@ Feature: Users can import presets
| data1 | Student entry 1 |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Actions" "button"
And I choose "Import preset" in the open action menu
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
Then I should see "Field mappings"
@ -86,13 +79,17 @@ Feature: Users can import presets
| data1 | Student entry 1 |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Actions" "button"
And I choose "Import preset" in the open action menu
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
Then I should see "Field mappings"
And I should see "image"
And I should see "Create a new field" in the "image" "table_row"
And I should see "title"
And I should see "Create a new field" in the "title" "table_row"
# We map existing field to keep the entry data
And I set the field "id_title" to "Map to field1"
And I click on "Continue" "button"
And I follow "Database"
And I should see "Student entry"
Scenario: Teacher can import from zero state page on an empty database
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
@ -101,3 +98,72 @@ Feature: Users can import presets
When I click on "Import preset and apply" "button"
Then I should not see "Field mappings"
And I should see "Image" in the "image" "table_row"
Scenario: Importing a preset could create new fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | title |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "title"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Importing a preset could create map fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | oldtitle |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "oldtitle"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
# Let's map a field that is not mapped by default
And I should see "Create a new field" in the "oldtitle" "table_row"
And I set the field "id_title" to "Map to oldtitle"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should not see "oldtitle"
And I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Importing same preset twice doesn't show mapping dialogue
# Importing a preset on an empty database doesn't show the mapping dialogue, so we add a field for the database
# not to be empty.
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | title |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
When I click on "Import preset and apply" "button"
And I should see "Field mappings"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
And I follow "Presets"
And I choose the "Import preset" item in the "Action" action menu
And I upload "mod/data/tests/fixtures/image_gallery_preset.zip" file to "Preset file" filemanager
And I click on "Import preset and apply" "button"
Then I should not see "Field mappings"
And I should see "The preset has been successfully applied"

View File

@ -0,0 +1,186 @@
@mod @mod_data @javascript
Feature: Users can use predefined presets
In order to use presets
As a user
I need to select an existing preset
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Mountain landscapes | introduction... | C1 | data1 |
And the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Test field name | Test field description |
Scenario: Using a preset on a non empty database could create new fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | title |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "title"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Using a preset on a non-empty database could show the option to map fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | oldtitle |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "oldtitle"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
# Let's map a field that is not mapped by default
And I should see "Create a new field" in the "oldtitle" "table_row"
And I set the field "id_title" to "Map to oldtitle"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should not see "oldtitle"
And I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Teacher can use a preset from presets page on a database with existing entries
# Creating an entry to test use a preset feature with databases with entries.
Given the following "mod_data > entries" exist:
| database | Test field name |
| data1 | Student entry 1 |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And the "Use this preset" "button" should be enabled
Then I click on "Use this preset" "button"
Then I should see "Field mappings"
And I should see "title"
And I should see "Create a new field" in the "title" "table_row"
# We map existing field to keep the entry data
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I follow "Fields"
And I should see "title"
And I follow "Database"
And I should see "Student entry 1"
Scenario: Using same preset twice doesn't show mapping dialogue and applies the preset directly
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
When I click on "Use this preset" "button"
And I should see "Field mappings"
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
Then I should not see "Field mappings"
And I should see "The preset has been successfully applied"
Scenario: Using a preset from preset preview page on a non empty database could create new fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | title |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "title"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Using a preset from preset preview page on a non-empty database could show the option to map fields
Given the following "mod_data > fields" exist:
| database | type | name |
| data1 | text | oldtitle |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Fields"
And I should see "oldtitle"
And I should not see "Description"
And I should not see "image"
And I follow "Presets"
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
# Let's map a field that is not mapped by default
And I should see "Create a new field" in the "oldtitle" "table_row"
And I set the field "id_title" to "Map to oldtitle"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should not see "oldtitle"
And I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
Scenario: Teacher can use a preset from preset preview page on a database with existing entries
# Creating an entry to test use a preset feature with databases with entries.
Given the following "mod_data > entries" exist:
| database | Test field name |
| data1 | Student entry 1 |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Image gallery" "link"
And the "Use this preset" "button" should be enabled
Then I click on "Use this preset" "button"
Then I should see "Field mappings"
And I should see "title"
And I should see "Create a new field" in the "title" "table_row"
# We map existing field to keep the entry data
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I follow "Fields"
And I should see "title"
And I follow "Database"
And I should see "Student entry 1"
Scenario: Using same preset twice from preset preview page doesn't show mapping dialogue and applies the preset
directly
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Image gallery" "link"
When I click on "Use this preset" "button"
And I should see "Field mappings"
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Presets"
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
Then I should not see "Field mappings"
And I should see "The preset has been successfully applied"

View File

@ -17,7 +17,6 @@
namespace mod_data;
use mod_data\local\importer\preset_existing_importer;
use mod_data\local\importer\preset_upload_importer;
/**
* Preset importer tests class for mod_data.
@ -30,65 +29,255 @@ use mod_data\local\importer\preset_upload_importer;
*/
class preset_importer_test extends \advanced_testcase {
/**
* Data provider for build providers for test_needs_mapping and test_set_affected_fields.
*
* @return array[]
*/
public function preset_importer_provider(): array {
// Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
$titlefield = new \stdClass();
$titlefield->name = 'title';
$titlefield->type = 'text';
$descfield = new \stdClass();
$descfield->name = 'description';
$descfield->type = 'textarea';
$imagefield = new \stdClass();
$imagefield->name = 'image';
$imagefield->type = 'picture';
$difffield = new \stdClass();
$difffield->name = 'title';
$difffield->type = 'textarea';
$newfield = new \stdClass();
$newfield->name = 'number';
$newfield->type = 'number';
return [
'Empty database / Empty importer' => [
'currentfields' => [],
'newfields' => [],
'pluginname' => '',
],
'Empty database / Importer with fields' => [
'currentfields' => [],
'newfields' => [$titlefield, $descfield, $imagefield],
'pluginname' => 'imagegallery',
],
'Database with fields / Empty importer' => [
'currentfields' => [$titlefield, $descfield, $imagefield],
'newfields' => [],
'pluginname' => '',
],
'Same fields' => [
'currentfields' => [$titlefield, $descfield, $imagefield],
'newfields' => [$titlefield, $descfield, $imagefield],
'pluginname' => 'imagegallery',
],
'Fields to create' => [
'currentfields' => [$titlefield, $descfield],
'newfields' => [$titlefield, $descfield, $imagefield],
'pluginname' => 'imagegallery',
],
'Fields to remove' => [
'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
'newfields' => [$titlefield, $descfield, $imagefield],
'pluginname' => 'imagegallery',
],
'Fields to update' => [
'currentfields' => [$difffield, $descfield, $imagefield],
'newfields' => [$titlefield, $descfield, $imagefield],
'pluginname' => 'imagegallery',
],
'Fields to create, remove and update' => [
'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
'newfields' => [$titlefield, $descfield, $newfield],
'pluginname' => '',
],
];
}
/**
* Data provider for needs_mapping().
*
* @return array[]
*/
public function needs_mapping_provider(): array {
$basedprovider = $this->preset_importer_provider();
$basedprovider['Empty database / Empty importer']['needsmapping'] = false;
$basedprovider['Empty database / Importer with fields']['needsmapping'] = false;
$basedprovider['Database with fields / Empty importer']['needsmapping'] = true;
$basedprovider['Same fields']['needsmapping'] = false;
$basedprovider['Fields to create']['needsmapping'] = true;
$basedprovider['Fields to remove']['needsmapping'] = true;
$basedprovider['Fields to update']['needsmapping'] = true;
$basedprovider['Fields to create, remove and update']['needsmapping'] = true;
return $basedprovider;
}
/**
* Test for needs_mapping method.
*
* @dataProvider needs_mapping_provider
* @covers ::needs_mapping
*
* @param array $currentfields Fields of the current activity.
* @param array $newfields Fields to be imported.
* @param string $pluginname The plugin preset to be imported.
* @param bool $expectedresult Expected exception.
*/
public function test_needs_mapping() {
global $CFG, $USER;
public function test_needs_mapping(
array $currentfields,
array $newfields,
string $pluginname,
bool $expectedresult
) {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($currentfields as $field) {
$plugingenerator->create_field($field, $activity);
}
$manager = manager::create_from_instance($activity);
// Create presets and importers.
$pluginname = 'imagegallery';
$plugin = preset::create_from_plugin(null, $pluginname);
$pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($newfields as $field) {
$plugingenerator->create_field($field, $presetactivity);
}
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($activity, $record);
$saved = $plugingenerator->create_preset($presetactivity, $record);
$savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
$this->assertEquals($savedimporter->needs_mapping(), $expectedresult);
$fixturepath = $CFG->dirroot . '/mod/data/tests/fixtures/image_gallery_preset.zip';
// Create presets and importers.
if ($pluginname) {
$plugin = preset::create_from_plugin(null, $pluginname);
$pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
$this->assertEquals($pluginimporter->needs_mapping(), $expectedresult);
}
}
// Create a storage file.
$draftid = file_get_unused_draft_itemid();
$filerecord = [
'component' => 'user',
'filearea' => 'draft',
'contextid' => \context_user::instance($USER->id)->id,
'itemid' => $draftid,
'filename' => 'image_gallery_preset.zip',
'filepath' => '/'
/**
* Data provider for test_set_affected_fields().
*
* @return array[]
*/
public function set_affected_provider(): array {
$basedprovider = $this->preset_importer_provider();
$basedprovider['Empty database / Empty importer']['fieldstocreate'] = 0;
$basedprovider['Empty database / Empty importer']['fieldstoremove'] = 0;
$basedprovider['Empty database / Empty importer']['fieldstoupdate'] = 0;
$basedprovider['Empty database / Importer with fields']['fieldstocreate'] = 3;
$basedprovider['Empty database / Importer with fields']['fieldstoremove'] = 0;
$basedprovider['Empty database / Importer with fields']['fieldstoupdate'] = 0;
$basedprovider['Database with fields / Empty importer']['fieldstocreate'] = 0;
$basedprovider['Database with fields / Empty importer']['fieldstoremove'] = 3;
$basedprovider['Database with fields / Empty importer']['fieldstoupdate'] = 0;
$basedprovider['Same fields']['fieldstocreate'] = 0;
$basedprovider['Same fields']['fieldstoremove'] = 0;
$basedprovider['Same fields']['fieldstoupdate'] = 3;
$basedprovider['Fields to create']['fieldstocreate'] = 1;
$basedprovider['Fields to create']['fieldstoremove'] = 0;
$basedprovider['Fields to create']['fieldstoupdate'] = 2;
$basedprovider['Fields to remove']['fieldstocreate'] = 0;
$basedprovider['Fields to remove']['fieldstoremove'] = 1;
$basedprovider['Fields to remove']['fieldstoupdate'] = 3;
$basedprovider['Fields to update']['fieldstocreate'] = 1;
$basedprovider['Fields to update']['fieldstoremove'] = 1;
$basedprovider['Fields to update']['fieldstoupdate'] = 2;
$basedprovider['Fields to create, remove and update']['fieldstocreate'] = 1;
$basedprovider['Fields to create, remove and update']['fieldstoremove'] = 2;
$basedprovider['Fields to create, remove and update']['fieldstoupdate'] = 2;
return $basedprovider;
}
/**
* Test for set_affected_fields method.
*
* @dataProvider set_affected_provider
* @covers ::set_affected_fields
*
* @param array $currentfields Fields of the current activity.
* @param array $newfields Fields to be imported.
* @param string $pluginname The plugin preset to be imported.
* @param int $fieldstocreate Expected number of fields on $fieldstocreate.
* @param int $fieldstoremove Expected number of fields on $fieldstoremove.
* @param int $fieldstoupdate Expected number of fields on $fieldstoupdate.
*/
public function test_set_affected_fields(
array $currentfields,
array $newfields,
string $pluginname,
int $fieldstocreate,
int $fieldstoremove,
int $fieldstoupdate
) {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($currentfields as $field) {
$plugingenerator->create_field($field, $activity);
}
$manager = manager::create_from_instance($activity);
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($newfields as $field) {
$plugingenerator->create_field($field, $presetactivity);
}
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$fs = get_file_storage();
$file = $fs->create_file_from_pathname($filerecord, $fixturepath);
$uploadedimporter = new preset_upload_importer($manager, $file->get_filepath());
$saved = $plugingenerator->create_preset($presetactivity, $record);
$savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
$this->assertEquals(count($savedimporter->fieldstoremove), $fieldstoremove);
$this->assertEquals(count($savedimporter->fieldstocreate), $fieldstocreate);
$this->assertEquals(count($savedimporter->fieldstoupdate), $fieldstoupdate);
// Needs mapping returns false for empty databases.
$this->assertFalse($pluginimporter->needs_mapping());
$this->assertFalse($savedimporter->needs_mapping());
$this->assertFalse($uploadedimporter->needs_mapping());
// Add a field to the database.
$fieldrecord = new \stdClass();
$fieldrecord->name = 'field1';
$fieldrecord->type = 'text';
$plugingenerator->create_field($fieldrecord, $activity);
// Needs mapping returns true for non-empty databases.
$this->assertTrue($pluginimporter->needs_mapping());
$this->assertTrue($savedimporter->needs_mapping());
$this->assertTrue($uploadedimporter->needs_mapping());
// Create presets and importers.
if ($pluginname) {
$plugin = preset::create_from_plugin(null, $pluginname);
$pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
$this->assertEquals(count($pluginimporter->fieldstoremove), $fieldstoremove);
$this->assertEquals(count($pluginimporter->fieldstocreate), $fieldstocreate);
$this->assertEquals(count($pluginimporter->fieldstoupdate), $fieldstoupdate);
}
}
}