|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace FormRenderSkipLogic\Migration; |
| 4 | + |
| 5 | +use ExternalModules\ExternalModules; |
| 6 | + |
| 7 | +class Migration { |
| 8 | + |
| 9 | + private $PREFIX; |
| 10 | + |
| 11 | + function __construct($prefix) { |
| 12 | + $this->PREFIX = $prefix; |
| 13 | + } |
| 14 | + |
| 15 | + /** |
| 16 | + * checks if FRSL settings for specified version exist. Does not support version |
| 17 | + * 1. Will return false for any invalid version. |
| 18 | + * @param string $version, module version in REDCap format e.g. 'v3.1.1' |
| 19 | + * @return boolean, true if they exist, false otherwise |
| 20 | + */ |
| 21 | + function checkIfVersionSettingsExist($version) { |
| 22 | + $module_id = $this->getFRSLModuleId(); |
| 23 | + |
| 24 | + $q = "SELECT 1 FROM redcap_external_module_settings WHERE external_module_id='$module_id' AND `key` IN "; |
| 25 | + |
| 26 | + if (preg_match("/v2\.[0-9]+(\.[0-9]+)?/", $version)) { |
| 27 | + $q .= "('control_field', 'event_name', 'event_name', 'field_name', 'enabled_before_ctrl_field_is_set', 'target_instruments', 'instrument_name', 'control_field_value')"; |
| 28 | + } else if (preg_match("/v3\.[0-9]+(\.[0-9]+)?/", $version)) { |
| 29 | + $q .= "('control_fields', 'control_mode', 'control_event_id', 'control_field_key', 'control_piping', 'control_default_value', 'branching_logic', 'condition_operator', 'condition_value', 'target_forms', 'target_events_select', 'target_events')"; |
| 30 | + } else { |
| 31 | + return false; |
| 32 | + } |
| 33 | + |
| 34 | + $result = ExternalModules::query($q); |
| 35 | + |
| 36 | + //if we got something return true, otherwise false |
| 37 | + $settings_exist = !empty($result->fetch_assoc()); |
| 38 | + |
| 39 | + return $settings_exist; |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * gets external module_id for FRSL. |
| 44 | + * cannot use ExternalModules::getIdForPrefix() because it is private. |
| 45 | + */ |
| 46 | + function getFRSLModuleId() { |
| 47 | + $q = "SELECT external_module_id FROM redcap_external_modules where directory_prefix = '" . $this->PREFIX . "'" ; |
| 48 | + $result = ExternalModules::query($q); |
| 49 | + $id = $result->fetch_assoc()['external_module_id']; |
| 50 | + |
| 51 | + return $id; |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * gets FRSLv2.x.x settings for each as an associative array indexed by |
| 56 | + * project_id, where each project setting is an associative array indexed by |
| 57 | + * setting name and maps to a setting value |
| 58 | + * @return array $settings |
| 59 | + */ |
| 60 | + function getV2Settings() { |
| 61 | + $module_id = $this->getFRSLModuleId(); |
| 62 | + |
| 63 | + //get old settings data |
| 64 | + $q = "SELECT project_id, `key`, value FROM redcap_external_module_settings WHERE external_module_id='$module_id' AND `key` IN ('control_field', 'event_name', 'event_name', 'field_name', 'enabled_before_ctrl_field_is_set', 'target_instruments', 'instrument_name', 'control_field_value')"; |
| 65 | + $result = ExternalModules::query($q); |
| 66 | + |
| 67 | + //create data stucture to represent old settings data |
| 68 | + $settings = []; |
| 69 | + while($row = $result->fetch_assoc()) { |
| 70 | + $project_id = $row["project_id"]; |
| 71 | + $key = $row["key"]; |
| 72 | + $value = $row["value"]; |
| 73 | + $settings[$project_id][$key] = $value; |
| 74 | + } |
| 75 | + |
| 76 | + return $settings; |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * converts settings from from FRSL_v2.X to FRSL_v3.X |
| 81 | + * @param array $old_settings, array of v2 settings indexed by project_id |
| 82 | + * @return array $new_settings, array of v3 settings indexed by project_id |
| 83 | + */ |
| 84 | + function convertV2SettingsToV3Settings($old_settings) { |
| 85 | + $new_settings = []; |
| 86 | + foreach ($old_settings as $project_id => $old_setting) { |
| 87 | + |
| 88 | + //generate branching_logic settings using old values |
| 89 | + $old_instrument_names = json_decode($old_setting["instrument_name"]); |
| 90 | + $old_instrument_count = count($old_instrument_names); |
| 91 | + $old_control_field_values = json_decode($old_setting["control_field_value"]); |
| 92 | + $branching_logic = []; |
| 93 | + $condition_operator = []; |
| 94 | + $condition_value = []; |
| 95 | + $target_forms = []; |
| 96 | + $target_events_select = []; |
| 97 | + $target_events = []; |
| 98 | + |
| 99 | + for($i = 0; $i < $old_instrument_count; $i++) { |
| 100 | + //check if a branching_logic setting already exists for this instrument |
| 101 | + $index = array_search($old_control_field_values[$i], $condition_value); |
| 102 | + |
| 103 | + if($index !== false) { |
| 104 | + //append instrument to existing branching_logic configuration |
| 105 | + $target_forms[$index][] = $old_instrument_names[$i]; |
| 106 | + } else { |
| 107 | + //create a new branching_logic sub setting |
| 108 | + $branching_logic[] = true; |
| 109 | + $condition_operator[] = null; |
| 110 | + $condition_value[] = $old_control_field_values[$i]; |
| 111 | + $target_forms[] = [$old_instrument_names[$i]]; |
| 112 | + $target_events_select[] = false; |
| 113 | + $target_events[] = [null]; |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + //convert to nested JSON-arrays for storage |
| 118 | + $branching_logic = "[" . json_encode($branching_logic) . "]"; |
| 119 | + $condition_operator = "[" . json_encode($condition_operator) . "]"; |
| 120 | + $condition_value = "[" . json_encode($condition_value) . "]"; |
| 121 | + $target_forms = "[" . json_encode($target_forms) . "]"; |
| 122 | + $target_events_select = "[" . json_encode($target_events_select) . "]"; |
| 123 | + $target_events = "[" . json_encode($target_events) . "]"; |
| 124 | + |
| 125 | + //create sub-structure for project setting |
| 126 | + $setting = []; |
| 127 | + |
| 128 | + $setting["control_fields"] = $old_setting["control_field"]; |
| 129 | + $setting["control_mode"] = '["default"]'; |
| 130 | + $setting["control_event_id"] = $old_setting["event_name"]; |
| 131 | + $setting["control_field_key"] = $old_setting["field_name"]; |
| 132 | + $setting["control_piping"] = "[null]"; |
| 133 | + $setting["control_default_value"] = "[null]"; |
| 134 | + $setting["branching_logic"] = $branching_logic; |
| 135 | + $setting["condition_value"] = $condition_value; |
| 136 | + $setting["condition_operator"] = $condition_operator; |
| 137 | + $setting["target_forms"] = $target_forms; |
| 138 | + $setting["target_events_select"] = $target_events_select; |
| 139 | + $setting["target_events"] = $target_events; |
| 140 | + |
| 141 | + //store in main data structure |
| 142 | + $new_settings[$project_id] = $setting; |
| 143 | + } |
| 144 | + |
| 145 | + return $new_settings; |
| 146 | + |
| 147 | + } |
| 148 | + |
| 149 | + /** |
| 150 | + * stores FRSL_v3.X created by convert2XSettingsTo3XSettings method into db |
| 151 | + * @param array $settings, array of v3 settings indexed by project_id and |
| 152 | + * maps to a array of setting keys pointing to their associated values. |
| 153 | + */ |
| 154 | + function storeV3Settings($settings) { |
| 155 | + $module_id = $this->getFRSLModuleId(); |
| 156 | + |
| 157 | + foreach ($settings as $project_id => $setting) { |
| 158 | + $q = "INSERT INTO redcap_external_module_settings (external_module_id, project_id, `key`, type, value) VALUES "; |
| 159 | + |
| 160 | + //build query |
| 161 | + $values_to_insert = []; |
| 162 | + foreach ($setting as $key => $value) { |
| 163 | + $values_to_insert[] = "($module_id, $project_id, '$key', 'json-array', '$value')"; |
| 164 | + } |
| 165 | + |
| 166 | + $q .= join(",", $values_to_insert); |
| 167 | + ExternalModules::query($q); |
| 168 | + } |
| 169 | + } |
| 170 | +} |
| 171 | + |
| 172 | + ?> |
0 commit comments