Skip to content

Commit

Permalink
instance related settings deletion when an instance is being deleted,
Browse files Browse the repository at this point in the history
This PR fixes #40
  • Loading branch information
ferishili committed Dec 19, 2024
1 parent cc2ba67 commit 11bd5cd
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions classes/settings/admin_setting_configtextwithvalidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_configtextwithvalidation extends \admin_setting_configtext {

/** @var string the old value of the this setting. */
private $oldvalue;

/** @var string the newly saved value of the this setting. */
private $newlysavedvalue;

/**
* Validate data before storage
* @param mixed $data
Expand All @@ -50,12 +57,27 @@ public function validate($data) {
* @return bool|\lang_string|mixed|string empty string if successful, otherwise error message
*/
public function write_setting($data) {
// Recording the old settings, before writing new settings.
$this->oldvalue = $this->get_setting();

$failed = parent::write_setting($data);
if (!$failed) {

// Record newly saved settings that pass the validation, to work with later on.
$this->newlysavedvalue = $this->get_setting();

// Catching what is saved in terms of instance ids, to avoid propagating deleted ones!
$newocinstanceids = $this->get_new_instance_ids();

// Propagate changes to plugins.
$adminroot = admin_get_root();
$toolsettings = $adminroot->locate('tool_opencast');
foreach ($toolsettings->get_children() as $child) {
// Making sure that setting is current.
if (!$this->is_setting_current($child->name, $newocinstanceids)) {
continue;
}

if (substr($child->name, 0, 28) == 'tool_opencast_configuration_') {
foreach ($child->settings as $name => $setting) {
$data = $setting->get_setting();
Expand All @@ -71,6 +93,10 @@ public function write_setting($data) {
if (core_plugin_manager::instance()->get_plugin_info('block_opencast')) {
$blocksettings = $adminroot->locate('block_opencast');
foreach ($blocksettings->get_children() as $category) {
// Making sure that category is current.
if (!$this->is_setting_current($category->name, $newocinstanceids)) {
continue;
}
if ($category instanceof admin_category) {
foreach ($category->get_children() as $child) {
foreach ($child->settings as $name => $setting) {
Expand All @@ -91,15 +117,162 @@ public function write_setting($data) {
if (core_plugin_manager::instance()->get_plugin_info('mod_opencast')) {
$modsettings = $adminroot->locate('modsettingopencast');
foreach ($modsettings->settings as $name => $setting) {
// Making sure that setting is current.
if (!$this->is_setting_current($name, $newocinstanceids)) {
continue;
}
$data = $setting->get_setting();
if (is_null($data)) {
$data = $setting->get_defaultsetting();
$setting->write_setting($data);
}
}
}

// Perform setting deletions for those instances that do not exist!
// Since the main purpose of this function is already fulfilled, therefore we don't need to catch any errors during
// deletion, in order to prevent further confusion.
$this->perform_ocinstance_deletion();

return '';
}
return $failed;
}

/**
* Extracts the IDs of deleted Opencast instances.
*
* This method compares the old and new values of Opencast instance IDs and identifies
* which IDs have been deleted. It returns an array of deleted Opencast instance IDs.
*
* @return array An array of deleted Opencast instance IDs.
*/
private function extract_deleted_ocinstances(): array {
$deletedocinstanceids = [];
if (!empty($this->oldvalue)) {
try {
$oldocinstanceids = array_column(json_decode($this->oldvalue), 'id');

$newocinstanceids = $this->get_new_instance_ids();

// If there are ids in the old settings, but not in the new, then it mean those ids are being deleted.
$deletedocinstanceids = array_diff($oldocinstanceids, $newocinstanceids);
} catch (\moodle_exception $e) {
// Something went wrong during all the decoding and differing arrays, then return empty array,
// to avoid unwanted deletions.
$deletedocinstanceids = [];
}
}
return $deletedocinstanceids;
}

/**
* Checks if the given setting name corresponds to a current instance ID.
*
* This method extracts the instance ID from the setting name using a regular expression.
* It then checks if the extracted instance ID is present in the provided list of current instance IDs.
*
* @param string $settingname The name of the setting to check.
* @param array $currentinstanceids An array of current instance IDs to validate against.
* @return bool Returns true if the setting name corresponds to a current instance ID, false otherwise.
*/
private function is_setting_current(string $settingname, array $currentinstanceids): bool {
if (preg_match('#_(\d+)$#', $settingname, $matches)) {
$settinginstanceid = intval($matches[1]);
if ($settinginstanceid && !in_array($settinginstanceid, $currentinstanceids)) {
return false;
}
}
return true;
}

/**
* Retrieves the new instance IDs from the newly saved value.
*
* This method attempts to decode the JSON-encoded newly saved value and extract the 'id' fields
* from it. If the newly saved value is empty or an error occurs during decoding, an empty array
* is returned.
*
* @return array An array of new instance IDs.
*/
private function get_new_instance_ids(): array {
$newocinstanceids = [];
try {
if (!empty($this->newlysavedvalue)) {
$newocinstanceids = array_column(json_decode($this->newlysavedvalue), 'id');
}
} catch (\Throwable $th) {
$newocinstanceids = [];
}
return $newocinstanceids;
}

/**
* Deletes the Opencast instance configurations from the database.
*
* This method performs the deletion of Opencast instance configurations when instances are removed.
* It ensures that the deletion process is only executed when there are actual deletions to prevent
* unnecessary processing.
*
* @return void
*/
private function perform_ocinstance_deletion(): void {
global $DB;

// If there are no old values, we don't need to perform the deletion, as there are no instances to delete.
if (empty($this->oldvalue)) {
return;
}

// We check and extract deleted instances to ensure that the following laborious procedure
// is only executed when deletions occur. This prevents unnecessary processing for other operations.

$deletedocinstanceids = $this->extract_deleted_ocinstances();

// Nothing to delete, we return the process.
if (empty($deletedocinstanceids)) {
return;
}

// Setting plugins to loop through and find configs to delete.
$plugins = [
'tool_opencast',
'block_opencast',
'mod_opencast',
'filter_opencast',
];

// Preparing the (where clause) query for select.
$select = $DB->sql_equal('plugin', ':plugin') . " AND " . $DB->sql_like('name', ':confignamelike');

// First level of looping is to go through the deleted instances.
foreach ($deletedocinstanceids as $id) {

// In here we need to set the params value and determine the config name based on the ocinstance id.
$params = [
'confignamelike' => '%_' . $id,
];

// Second level of looping is to go through the plugins.
foreach ($plugins as $plugin) {

// In here we can determine the plugin name.
$params['plugin'] = $plugin;

// Now that the information to get the plugin configuration related to deleted instance is ready,
// we perform the select records query.
$selectedpluginconfigs = $DB->get_records_select('config_plugins', $select, $params, '', 'name');

// If we found something, we proceed to the deletion by using "unset_config".
if (!empty($selectedpluginconfigs)) {
foreach ($selectedpluginconfigs as $configrecord) {
if (!empty($configrecord->name)) {
// Very important to use "unset_config", because of taking care of cached configuration as well.
unset_config($configrecord->name, $plugin);
}
}
}
}
}
}
}

0 comments on commit 11bd5cd

Please sign in to comment.