migration.class.php 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  1. <?php
  2. /**
  3. * Scipt defining the Migration class
  4. * @package chamilo.migration
  5. */
  6. /**
  7. * Migration class (ease the migration work). This class *must* be extended
  8. * in a database server-specific implementation as migration.[DB].class.php
  9. */
  10. class Migration {
  11. /**
  12. * Origin DB type holder
  13. */
  14. public $odbtype = '';
  15. /**
  16. * Origin DB host holder
  17. */
  18. public $odbhost = '';
  19. /**
  20. * Origin DB port holder
  21. */
  22. public $odbport = '';
  23. /**
  24. * Origin DB user holder
  25. */
  26. public $odbuser = '';
  27. /**
  28. * Origin DB password holder
  29. */
  30. public $odbpass = '';
  31. /**
  32. * Origin DB name holder
  33. */
  34. public $odbname = '';
  35. /**
  36. * Array holding all errors/warnings ocurring during one execution
  37. */
  38. public $errors_stack = array();
  39. /**
  40. * Temporary handler for SQL result
  41. */
  42. public $odbrows = null;
  43. public $web_service_connection_info = array();
  44. /**
  45. * The constructor assigns all database connection details to the migration
  46. * object
  47. * @param string The original database's host
  48. * @param string The original database's port
  49. * @param string The original database's user
  50. * @param string The original database's password
  51. * @param string The original database's name
  52. * @return boolean False on error. Void on success.
  53. */
  54. public function __construct($dbhost = null, $dbport = null, $dbuser = null, $dbpass = null, $dbname = null, $boost = false) {
  55. if (empty($dbhost) || empty($dbport) || empty($dbuser) || empty($dbpass) || empty($dbname)) {
  56. $this->errors_stack[] = 'All origin database params must be given. Received ' . print_r(func_get_args(), 1);
  57. //return false;
  58. }
  59. //$this->odbtype = $dbtype;
  60. $this->odbhost = $dbhost;
  61. $this->odbport = $dbport;
  62. $this->odbuser = $dbuser;
  63. $this->odbpass = $dbpass;
  64. $this->odbname = $dbname;
  65. // Set the boost level if set in config.php
  66. if (!empty($boost) && is_array($boost)) {
  67. global $data_list;
  68. foreach ($boost as $item => $val) {
  69. if ($val == true) {
  70. $data_list[$item] = true;
  71. }
  72. }
  73. }
  74. }
  75. /**
  76. * The connect method should be extended by the child class
  77. */
  78. public function connect() {
  79. //extend in child class
  80. }
  81. public function set_web_service_connection_info($matches) {
  82. $this->web_service_connection_info = $matches['web_service_calls'];
  83. }
  84. /**
  85. * The migrate method launches the migration process based on an array of
  86. * tables and fields matches defined in the given array.
  87. * @param array Structured array of matches (see migrate.php)
  88. */
  89. public function migrate($matches) {
  90. error_log("\n" . '------------ ['.date('H:i:s').'] Migration->migrate function called ------------' . "\n");
  91. $extra_fields = array();
  92. global $data_list, $utc_datetime;
  93. define('USER_FUNC_EXCEPTION_GRADEBOOK','MigrationCustom::add_gradebook_result_with_evaluation');
  94. define('USER_FUNC_EXCEPTION_ATTENDANCE','MigrationCustom::create_attendance');
  95. // Browsing through 1st-level arrays in db_matches.php
  96. foreach ($matches as $idx => $table) {
  97. if ($idx === 'web_service_calls') { continue;}
  98. echo "Starting table ".$table['orig_table']." at ".date('h:i:s')."\n";
  99. error_log('['.date('H:i:s').'] Found table ' . $table['orig_table'] . ' in db_matches');
  100. $build_only = false;
  101. if (empty($table['dest_table'])) {
  102. //If there is no destination for this table, report
  103. error_log(' ... which is just for data collection');
  104. $build_only = true;
  105. }
  106. // Creating extra fields if necessary inside Chamilo (to store
  107. // original fields)
  108. if (isset($table['extra_fields']) && in_array($table['dest_table'], array('course', 'user', 'session'))) {
  109. $extra_fields = self::_create_extra_fields($table);
  110. }
  111. // Process the migration of fields from the given table
  112. $sql_select_fields = self::prepare_field_match($table);
  113. $this->select_all($table['orig_table'], $sql_select_fields, $table);
  114. if (count($table['fields_match']) == 0) {
  115. error_log('No fields found');
  116. continue;
  117. }
  118. $num_rows = $this->num_rows();
  119. $data_list['create_attendance'] = array();
  120. $data_list['create_eval_results'] = array();
  121. $data_list['create_eval_results_limit'] = 200;
  122. if ($num_rows) {
  123. error_log('Records found: ' . $num_rows);
  124. $item = 1;
  125. $lastpct = 0;
  126. //error_log(print_r($table['extra_fields'],1));
  127. $save_row = array();
  128. while ($row = $this->fetch_array()) {
  129. $utc_datetime = api_get_utc_datetime();
  130. self::execute_field_match($table, $row, $extra_fields);
  131. $percentage = ($item / $num_rows) * 100;
  132. $newpct = intval($percentage);
  133. if ($newpct>$lastpct && floor($percentage) % 10 == 0) {
  134. $percentage = round($percentage, 3);
  135. $lastpct = $newpct;
  136. error_log("Processing item {$table['orig_table']} #$item $percentage% (to put into ".$table['dest_table'].")");
  137. }
  138. $item++;
  139. $save_row = $row;
  140. }
  141. if (count($data_list['create_attendance']) > 0) {
  142. $limit = 100;
  143. $fill = $limit - count($data_list['create_attendance']);
  144. for ($ijk = 0; $ijk<$fill; $ijk++) {
  145. $data_list['create_attendance'][] = array();
  146. }
  147. self::execute_field_match($table, $save_row, $extra_fields);
  148. error_log('Executing '.($limit-$fill).'remains of create_attendance list');
  149. $data_list['create_attendance'] = array();
  150. }
  151. if (count($data_list['create_eval_results']) > 0) {
  152. $limit = $data_list['create_eval_results_limit'];
  153. $fill = $limit - count($data_list['create_eval_results']);
  154. for ($ijk = 0; $ijk<$fill; $ijk++) {
  155. $data_list['create_eval_results'][] = array();
  156. }
  157. self::execute_field_match($table, $save_row, $extra_fields);
  158. error_log('Executing '.($limit-$fill).'remains of create_eval_results list');
  159. $data_list['create_eval_results'] = array();
  160. }
  161. error_log('Finished processing table ' . $table['orig_table'] . " \n\n");
  162. } else {
  163. error_log('No records found');
  164. }
  165. //Stop here (only for tests)
  166. //if ($table['orig_table'] == 'gradebook_evaluation_type') {
  167. //exit;
  168. //}
  169. }
  170. }
  171. /**
  172. * Call the SOAP web service as detailed in the parameters
  173. * @param array Settings for the WS call
  174. * @param string Name of the function to call
  175. * @param array Variables to be passed as params to the function
  176. * @return array Results as returned by the SOAP call
  177. */
  178. static function soap_call($web_service_params, $function_name, $params = array()) {
  179. // Create the client instance
  180. $url = $web_service_params['url'];
  181. try {
  182. $client = new SoapClient($url, array('cache_wsdl' => WSDL_CACHE_NONE));
  183. } catch (SoapFault $fault) {
  184. $error = 1;
  185. return false;
  186. //die('Error connecting');
  187. }
  188. $client->debug_flag = true;
  189. try {
  190. $data = $client->$function_name($params);
  191. } catch (SoapFault $fault) {
  192. $error = 2;
  193. //die("Problem querying service - $function_name");
  194. return array(
  195. 'error' => true,
  196. 'message' => "Problem querying service - $function_name in URL $url with params: ".print_r($params, 1),
  197. 'status_id' => 0
  198. );
  199. }
  200. if (!empty($data)) {
  201. error_log("Calling MigrationCustom::$function_name $url with params: ".print_r($params,1));
  202. return MigrationCustom::$function_name($data, $params);
  203. } else {
  204. return array(
  205. 'error' => true,
  206. 'message' => "No data found when calling $function_name in URL $url with params: ".print_r($params, 1),
  207. 'status_id' => 0
  208. );
  209. }
  210. }
  211. function clean_all_transactions() {
  212. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  213. $sql = "TRUNCATE $table";
  214. Database::query($sql);
  215. }
  216. /**
  217. * Test a series of hand-crafted transactions
  218. * @param array of parameters that would usually get passed to the web service
  219. * @param bool Whether to truncate the transaction table before the test or not
  220. * @return void
  221. */
  222. function insert_test_transactions($truncate = false) {
  223. error_log('insert_test_transactions');
  224. //Just for tests
  225. //Cleaning transaction table
  226. if ($truncate) {
  227. $this->clean_all_transactions();
  228. }
  229. $transaction_hardcoded = array(
  230. array(
  231. //'action' => 'usuario_agregar',
  232. 'action' => 1,
  233. 'transaction_id' => 1000,
  234. 'item_id' => 'D236776B-D7A5-47FF-8328-55EBE9A59015',
  235. 'orig_id' => null,
  236. 'branch_id' => 1,
  237. 'dest_id' => null,
  238. 'status_id' => 0
  239. ),
  240. array(
  241. //'action' => 'usuario_editar',
  242. 'transaction_id' => 1001,
  243. 'action' => 3,
  244. 'item_id' => 'D236776B-D7A5-47FF-8328-55EBE9A59015',
  245. 'orig_id' => '0',
  246. 'branch_id' => 1,
  247. 'dest_id' => null,
  248. 'status_id' => 0
  249. ),
  250. array(
  251. 'transaction_id' => 1002,
  252. //'action' => 'usuario_eliminar',
  253. 'action' => 2,
  254. 'item_id' => 'D236776B-D7A5-47FF-8328-55EBE9A59015',
  255. 'orig_id' => '0',
  256. 'branch_id' => 1,
  257. 'dest_id' => null,
  258. 'status_id' => 0
  259. ),
  260. array(
  261. 'transaction_id' => 1003,
  262. //'action' => 'usuario_matricula',
  263. 'action' => 4,
  264. 'item_id' => '95EDA88F-D729-450F-95FF-4A3989244F53', //usuario - Abel
  265. 'orig_id' => null, //session orig
  266. 'dest_id' => 'C3671999-095E-4018-9826-678BAFF595DF', //session dest
  267. 'branch_id' => 1,
  268. 'status_id' => 0
  269. ),
  270. array(
  271. 'transaction_id' => 1004,
  272. //'action' => 'curso_agregar',
  273. 'action' => 5,
  274. 'item_id' => 'E2334974-9D55-4BB4-8B57-FCEFBE2510DC',
  275. 'orig_id' => null,
  276. 'dest_id' => null,
  277. 'branch_id' => 1,
  278. 'status_id' => 0
  279. ),
  280. array(
  281. 'transaction_id' => 1005,
  282. //'action' => 'curso_eliminar',
  283. 'action' => 6,
  284. 'item_id' => 'E2334974-9D55-4BB4-8B57-FCEFBE2510DC',
  285. 'orig_id' => null,
  286. 'dest_id' => null,
  287. 'branch_id' => 1,
  288. 'status_id' => 0
  289. ),
  290. array(
  291. 'transaction_id' => 1006,
  292. //'action' => 'curso_editar',
  293. 'action' => 7,
  294. 'item_id' => '31B4BD38-5D90-4275-88AF-F01F0274800A', // ONE (SATURDAYS)
  295. 'orig_id' => '0',
  296. 'branch_id' => 1,
  297. 'dest_id' => null,
  298. 'status_id' => 0
  299. ),
  300. array(
  301. //'action' => 'curso_matricula',
  302. 'item_id' => 'E2334974-9D55-4BB4-8B57-FCEFBE2510DC', //course
  303. 'orig_id' => null,
  304. 'dest_id' => 'C3671999-095E-4018-9826-678BAFF595DF', //session
  305. 'branch_id' => 1,
  306. 'status_id' => 0
  307. ),
  308. array(
  309. //'action' => 'pa_agregar',
  310. 'transaction_id' => 1007,
  311. 'action' => 8,
  312. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',
  313. 'orig_id' => null,
  314. 'dest_id' => null,
  315. 'branch_id' => 1,
  316. 'status_id' => 0
  317. ),
  318. array(
  319. //'action' => 'pa_editar',
  320. 'transaction_id' => 1008,
  321. 'action' => 10,
  322. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',
  323. 'orig_id' => '0',
  324. 'dest_id' => null,
  325. 'branch_id' => 1,
  326. 'status_id' => 0
  327. ),
  328. array(
  329. //'action' => 'pa_eliminar',
  330. 'transaction_id' => 1009,
  331. 'action' => 9,
  332. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF', //id to delete
  333. 'orig_id' => null,
  334. 'branch_id' => 1,
  335. 'dest_id' => null,
  336. 'status_id' => 0
  337. ),
  338. // seems not to be used
  339. array(
  340. //'action' => 'pa_cambiar_aula',
  341. 'action' => 11,
  342. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',
  343. 'orig_id' => '0',
  344. 'dest_id' => '',
  345. 'branch_id' => 1,
  346. 'status_id' => 0
  347. ),
  348. array(
  349. 'transaction_id' => 1010,
  350. //'action' => 'pa_cambiar_horario',
  351. 'action' => 12,
  352. 'item_id' => 'B94FEBA2-7EAD-4E14-B3DA-1D02397D1FA1', //session id - 200910 (A02M) Advanced Oral Communication Skills 2 08:45 10:15 701 00003
  353. 'orig_id' => '63D661DB-0A2F-47FC-94C0-5AA46BE7DA66', // (01) 07:00 09:00
  354. 'branch_id' => 1,
  355. 'dest_id' => 'B4FE6E83-F33F-417B-8B3F-C24CB94264EA', //(02) 09:00 11:00
  356. 'status_id' => 0
  357. ),
  358. array(
  359. //'action' => 'pa_cambiar_sede',
  360. 'action' => 'x',
  361. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',//session id
  362. 'orig_id' => '0',
  363. 'dest_id' => null,
  364. 'branch_id' => 1,
  365. 'status_id' => 0
  366. ),
  367. array(
  368. 'action' => 'cambiar_pa_fase',
  369. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',//session id
  370. 'orig_id' => '0',
  371. 'dest_id' => null,
  372. 'branch_id' => 1,
  373. 'status_id' => 0
  374. ),
  375. array(
  376. 'action' => 'cambiar_pa_intensidad',
  377. 'item_id' => 'C3671999-095E-4018-9826-678BAFF595DF',
  378. 'orig_id' => '0',
  379. 'branch_id' => 1,
  380. 'dest_id' => null,
  381. 'status_id' => 0
  382. ),
  383. array(
  384. //'action' => 'horario_agregar',
  385. 'transaction_id' => 1010,
  386. 'action' => 13,
  387. 'item_id' => 'E395895A-B480-456F-87F2-36B3A1EBB81C', // horario
  388. 'orig_id' => '0',
  389. 'branch_id' => 1,
  390. 'dest_id' => null,
  391. 'status_id' => 0
  392. ),
  393. array(
  394. 'transaction_id' => 1011,
  395. //'action' => 'horario_editar',
  396. 'action' => 15,
  397. 'item_id' => 'E395895A-B480-456F-87F2-36B3A1EBB81C',
  398. 'orig_id' => '0',
  399. 'dest_id' => null,
  400. 'branch_id' => 1,
  401. 'status_id' => 0
  402. ),
  403. array(
  404. //'action' => 'horario_eliminar',
  405. 'action' => 14,
  406. 'transaction_id' => 1012,
  407. 'item_id' => 'E395895A-B480-456F-87F2-36B3A1EBB81C',
  408. 'orig_id' => '0',
  409. 'dest_id' => null,
  410. 'branch_id' => 1,
  411. 'status_id' => 0
  412. ),
  413. array(
  414. //'action' => 'aula_agregar',
  415. 'action' => 16,
  416. 'item_id' => '1',
  417. 'orig_id' => '0',
  418. 'branch_id' => 1,
  419. 'dest_id' => null,
  420. 'status_id' => 0
  421. ),
  422. array(
  423. //'action' => 'aula_eliminar',
  424. 'action' => 17,
  425. 'item_id' => '1',
  426. 'orig_id' => '0',
  427. 'branch_id' => 1,
  428. 'dest_id' => null,
  429. 'status_id' => 0
  430. ),
  431. array(
  432. //'action' => 'aula_editar',
  433. 'action' => 18,
  434. 'item_id' => '1',
  435. 'orig_id' => '0',
  436. 'branch_id' => 1,
  437. 'dest_id' => null,
  438. 'status_id' => 0
  439. ),
  440. array(
  441. //'action' => 'sede_agregar',
  442. 'action' => 19,
  443. 'transaction_id' => 1013,
  444. 'item_id' => '7379A7D3-6DC5-42CA-9ED4-97367519F1D9',
  445. 'orig_id' => '0',
  446. 'branch_id' => 1,
  447. 'dest_id' => null,
  448. 'status_id' => 0
  449. ),
  450. array(
  451. //'action' => 'sede_editar',
  452. 'action' => 21,
  453. 'transaction_id' => 1014,
  454. 'item_id' => '7379A7D3-6DC5-42CA-9ED4-97367519F1D9',
  455. 'orig_id' => '0',
  456. 'branch_id' => 1,
  457. 'dest_id' => null,
  458. 'status_id' => 0
  459. ),
  460. array(
  461. //'action' => 'sede_eliminar',
  462. 'action' => 20,
  463. 'transaction_id' => 1015,
  464. 'item_id' => '7379A7D3-6DC5-42CA-9ED4-97367519F1D9',
  465. 'orig_id' => '0',
  466. 'branch_id' => 1,
  467. 'dest_id' => null,
  468. 'status_id' => 0
  469. ),
  470. array(
  471. //'action' => 'frecuencia_agregar',
  472. 'action' => 22,
  473. 'transaction_id' => 1016,
  474. 'item_id' => '0091CD3B-F042-11D7-B338-0050DAB14015',
  475. 'orig_id' => '0',
  476. 'branch_id' => 1,
  477. 'dest_id' => null,
  478. 'status_id' => 0
  479. ),
  480. array(
  481. //'action' => 'frecuencia_editar',
  482. 'transaction_id' => 1017,
  483. 'action' => 24,
  484. 'item_id' => '0091CD3B-F042-11D7-B338-0050DAB14015',
  485. 'orig_id' => '0',
  486. 'branch_id' => 1,
  487. 'dest_id' => null,
  488. 'status_id' => 0
  489. ),
  490. array(
  491. //'action' => 'frecuencia_eliminar',
  492. 'transaction_id' => 1018,
  493. 'action' => 23,
  494. 'item_id' => '0091CD3B-F042-11D7-B338-0050DAB14015',
  495. 'orig_id' => '0',
  496. 'branch_id' => 1,
  497. 'dest_id' => null,
  498. 'status_id' => 0
  499. ),
  500. array(
  501. //'action' => 'intensidad_agregar',
  502. 'transaction_id' => 1019,
  503. 'action' => 25,
  504. 'item_id' => '0091CD3C-F042-11D7-B338-0050DAB14015',
  505. 'orig_id' => '0',
  506. 'branch_id' => 1,
  507. 'dest_id' => null,
  508. 'status_id' => 0
  509. ),
  510. array(
  511. //'action' => 'intensidad_editar',
  512. 'transaction_id' => 1020,
  513. 'action' => 27,
  514. 'item_id' => '0091CD3C-F042-11D7-B338-0050DAB14015',
  515. 'orig_id' => '0',
  516. 'branch_id' => 1,
  517. 'dest_id' => null,
  518. 'status_id' => 0
  519. ),
  520. array(
  521. //'action' => 'intensidad_eliminar',
  522. 'transaction_id' => 1021,
  523. 'action' => 26,
  524. 'item_id' => '0091CD3C-F042-11D7-B338-0050DAB14015',
  525. 'orig_id' => '0',
  526. 'branch_id' => 1,
  527. 'dest_id' => null,
  528. 'status_id' => 0
  529. ),
  530. //Notas
  531. array(
  532. //'action' => 'TRANSACTION_TYPE_ADD_NOTA',
  533. 'transaction_id' => 1031,
  534. 'action' => 31,
  535. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  536. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB', ///session_id
  537. 'branch_id' => 1,
  538. 'dest_id' => null,
  539. 'status_id' => 0
  540. ),
  541. array(
  542. //'action' => 'TRANSACTION_TYPE_DEL_NOTA',
  543. 'transaction_id' => 1032,
  544. 'action' => 32,
  545. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  546. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB',
  547. 'branch_id' => 1,
  548. 'dest_id' => null,
  549. 'status_id' => 0
  550. ),
  551. array(
  552. //'action' => 'TRANSACTION_TYPE_EDIT_NOTA',
  553. 'transaction_id' => 1033,
  554. 'action' => 33,
  555. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  556. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB',
  557. 'branch_id' => 1,
  558. 'dest_id' => null,
  559. 'status_id' => 0
  560. ),
  561. array(
  562. //'action' => 'TRANSACTION_TYPE_ADD_ASSIST',
  563. 'transaction_id' => 1034,
  564. 'action' => 34,
  565. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  566. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB',
  567. 'branch_id' => 1,
  568. 'dest_id' => null,
  569. 'status_id' => 0
  570. ),
  571. array(
  572. //'action' => 'TRANSACTION_TYPE_DEL_ASSIST',
  573. 'transaction_id' => 1035,
  574. 'action' => 35,
  575. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  576. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB',
  577. 'branch_id' => 1,
  578. 'dest_id' => null,
  579. 'status_id' => 0
  580. ),
  581. array(
  582. //'action' => 'TRANSACTION_TYPE_EDIT_ASSIST',
  583. 'transaction_id' => 1036,
  584. 'action' => 36,
  585. 'item_id' => '2C901CB8-E0A2-412E-A754-3B18AE7F3C02',
  586. 'orig_id' => 'A33ADE80-F62B-4760-8C16-000B81E1C6AB',
  587. 'branch_id' => 1,
  588. 'dest_id' => null,
  589. 'status_id' => 0
  590. ),
  591. );
  592. foreach ($transaction_hardcoded as $transaction) {
  593. $transaction['branch_id'] = 2;
  594. /*if ($transaction['action'] < 31) {
  595. continue;
  596. }*/
  597. self::add_transaction($transaction);
  598. }
  599. }
  600. /**
  601. * Adds a given transaction to the transactions table in Chamilo
  602. * @param array The transaction details (array('id' => ..., 'action' => '...', ...))
  603. * @return int The ID of the transaction row in Chamilo's table
  604. */
  605. static function add_transaction($params) {
  606. //error_log('Requested add_transaction of : '.print_r($params,1));
  607. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  608. if (isset($params['id'])) {
  609. unset($params['id']);
  610. }
  611. $params['time_update'] = $params['time_insert'] = api_get_utc_datetime();
  612. $inserted_id = Database::insert($table, $params);
  613. //if ($inserted_id) {
  614. //error_log("Transaction added #$inserted_id");
  615. //}
  616. return $inserted_id;
  617. }
  618. /**
  619. * Get all available branches (the migration system supports multiple origin databases, the branch identifies which database it comes from)
  620. * @return array Branches IDs (int)
  621. */
  622. static function get_branches() {
  623. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  624. $sql = "SELECT DISTINCT branch_id FROM $table ORDER BY branch_id";
  625. $result = Database::query($sql);
  626. if (Database::num_rows($result) > 0) {
  627. return Database::store_result($result, 'ASSOC');
  628. }
  629. return array(
  630. 0 => array('branch_id' => 1),
  631. 1 => array('branch_id' => 2),
  632. 2 => array('branch_id' => 3),
  633. 3 => array('branch_id' => 4),
  634. 4 => array('branch_id' => 5),
  635. );
  636. }
  637. /**
  638. * Gets transactions in a specific state (for example to get all non-processed transactions) from the Chamilo transactions table
  639. * @param int State ID (0=unprocessed (default), 2=completed)
  640. * @param int Branch ID
  641. * @return array Associative array containing the details of the transactions requested
  642. */
  643. static function get_transactions($status_id = 0, $branch_id = 0) {
  644. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  645. $branch_id = intval($branch_id);
  646. $status_id = intval($status_id);
  647. //$extra_conditions = " AND branch_id = $branch_id ";
  648. // Temporary patch to avoid attendances and gradebook transactions
  649. $extra_conditions = " AND branch_id = $branch_id";
  650. $sql = "SELECT * FROM $table WHERE status_id = $status_id $extra_conditions ORDER BY id ";
  651. $result = Database::query($sql);
  652. return Database::store_result($result, 'ASSOC');
  653. }
  654. static function get_transaction_by_transaction_id($transaction_id, $branch_id) {
  655. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  656. $transaction_id = intval($transaction_id);
  657. $branch_id = intval($branch_id);
  658. if (!empty($transaction_id) && !empty($branch_id)) {
  659. $sql = "SELECT * FROM $table WHERE transaction_id = $transaction_id AND branch_id = $branch_id";
  660. $result = Database::query($sql);
  661. if (Database::num_rows($result)) {
  662. return Database::fetch_array($result, 'ASSOC');
  663. }
  664. }
  665. return false;
  666. }
  667. static function delete_transaction_by_transaction_id($transaction_id, $branch_id) {
  668. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  669. $transaction_id = intval($transaction_id);
  670. $branch_id = intval($branch_id);
  671. if (!empty($transaction_id) && !empty($branch_id)) {
  672. $sql = "DELETE FROM $table WHERE transaction_id = $transaction_id AND branch_id = $branch_id";
  673. Database::query($sql);
  674. }
  675. }
  676. /**
  677. * Gets the latest completed transaction for a specific branch (allows the building of a request to the branch to get new transactions)
  678. * @param int The ID of the branch
  679. * @return int The ID of the latest transaction
  680. */
  681. static function get_latest_completed_transaction_by_branch($branch_id) {
  682. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  683. $branch_id = intval($branch_id);
  684. $sql = "SELECT id FROM $table WHERE status_id = 2 AND branch_id = $branch_id ORDER BY id DESC LIMIT 1";
  685. $result = Database::query($sql);
  686. if (Database::num_rows($result)) {
  687. $row = Database::fetch_array($result);
  688. return $row['id'];
  689. }
  690. return 0;
  691. }
  692. /**
  693. * Gets the latest locally-recorded transaction for a specific branch
  694. * @param int The ID of the branch
  695. * @return int The ID of the last transaction registered
  696. */
  697. static function get_latest_transaction_id_by_branch($branch_id) {
  698. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  699. $branch_id = intval($branch_id);
  700. $sql = "SELECT transaction_id FROM $table
  701. WHERE branch_id = $branch_id
  702. ORDER BY transaction_id DESC
  703. LIMIT 1";
  704. $result = Database::query($sql);
  705. if (Database::num_rows($result)) {
  706. $row = Database::fetch_array($result);
  707. return $row['transaction_id'];
  708. }
  709. return 376012;
  710. }
  711. /**
  712. * Gets a specific transaction using select parameters
  713. * @param array Select parameters (associative array)
  714. * @param string Type of result set expected
  715. * @return array Results as requested
  716. */
  717. static function get_transaction_by_params($params, $type_result = 'all') {
  718. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  719. return Database::select('*', $table, $params, $type_result);
  720. }
  721. /**
  722. * Updates a transaction using the given query parameters
  723. * @param array Query parameters
  724. * @return bool The result of the transaction row update
  725. */
  726. static function update_transaction($params) {
  727. //return false;
  728. $table = Database::get_main_table(TABLE_BRANCH_TRANSACTION);
  729. if (empty($params['id'])) {
  730. error_log('No transaction id provided during update_transaction');
  731. return false;
  732. }
  733. $params['time_update'] = api_get_utc_datetime();
  734. error_log("Transaction updated #{$params['id']} with status_id = {$params['status_id']}");
  735. //Failed - do something else
  736. if ($params['status_id'] == MigrationCustom::TRANSACTION_STATUS_FAILED) {
  737. //event_system($event_type, $event_value_type, $event_value, $datetime = null, $user_id = null, $course_code = null) {
  738. event_system('transaction_error', 'transaction_id', $params['id'], $params['time_update']);
  739. }
  740. return Database::update($table, $params, array('id = ?' => $params['id']));
  741. }
  742. /**
  743. * Search for new transactions through a web service call. Automatically insert them in the local transactions table.
  744. * @param array The web service parameters
  745. * @param int the branch id optional
  746. * @param int An optional transaction ID to start from. Branch id must be selected if you use this option.
  747. * If none provided, fetches the latest transaction available and add + 1
  748. * @return The operation results
  749. */
  750. function get_transactions_from_webservice($params = array()) {
  751. error_log("get_transactions_from_webservice() function called");
  752. $branch_id = isset($params['branch_id']) ? $params['branch_id'] : null;
  753. $transaction_id = isset($params['transaction_id']) ? $params['transaction_id'] : null;
  754. $number_of_transactions = isset($params['number_of_transactions']) ? $params['number_of_transactions'] : 2;
  755. $transactions_found = 0;
  756. //Testing transactions
  757. $web_service_params = $this->web_service_connection_info;
  758. /*
  759. $result = self::soap_call($web_service_params,'usuarioDetalles', array('uididpersona' => 'D236776B-D7A5-47FF-8328-55EBE9A59015'));
  760. $result = self::soap_call($web_service_params,'programaDetalles', array('uididprograma' => 'C3671999-095E-4018-9826-678BAFF595DF'));
  761. $result = self::soap_call($web_service_params,'cursoDetalles', array('uididcurso' => 'E2334974-9D55-4BB4-8B57-FCEFBE2510DC'));
  762. $result = self::soap_call($web_service_params,'faseDetalles', array('uididfase' => 'EBF63F1C-FBD7-46A5-B039-80B5AF064929'));
  763. $result = self::soap_call($web_service_params,'frecuenciaDetalles', array('uididfrecuencia' => '0091CD3B-F042-11D7-B338-0050DAB14015'));
  764. $result = self::soap_call($web_service_params,'intensidadDetalles', array('uididintensidad' => '0091CD3C-F042-11D7-B338-0050DAB14015'));
  765. $result = self::soap_call($web_service_params,'mesesDetalles', array('uididfase' => 'EBF63F1C-FBD7-46A5-B039-80B5AF064929'));
  766. $result = self::soap_call($web_service_params,'sedeDetalles', array('uididsede' => '7379A7D3-6DC5-42CA-9ED4-97367519F1D9'));
  767. $result = self::soap_call($web_service_params,'horarioDetalles', array('uididhorario' => 'E395895A-B480-456F-87F2-36B3A1EBB81C'));
  768. $result = self::soap_call($web_service_params,'transacciones', array('ultimo' => 354911, 'cantidad' => 2));
  769. $result = self::soap_call($web_service_params, 'notaDetalles', array('uididpersona' => 'FC30EE0F-5C6F-4934-884B-BE7B68F96164', 'uididprograma' => 'bc0bdf04-cc08-4817-97c7-72840ca1171c', 'intIdSede' => 3));
  770. */
  771. if (empty($branch_id)) {
  772. $branches = self::get_branches();
  773. } else {
  774. $branches = array('branch_id' => $branch_id);
  775. }
  776. error_log(count($branches)." branche(s) found");
  777. if (!empty($branches)) {
  778. foreach ($branches as $branch) {
  779. if (!empty($branch_id) && !empty($transaction_id)) {
  780. $last_transaction_id = $transaction_id;
  781. } else {
  782. $last_transaction_id = self::get_latest_transaction_id_by_branch($branch['branch_id']);
  783. }
  784. //Calling a process to save transactions
  785. $params = array(
  786. 'ultimo' => $last_transaction_id,
  787. 'cantidad' => isset($number_of_transactions) && !empty($number_of_transactions) ? $number_of_transactions : 2,
  788. 'intIdSede' => $branch['branch_id'],
  789. );
  790. error_log("Branch #".$branch['branch_id']." - treating $number_of_transactions transaction(s) starting with transaction #$last_transaction_id");
  791. $transactions_found += MigrationCustom::process_transactions($params, $web_service_params);
  792. }
  793. }
  794. return $transactions_found;
  795. }
  796. /**
  797. * Loads a specific set of transactions from the transactions table and executes them
  798. * @param array Transactions filter
  799. * @param int Optional limit of transactions to execute
  800. * @return void
  801. */
  802. function execute_transactions($params = array()) {
  803. error_log("load_transactions() function called \n");
  804. $branch_id = isset($params['branch_id']) ? $params['branch_id'] : null;
  805. //$transaction_id = isset($params['transaction_id']) ? $params['transaction_id'] : null;
  806. //$number_of_transactions = isset($params['number_of_transactions']) ? $params['number_of_transactions'] : 2;
  807. $transactions_count = 0;
  808. //Getting transactions of the migration_transaction table
  809. if (empty($branch_id)) {
  810. $branches = self::get_branches();
  811. } else {
  812. $branches = array('branch_id' => $branch_id);
  813. }
  814. if (!empty($branches)) {
  815. error_log(count($branches)." branch(es) found \n");
  816. foreach ($branches as $branch_info) {
  817. //Get uncompleted transactions
  818. $transactions = array();
  819. $transactions = self::get_transactions(0, $branch_info['branch_id']);
  820. //Getting latest executed transaction
  821. $options = array('where' => array('branch_id = ? and status_id <> ?' => array($branch_info['branch_id'], 0)), 'order' => 'id desc', 'limit' => '1');
  822. $transaction_info = self::get_transaction_by_params($options, 'first');
  823. $latest_id_attempt = 1;
  824. if ($transaction_info) {
  825. $latest_id = $transaction_info['id'];
  826. $latest_id_attempt = $latest_id + 1;
  827. }
  828. $count = count($transactions);
  829. $transactions_count += $count;
  830. $item = 1;//counter
  831. if (!empty($transactions)) {
  832. error_log("Branch #".$branch_info['branch_id']." called, $count transaction(s) found starting with transaction #$latest_id_attempt \n");
  833. //Looping transactions
  834. if (!empty($transactions)) {
  835. foreach ($transactions as $transaction) {
  836. //Calculating percentage
  837. $percentage = $item / $count * 100;
  838. if (round($percentage) % 10 == 0) {
  839. $percentage = round($percentage, 3);
  840. error_log("Processing transaction #{$transaction['id']} $percentage%");
  841. }
  842. $item++;
  843. error_log("Progressing towards last transaction: #$latest_id_attempt ...");
  844. //Checking "huecos"
  845. //Waiting transaction is fine continue:
  846. if ($transaction['id'] == $latest_id_attempt) {
  847. $latest_id_attempt++;
  848. } else {
  849. error_log("Transaction #$latest_id_attempt is missing in branch #{$branch_info['branch_id']} \n");
  850. }
  851. $result = $this->execute_transaction($transaction);
  852. error_log($result['message']);
  853. }
  854. }
  855. } else {
  856. error_log("Branch #".$branch_info['branch_id']." - No transactions to load");
  857. }
  858. }
  859. } else {
  860. error_log('No branches found');
  861. }
  862. $actions = array(); //load actions from Mysql
  863. foreach ($actions as $action_data) {
  864. if (in_array($action_data['action'], $transactions)) {
  865. $function_to_call = $transactions[$action_data['action']];
  866. $function_to_call($action_data['params']);
  867. }
  868. }
  869. return $transactions_count;
  870. }
  871. function execute_transaction($transaction_info) {
  872. //Loading function. The action is now numeric, so we call a transaction_1() function, for example
  873. $validate = MigrationCustom::validate_transaction($transaction_info);
  874. if (isset($validate['error']) && $validate['error']) {
  875. if ($transaction_info['failed_attempts'] >= 3) {
  876. self::update_transaction(array('id' => $transaction_info['id'] , 'failed_attempts' => $transaction_info['failed_attempts']+1, 'status_id' => 5));
  877. } else {
  878. self::update_transaction(array('id' => $transaction_info['id'] , 'failed_attempts' => $transaction_info['failed_attempts']+1));
  879. }
  880. return $validate;
  881. }
  882. error_log("-----------------------------------");
  883. error_log("Executing transaction ".$transaction_info['id']);
  884. error_log("-----------------------------------");
  885. $function_to_call = "transaction_" . $transaction_info['action'];
  886. if (method_exists('MigrationCustom', $function_to_call)) {
  887. error_log("Calling function MigrationCustom::$function_to_call()");
  888. $result = MigrationCustom::$function_to_call($transaction_info, $this->web_service_connection_info);
  889. $result['message'] = "Function response: ".$result['message'];
  890. //error_log('Reponse: '.$result['message']);
  891. if (!empty($transaction_info['id'])) {
  892. if (isset($result['error']) && $result['error'] == true) {
  893. if ($transaction_info['failed_attempts'] >= 3) {
  894. // if this failed several times, mark as abandonned (change status to 5)
  895. self::update_transaction(array('id' => $transaction_info['id'] , 'status_id' => 5, 'failed_attempts' => $transaction_info['failed_attempts']));
  896. } else {
  897. // if this failed but not too many times yet, just increment failed_attempts
  898. self::update_transaction(array('id' => $transaction_info['id'] , 'status_id' => $result['status_id'], 'failed_attempts' => $transaction_info['failed_attempts'] + 1));
  899. }
  900. } else {
  901. // did not fail. Update status (to 2, most likely)
  902. self::update_transaction(array('id' => $transaction_info['id'] , 'status_id' => $result['status_id']));
  903. }
  904. } else {
  905. error_log("Can't update transaction, id was not provided");
  906. }
  907. return $result;
  908. } else {
  909. // method does not exist
  910. $error_message = "Function $function_to_call does not exists";
  911. error_log($error_message);
  912. //Failed
  913. if (!empty($transaction_info['id'])) {
  914. self::update_transaction(array('id' => $transaction_info['id'] , 'status_id' => MigrationCustom::TRANSACTION_STATUS_FAILED));
  915. }
  916. return array('message' => $error_message);
  917. }
  918. }
  919. /**
  920. *
  921. * @param int Transaction id of the third party
  922. *
  923. */
  924. function load_transaction_by_third_party_id($transaction_external_id, $branch_id, $forced = false) {
  925. //Asking for 2 transactions by getting 1
  926. $params = array(
  927. 'ultimo' => $transaction_external_id,
  928. 'cantidad' => 1,
  929. 'intIdSede' => $branch_id
  930. );
  931. $result = self::soap_call($this->web_service_connection_info, 'transacciones', $params);
  932. //Hacking webservice default result
  933. if ($result && isset($result[0])) {
  934. //Getting 1 transaction
  935. $result = $result[0];
  936. $transaction_external_id++;
  937. if ($result['idt'] == $transaction_external_id) {
  938. $message = Display::return_message('Transaction id found in third party', 'info');
  939. //Adding third party transaction to Chamilo
  940. $transaction_result = MigrationCustom::process_transaction($result, null, $forced);
  941. $transaction_chamilo_info = array();
  942. if ($transaction_result['error'] == false) {
  943. $chamilo_transaction_id = $transaction_result['id'];
  944. $message .= Display::return_message($transaction_result['message'], 'info');
  945. $transaction_chamilo_info = self::get_transaction_by_params(array('Where' => array('id = ?' => $chamilo_transaction_id), 'first'));
  946. if (isset($transaction_chamilo_info) && isset($transaction_chamilo_info[$chamilo_transaction_id])) {
  947. $transaction_chamilo_info = $transaction_chamilo_info[$chamilo_transaction_id];
  948. } else {
  949. $transaction_chamilo_info = null;
  950. }
  951. } else {
  952. $message .= Display::return_message("Transaction NOT added to Chamilo. {$transaction_result['message']}", 'warning');
  953. }
  954. if (!empty($transaction_chamilo_info)) {
  955. $transaction_result = $this->execute_transaction($transaction_chamilo_info);
  956. if ($transaction_result) {
  957. $message .= Display::page_subheader("Transaction result:");
  958. $message .= nl2br($transaction_result['message']);
  959. $message .= "<br />";
  960. if (isset($transaction_result['entity']) && !empty($transaction_result['entity'])) {
  961. $message .= Display::page_subheader2("Entity {$transaction_result['entity']} before:");
  962. $message .= "<pre>".print_r($transaction_result['before'], 1)."</pre>";
  963. $message .= "<br />";
  964. $message .= Display::page_subheader2("Entity {$transaction_result['entity']} after:");
  965. $message .= "<pre>".print_r($transaction_result['after'], 1)."</pre>";
  966. $message .= "<br />";
  967. }
  968. } else {
  969. $message .= Display::return_message("Transaction failed", 'error');
  970. }
  971. }
  972. return array(
  973. 'message' => $message,
  974. 'raw_reponse' =>
  975. //Display::page_subheader2("Transactions:").
  976. Display::page_subheader3("Chamilo transaction info:")."<pre>".print_r($transaction_chamilo_info, true)."</pre>".
  977. Display::page_subheader3("Webservice transaction reponse:")."<pre>".print_r($result, true)."</pre>",
  978. );
  979. }
  980. }
  981. return array(
  982. 'message' => Display::return_message("Transaction NOT found in third party", 'warning'),
  983. //'raw_reponse' => print_r($result, true)
  984. );
  985. }
  986. /**
  987. * Prepares the relationship between two fields (one from the original database and on from the destination/local database)
  988. * @param array List of fields that must be matched ('fields_match' => array(0=>array('orig'=>'...','dest'=>'...',...)))
  989. * @return mixed Modified field
  990. */
  991. function prepare_field_match($table) {
  992. $sql_select_fields = array();
  993. if (!empty($table['fields_match'])) {
  994. foreach ($table['fields_match'] as $details) {
  995. if (empty($details['orig'])) {
  996. //Ignore if the field declared in $matches doesn't exist in
  997. // the original database
  998. continue;
  999. }
  1000. $sql_select_fields[$details['orig']] = $details['orig'];
  1001. // If there is something to alter in the SQL query, rewrite the entry
  1002. if (!empty($details['sql_alter'])) {
  1003. $func_alter = $details['sql_alter'];
  1004. $sql_select_fields[$details['orig']] = MigrationCustom::$func_alter($details['orig']);
  1005. }
  1006. //error_log('Found field ' . $details['orig'] . ' to be selected as ' . $sql_select_fields[$details['orig']]);
  1007. }
  1008. }
  1009. return $sql_select_fields;
  1010. }
  1011. /**
  1012. * Executes a fields match
  1013. * @param array List of fields that must be matched ('fields_match' => array(0=>array('orig'=>'...','dest'=>'...',...)))
  1014. * @param array Row of data
  1015. * @param array Extra fields table definition
  1016. */
  1017. function execute_field_match($table, $row, $extra_fields = array()) {
  1018. //error_log('execute_field_match');
  1019. $dest_row = array();
  1020. $first_field = '';
  1021. // If a dest table has been defined, fill $my_extra_fields with the
  1022. // extra_fields defined for that table
  1023. $my_extra_fields = isset($table['dest_table']) && isset($extra_fields[$table['dest_table']]) ? $extra_fields[$table['dest_table']] : null;
  1024. $extra_field_obj = null;
  1025. $extra_field_value_obj = null;
  1026. if (!empty($table['dest_table'])) {
  1027. $extra_field_obj = new ExtraField($table['dest_table']);
  1028. $extra_field_value_obj = new ExtraFieldValue($table['dest_table']);
  1029. }
  1030. $extra_fields_to_insert = array();
  1031. global $data_list;
  1032. // Fill the data list, if possible
  1033. if (count($data_list['users'])<1) {
  1034. MigrationCustom::fill_data_list($data_list);
  1035. }
  1036. foreach ($table['fields_match'] as $id_field => $details) {
  1037. //if ($table['dest_table'] == 'session') {error_log('Processing field '.$details['orig']);}
  1038. $params = array();
  1039. // Remove the table name prefix if any (in the orig field)
  1040. if (isset($details['orig'])) {
  1041. $field_exploded = explode('.', $details['orig']);
  1042. if (isset($field_exploded[1])) {
  1043. $details['orig'] = $field_exploded[1];
  1044. }
  1045. }
  1046. // process the fields one by one
  1047. if ($details['func'] == 'none' || empty($details['func'])) {
  1048. // if no function is defined to alter the field, take it as is
  1049. $dest_data = $row[$details['orig']];
  1050. } else {
  1051. // if an alteration function is defined, run it on the field
  1052. //error_log(__FILE__.' '.__LINE__.' Preparing to treat field with '.$details['func']);
  1053. $dest_data = MigrationCustom::$details['func']($row[$details['orig']], $data_list, $row);
  1054. }
  1055. if (isset($dest_row[$details['dest']])) {
  1056. $dest_row[$details['dest']] .= ' ' . $dest_data;
  1057. } else {
  1058. $dest_row[$details['dest']] = $dest_data;
  1059. }
  1060. //Extra field values
  1061. $extra_field = isset($my_extra_fields) && isset($my_extra_fields[$details['dest']]) ? $my_extra_fields[$details['dest']] : null;
  1062. // Check the array is there
  1063. //if($table['dest_table'] == 'session') error_log('Extra field: '.print_r($extra_field,1));
  1064. if (!empty($extra_field) && $extra_field_obj) {
  1065. //if($table['dest_table'] == 'session') error_log('Extra_field no es vacío');
  1066. // Check the "options" array is defined for this field (checking is_array is crucial here, see BT#5215)
  1067. if (is_array($extra_field['options']) && count($extra_field['options'])>0) {
  1068. //if($table['dest_table'] == 'session') error_log('...y sus opciones son: '.print_r($extra_field['options'],1));
  1069. //if($details['orig']=='uidIdPrograma') { error_log('Eso era lo inicial, del cual se tomó '.$details['dest'].': '.print_r($my_extra_fields,1));}
  1070. $options = $extra_field['options'];
  1071. $field_type = $extra_field['field_type'];
  1072. //if ($table['dest_table'] == 'session') {error_log('Field orig: '.$details['orig']);}
  1073. if (!empty($options)) {
  1074. //if ($table['dest_table'] == 'session') {error_log('Options not empty');}
  1075. if (!is_array($options)) { $options = array($options); }
  1076. foreach ($options as $option) {
  1077. if (is_array($option)) {
  1078. foreach ($option as $key => $value) {
  1079. //error_log("$key $value --> {$dest_row[$details['dest']]} ");
  1080. if ($key == 'option_value' && $value == $dest_row[$details['dest']]) {
  1081. $value = $option['option_display_text'];
  1082. if ($field_type == Extrafield::FIELD_TYPE_SELECT) {
  1083. $value = $option['option_value'];
  1084. }
  1085. $params = array(
  1086. 'field_id' => $option['field_id'],
  1087. 'field_value' => $value,
  1088. );
  1089. break(2);
  1090. }
  1091. }
  1092. }
  1093. }
  1094. }
  1095. } else {
  1096. $params = array(
  1097. 'field_id' => $extra_field,
  1098. 'field_value' => $dest_row[$details['dest']],
  1099. );
  1100. }
  1101. if (!empty($params)) {
  1102. $extra_fields_to_insert[] = $params;
  1103. }
  1104. unset($dest_row[$details['dest']]);
  1105. }
  1106. unset($extra_field);
  1107. }
  1108. //if ($table['dest_table']=='session') { error_log('Params: '.print_r($params,1)); }
  1109. // If a dest_func entry has been defind, use this entry as the main
  1110. // operation to execute when inserting the item
  1111. if (!empty($table['dest_func'])) {
  1112. //error_log('Calling '.$table['dest_func'].' on data recovered: '.print_r($dest_row, 1));
  1113. $dest_row['return_item_if_already_exists'] = true;
  1114. $item_result = false;
  1115. // Using call_user_func_array() has a serious impact on performance
  1116. switch($table['dest_func']) {
  1117. case USER_FUNC_EXCEPTION_GRADEBOOK:
  1118. MigrationCustom::add_gradebook_result_with_evaluation($dest_row);
  1119. break;
  1120. case USER_FUNC_EXCEPTION_ATTENDANCE:
  1121. MigrationCustom::create_attendance($dest_row);
  1122. break;
  1123. default:
  1124. $item_result = call_user_func_array($table['dest_func'], array($dest_row, $data_list));
  1125. }
  1126. //After the function was executed fill the $data_list array
  1127. switch ($table['dest_table']) {
  1128. case 'course':
  1129. //Saving courses in array
  1130. if ($item_result) {
  1131. //$data_list['courses'][$dest_row['uidIdCurso']] = $item_result;
  1132. } else {
  1133. error_log('Course Not FOUND');
  1134. error_log(print_r($item_result, 1));
  1135. return false;
  1136. }
  1137. $handler_id = $item_result['code'];
  1138. break;
  1139. case 'user':
  1140. if (!empty($item_result)) {
  1141. $handler_id = $item_result['user_id'];
  1142. //error_log($dest_row['email'].' '.$dest_row['uidIdPersona']);
  1143. if (isset($dest_row['uidIdAlumno'])) {
  1144. //$data_list['users_alumno'][$dest_row['uidIdAlumno']]['extra'] = $item_result;
  1145. }
  1146. if (isset($dest_row['uidIdEmpleado'])) {
  1147. //print_r($dest_row['uidIdEmpleado']);exit;
  1148. //$data_list['users_empleado'][$dest_row['uidIdEmpleado']]['extra'] = $item_result;
  1149. }
  1150. } else {
  1151. global $api_failureList;
  1152. error_log('Empty user details');
  1153. error_log(print_r($api_failureList, 1));
  1154. }
  1155. break;
  1156. case 'session':
  1157. //$data_list['sessions'][$dest_row['uidIdPrograma']] = $item_result;
  1158. $handler_id = $item_result; //session_id
  1159. break;
  1160. }
  1161. //Saving extra fields of the element
  1162. //error_log('Checking extra fields for '.$extra_field_value_obj->handler_id.' '.$handler_id);
  1163. if (!empty($extra_fields_to_insert)) {
  1164. foreach ($extra_fields_to_insert as $params) {
  1165. //error_log('Trying to save '.print_r($params,1));
  1166. $params[$extra_field_value_obj->handler_id] = $handler_id;
  1167. $extra_field_value_obj->save($params);
  1168. }
  1169. }
  1170. } else {
  1171. // $this->errors_stack[] = "No destination data dest_func found. Abandoning data with first field $first_field = " . $dest_row[$first_field];
  1172. }
  1173. unset($extra_fields_to_insert); //remove to free up memory
  1174. return $dest_row;
  1175. }
  1176. /**
  1177. * Helper function to create extra fields in the Chamilo database. If the
  1178. * extra field aleady exists, then just return the ID of this field. If
  1179. * options are provided ('options' sub-array), then options are inserted in
  1180. * the corresponding x_field_options table.
  1181. * @param Array An array containing an 'extra_fields' entry with details about the required extra fields
  1182. * @return void
  1183. */
  1184. private function _create_extra_fields(&$table) {
  1185. $extra_fields = array();
  1186. error_log('Inserting (if not exist) extra fields for : ' . $table['dest_table'] . " \n");
  1187. foreach ($table['extra_fields'] as $extra_field) {
  1188. //error_log('Preparing for insertion of extra field ' . $extra_field['field_display_text'] . "\n");
  1189. $options = isset($extra_field['options']) ? $extra_field['options'] : null;
  1190. unset($extra_field['options']);
  1191. $extra_field_obj = new ExtraField($table['dest_table']);
  1192. $extra_field_id = $extra_field_obj->save($extra_field);
  1193. $selected_fields = self::prepare_field_match($options);
  1194. //Adding options. This is only processed if the corresponding
  1195. // extra_field has an 'options' sub-aray defined
  1196. if (!empty($options)) {
  1197. $extra_field_option_obj = new ExtraFieldOption($table['dest_table']);
  1198. // use the query defined in the 'query' item as returned in a select by prepare_field_match above
  1199. $this->select_all($options['orig_table'], $selected_fields);
  1200. $num_rows = $this->num_rows();
  1201. if ($num_rows) {
  1202. $data_to_insert = array();
  1203. $data_to_insert['field_id'] = $extra_field_id;
  1204. while ($row = $this->fetch_array()) {
  1205. $data = self::execute_field_match($options, $row);
  1206. $data_to_insert = array_merge($data_to_insert, $data);
  1207. $extra_field_option_obj->save_one_item($data_to_insert, false, false);
  1208. //error_log(print_r($extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']], 1));
  1209. $extra_fields[$table['dest_table']]['extra_field_' . $extra_field['field_variable']]['options'][] = $data_to_insert;
  1210. $extra_fields[$table['dest_table']]['extra_field_' . $extra_field['field_variable']]['field_type'] = $extra_field['field_type'];
  1211. }
  1212. //$extra_fields[$table['dest_table']]['extra_field_'.$extra_field['field_variable']]['selected_option'] =
  1213. //error_log('$data: ' . print_r($data_to_insert, 1));
  1214. }
  1215. } else {
  1216. // if there are no pre-defined options, then just return the field_id for this variable
  1217. $extra_fields[$table['dest_table']]['extra_field_' . $extra_field['field_variable']] = $extra_field_id;
  1218. }
  1219. }
  1220. return $extra_fields;
  1221. }
  1222. }