migration.class.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * Scipt defining the Migration class
  4. */
  5. /**
  6. * Migration class (ease the migration work). This class *must* be extended
  7. * in a database server-specific implementation as migration.[DB].class.php
  8. */
  9. class Migration {
  10. /**
  11. * Origin DB type holder
  12. */
  13. public $odbtype = '';
  14. /**
  15. * Origin DB host holder
  16. */
  17. public $odbhost = '';
  18. /**
  19. * Origin DB port holder
  20. */
  21. public $odbport = '';
  22. /**
  23. * Origin DB user holder
  24. */
  25. public $odbuser = '';
  26. /**
  27. * Origin DB password holder
  28. */
  29. public $odbpass = '';
  30. /**
  31. * Origin DB name holder
  32. */
  33. public $odbname = '';
  34. /**
  35. * Array holding all errors/warnings ocurring during one execution
  36. */
  37. public $errors_stack = array();
  38. /**
  39. * Temporary handler for SQL result
  40. */
  41. public $odbrows = null;
  42. /**
  43. * Temporary holder for the list of users, courses and sessions and their
  44. * data. Store values here (preferably using the same indexes as the
  45. * destination database field names) until ready to insert into Chamilo.
  46. */
  47. public $data_list = array('users' => array(), 'courses' => array(), 'sessions' => array());
  48. /**
  49. * The constructor assigns all database connection details to the migration
  50. * object
  51. * @param string The original database's host
  52. * @param string The original database's port
  53. * @param string The original database's user
  54. * @param string The original database's password
  55. * @param string The original database's name
  56. * @return boolean False on error. Void on success.
  57. */
  58. public function __construct($dbhost, $dbport, $dbuser, $dbpass, $dbname) {
  59. if (empty($dbhost) || empty($dbport) || empty($dbuser) || empty($dbpass) || empty($dbname)) {
  60. $this->errors_stack[] = 'All origin database params must be given. Received ' . print_r(func_get_args(), 1);
  61. return false;
  62. }
  63. $this->odbtype = $dbtype;
  64. $this->odbhost = $dbhost;
  65. $this->odbport = $dbport;
  66. $this->odbuser = $dbuser;
  67. $this->odbpass = $dbpass;
  68. $this->odbname = $dbname;
  69. }
  70. /**
  71. * The connect method should be extended by the child class
  72. */
  73. public function connect() {
  74. //extend in child class
  75. }
  76. /**
  77. * The migrate method launches the migration process based on an array of
  78. * tables and fields matches defined in the given array.
  79. * @param array Structured array of matches (see migrate.php)
  80. */
  81. public function migrate($matches) {
  82. $found = false;
  83. $table_idx = -1;
  84. error_log("\n".'------------ Migration->migrate function called ------------'."\n");
  85. $extra_fields = array();
  86. foreach ($matches as $table) {
  87. error_log('Found table ' . $table['orig_table']);
  88. $build_only = false;
  89. if (empty($table['dest_table'])) {
  90. error_log(' ... which is just for data building');
  91. $build_only = true;
  92. }
  93. //Creating extra fields
  94. if (isset($table['extra_fields']) && in_array($table['dest_table'], array('course', 'user', 'session'))) {
  95. error_log('Inserting (if exists) extra fields for : ' . $table['dest_table']." \n");
  96. foreach ($table['extra_fields'] as $extra_field) {
  97. $options = $extra_field['options'];
  98. unset($extra_field['options']);
  99. $extra_field_obj = new ExtraField($table['dest_table']);
  100. $extra_field_id = $extra_field_obj->save($extra_field);
  101. $selected_fields = self::prepare_field_match($options);
  102. //error_log('$selected_fields: ' . print_r($selected_fields, 1));
  103. //Adding options
  104. if (!empty($options)) {
  105. $extra_field_option_obj = new ExtraFieldOption($table['dest_table']);
  106. $this->select_all($options['orig_table'], $selected_fields);
  107. $num_rows = $this->num_rows();
  108. if ($num_rows) {
  109. $data_to_insert = array();
  110. $data_to_insert['field_id'] = $extra_field_id;
  111. while ($row = $this->fetch_array()) {
  112. $data = self::execute_field_match($options, $row);
  113. $data_to_insert = array_merge($data_to_insert, $data);
  114. $extra_field_option_obj->save_one_item($data_to_insert, false, false);
  115. //error_log(print_r($extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']], 1));
  116. $extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']]['options'][] = $data_to_insert;
  117. $extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']]['field_type'] = $extra_field['field_type'];
  118. }
  119. //$extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']]['selected_option'] =
  120. //error_log('$data: ' . print_r($data_to_insert, 1));
  121. }
  122. } else {
  123. $extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']] = $extra_field_id;
  124. }
  125. }
  126. }
  127. // Process the migration of fields from the given table
  128. $sql_select_fields = self::prepare_field_match($table);
  129. $this->select_all($table['orig_table'], $sql_select_fields, $table);
  130. if (count($table['fields_match']) == 0) {
  131. error_log('No fields found');
  132. continue;
  133. }
  134. $num_rows = $this->num_rows();
  135. if ($num_rows) {
  136. error_log('Records found: '.$num_rows);
  137. $item = 1;
  138. while ($row = $this->fetch_array()) {
  139. //error_log('Loading: ');error_log(print_r($row, 1));
  140. self::execute_field_match($table, $row, $extra_fields);
  141. $percentage = $item / $num_rows*100;
  142. if (round($percentage) % 10 == 0) {
  143. $percentage = round($percentage, 3);
  144. error_log("Processing item {$table['orig_table']} #$item $percentage%") ;
  145. }
  146. $item++;
  147. }
  148. error_log('Finished processing table ' . $table['orig_table']." \n\n");
  149. } else {
  150. error_log('No records found');
  151. }
  152. //Stop here (only for tests)
  153. if ($table['orig_table'] == 'Matricula') {
  154. exit;
  155. }
  156. }
  157. }
  158. function prepare_field_match($table) {
  159. $sql_select_fields = array();
  160. foreach ($table['fields_match'] as $details) {
  161. if (empty($details['orig'])) {
  162. //Ignore if the field declared in $matches doesn't exist in
  163. // the original database
  164. continue;
  165. }
  166. $sql_select_fields[$details['orig']] = $details['orig'];
  167. // If there is something to alter in the SQL query, rewrite the entry
  168. if (!empty($details['sql_alter'])) {
  169. $func_alter = $details['sql_alter'];
  170. $sql_select_fields[$details['orig']] = MigrationCustom::$func_alter($details['orig']);
  171. }
  172. //error_log('Found field ' . $details['orig'] . ' to be selected as ' . $sql_select_fields[$details['orig']]);
  173. }
  174. return $sql_select_fields;
  175. }
  176. function execute_field_match($table, $row, $extra_fields) {
  177. //error_log('execute_field_match');
  178. $dest_row = array();
  179. $first_field = '';
  180. $my_extra_fields = isset($extra_fields[$table['dest_table']]) ? $extra_fields[$table['dest_table']] : null;
  181. $extra_field_obj = null;
  182. $extra_field_value_obj = null;
  183. if (!empty($table['dest_table'])) {
  184. $extra_field_obj = new Extrafield($table['dest_table']);
  185. $extra_field_value_obj = new ExtraFieldValue($table['dest_table']);
  186. }
  187. $extra_fields_to_insert = array();
  188. foreach ($table['fields_match'] as $id_field => $details) {
  189. if ($id_field == 0) {
  190. $first_field = $details['dest'];
  191. }
  192. if (isset($details['orig'])) {
  193. $field_exploded = explode('.', $details['orig']);
  194. if (isset($field_exploded[1])) {
  195. $details['orig'] = $field_exploded[1];
  196. }
  197. }
  198. // process the fields one by one
  199. if ($details['func'] == 'none' || empty($details['func'])) {
  200. $dest_data = $row[$details['orig']];
  201. } else {
  202. $dest_data = MigrationCustom::$details['func']($row[$details['orig']], $this->data_list, $row);
  203. }
  204. if (isset($dest_row[$details['dest']])) {
  205. $dest_row[$details['dest']] .= ' '.$dest_data;
  206. } else {
  207. $dest_row[$details['dest']] = $dest_data;
  208. }
  209. //Extra field values
  210. $extra_field = isset($my_extra_fields) && isset($my_extra_fields[$details['dest']]) ? $my_extra_fields[$details['dest']] : null;
  211. //error_log('-----');
  212. //error_log(print_r($extra_field, 1));
  213. if (!empty($extra_field) && $extra_field_obj) {
  214. if (isset($extra_field['options'])) {
  215. $options = $extra_field['options'];
  216. $field_type = $extra_field['field_type'];
  217. if (!empty($options)) {
  218. foreach ($options as $option) {
  219. foreach ($option as $key => $value) {
  220. //error_log("$key $value --> {$dest_row[$details['dest']]} ");
  221. if ($key == 'option_value' && $value == $dest_row[$details['dest']]) {
  222. $value = $option['option_display_text'];
  223. if ($field_type == Extrafield::FIELD_TYPE_SELECT) {
  224. $value = $option['option_display_text'];
  225. }
  226. $params = array(
  227. 'field_id' => $option['field_id'],
  228. 'field_value' => $value,
  229. );
  230. break(2);
  231. }
  232. }
  233. }
  234. }
  235. } else {
  236. $params = array(
  237. 'field_id' => $extra_field,
  238. 'field_value' => $dest_row[$details['dest']],
  239. );
  240. }
  241. if (!empty($params)) {
  242. $extra_fields_to_insert[] = $params;
  243. }
  244. unset($dest_row[$details['dest']]);
  245. }
  246. }
  247. if (!empty($table['dest_func'])) {
  248. //error_log('Calling '.$table['dest_func'].' on data recovered: '.print_r($dest_row, 1));
  249. $dest_row['return_item_if_already_exists'] = true;
  250. $item_result = call_user_func_array($table['dest_func'], array($dest_row, $this->data_list));
  251. if ($table['show_in_error_log'] == false) {
  252. } else {
  253. error_log('Result of calling ' . $table['dest_func'] . ': ' . print_r($item_result, 1));
  254. }
  255. //error_log('Result of calling ' . $table['dest_func'] . ': ' . print_r($item_result, 1));
  256. //After the function was executed fill the $this->data_list array
  257. switch ($table['dest_table']) {
  258. case 'course':
  259. //Saving courses in array
  260. if ($item_result) {
  261. $this->data_list['courses'][$dest_row['uidIdCurso']] = $item_result;
  262. } else {
  263. error_log('Course Not FOUND');
  264. error_log(print_r($item_result, 1));
  265. exit;
  266. }
  267. $handler_id = $item_result['code'];
  268. break;
  269. case 'user':
  270. if (!empty($item_result)) {
  271. $handler_id = $item_result['user_id'];
  272. //error_log($dest_row['email'].' '.$dest_row['uidIdPersona']);
  273. if (isset($dest_row['uidIdAlumno'])) {
  274. $this->data_list['users_alumno'][$dest_row['uidIdAlumno']]['extra'] = $item_result;
  275. }
  276. if (isset($dest_row['uidIdEmpleado'])) {
  277. //print_r($dest_row['uidIdEmpleado']);exit;
  278. $this->data_list['users_empleado'][$dest_row['uidIdEmpleado']]['extra'] = $item_result;
  279. }
  280. } else {
  281. global $api_failureList;
  282. error_log(print_r($api_failureList, 1));
  283. }
  284. break;
  285. case 'session':
  286. $this->data_list['sessions'][$dest_row['uidIdPrograma']] = $item_result;
  287. $handler_id = $item_result; //session_id
  288. break;
  289. }
  290. //Saving extra fields of the element
  291. if (!empty($extra_fields_to_insert)) {
  292. foreach ($extra_fields_to_insert as $params) {
  293. $params[$extra_field_value_obj->handler_id] = $handler_id;
  294. $extra_field_value_obj->save($params);
  295. }
  296. }
  297. } else {
  298. $this->errors_stack[] = "No destination data dest_func found. Abandoning data with first field $first_field = " . $dest_row[$first_field];
  299. }
  300. return $dest_row;
  301. }
  302. }