tripal_chado.migrate.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. <?php
  2. /**
  3. * Implements hook_form()
  4. *
  5. * Provide a form to select Tripal v2 content types for migration
  6. *
  7. * @param $form
  8. * @param $form_state
  9. */
  10. function tripal_chado_migrate_form($form, &$form_state) {
  11. $form['overview_vert_tabs'] = array(
  12. '#type' => 'vertical_tabs'
  13. );
  14. $form['modes']['#group'] = 'overview_vert_tabs';
  15. $form['modes']['#weight'] = 1000;
  16. // Step 1
  17. $form['step1'] = array(
  18. '#type' => 'fieldset',
  19. '#title' => 'Step1',
  20. '#description' => '<b>Enable Legacy Support</b>',
  21. '#collapsible' => TRUE,
  22. '#collapsed' => TRUE,
  23. '#group' => 'overview_vert_tabs'
  24. );
  25. global $base_url;
  26. $mod_url = $base_url . '/admin/modules';
  27. $form['step1']['step1_content'] = array(
  28. '#markup' => 'Tripal legacy modules are needed to support the display of Tripal v2
  29. content types. Review and <a href="'. $mod_url .'">enable modules</a>
  30. in the \'Tripal v2 Legacy\' category for legacy content support'
  31. );
  32. // Step 2
  33. $form['step2'] = array(
  34. '#type' => 'fieldset',
  35. '#title' => 'Step2',
  36. '#description' => '<b>Migrate Content</b>',
  37. '#collapsible' => TRUE,
  38. '#collapsed' => TRUE,
  39. '#group' => 'overview_vert_tabs'
  40. );
  41. $form['step2']['step2_container'] = array(
  42. '#type' => 'container',
  43. '#collapsible' => FALSE,
  44. '#prefix' => '<div id="tripal-chado-migrate-form-step2">',
  45. '#suffix' => '</div>'
  46. );
  47. $tv2_content_type = 'all';
  48. if (array_key_exists('values', $form_state)) {
  49. $tv2_content_type = $form_state['values']['tv2_content_type'];
  50. }
  51. $tv2_options = tripal_chado_get_tripal_v2_content_type_options(TRUE);
  52. $form['step2']['step2_container']['tv2_content_type'] = array(
  53. '#type' => 'select',
  54. '#title' => 'Tripal v2 Content Type',
  55. '#description' => t('Select the Tripal v2 content type to migrate.'),
  56. '#options' => $tv2_options,
  57. '#default_value' => $tv2_content_type,
  58. '#ajax' => array(
  59. 'callback' => "tripal_chado_migrate_form_step2_ajax_callback",
  60. 'wrapper' => "tripal-chado-migrate-form-step2",
  61. 'effect' => 'fade',
  62. 'method' => 'replace'
  63. ),
  64. );
  65. // Add a review button that allows reviewing migratable content types
  66. if ($tv2_content_type != 'all') {
  67. $table = str_replace('chado_', '', $tv2_content_type);
  68. $schema = chado_get_schema($table);
  69. $pkey = $schema['primary key'][0];
  70. $fkeys = $schema['foreign keys'];
  71. $form['step2']['step2_container']['tv3_content_type'] = array(
  72. '#type' => 'fieldset',
  73. '#title' => 'Tripal v3 Content Type',
  74. '#description' => "Click the 'Get Tripal v3 Types' button to retrieve a list of Tripal v3
  75. content types to which this Tripal v2 type can be converted. This may take a while
  76. depending on the size of your database. The number of items to be converted is
  77. shown beside the type."
  78. );
  79. $form['step2']['step2_container']['tv3_content_type']['get_v3_type_btn'] = array(
  80. '#type' => 'button',
  81. '#name' => 'get_v3_type_btn',
  82. '#value' => "Get Tripal v3 Types",
  83. '#ajax' => array(
  84. 'callback' => "tripal_chado_migrate_form_step2_ajax_callback",
  85. 'wrapper' => "tripal-chado-migrate-form-step2",
  86. 'effect' => 'fade',
  87. 'method' => 'replace'
  88. ),
  89. );
  90. $no_data = TRUE;
  91. if ($form_state['clicked_button']['#name'] == 'get_v3_type_btn') {
  92. // Migrate all
  93. $form['step2']['step2_container']['tv3_content_type']['tv3_migrate_all'] = array(
  94. '#type' => 'checkbox',
  95. '#title' => 'Migrate All'
  96. );
  97. // Migrate selection only
  98. if (key_exists('cvterm', $fkeys) && key_exists('type_id', $fkeys['cvterm']['columns'])) {
  99. // Get all Tripal v2 node types from the chad_* linking table
  100. $sql =
  101. "SELECT V.name AS type, X.accession, db.name AS namespace , count(*) AS num
  102. FROM {" . $table . "} T
  103. INNER JOIN public.$tv2_content_type CT ON T.$pkey = CT.$pkey
  104. INNER JOIN {cvterm} V ON V.cvterm_id = T.type_id
  105. INNER JOIN {dbxref} X ON X.dbxref_id = V.dbxref_id
  106. INNER JOIN {db} ON db.db_id = X.db_id
  107. LEFT JOIN public.chado_entity CE ON CE.record_id = T.$pkey
  108. AND CE.data_table = '$table'
  109. WHERE CE.record_id IS NULL
  110. GROUP BY V.name, X.accession, db.name";
  111. $tv3_content_types = chado_query($sql);
  112. while($tv3_content_type = $tv3_content_types->fetchObject()) {
  113. // We need to store namespace/accession/type for each checkbox in the key becuase
  114. // the value only allows 1 or 0
  115. $key = urlencode(
  116. 'tv3_content_type--' .
  117. $tv3_content_type->namespace . '--' .
  118. $tv3_content_type->accession . '--' .
  119. $tv3_content_type->type);
  120. $form['step2']['step2_container']['tv3_content_type'][$key] = array(
  121. '#type' => 'checkbox',
  122. '#title' => $tv3_content_type->type . ' (' . $tv3_content_type->num . ')',
  123. );
  124. $no_data = FALSE;
  125. }
  126. }
  127. else if ($table == 'organism') {
  128. $sql =
  129. "SELECT count(*)
  130. FROM {organism} O
  131. INNER JOIN public.chado_organism CO ON O.organism_id = CO.organism_id
  132. LEFT JOIN public.chado_entity CE ON CE.record_id = O.organism_id
  133. AND CE.data_table = 'organism'
  134. WHERE CE.record_id IS NULL";
  135. $org_count = chado_query($sql)->fetchField();
  136. if ($org_count > 0) {
  137. $key = urldecode('tv3_content_type--local--organism--organism');
  138. $form['step2']['step2_container']['tv3_content_type'][$key] = array(
  139. '#type' => 'checkbox',
  140. '#title' => 'Organism (' . $org_count . ')',
  141. );
  142. $no_data = FALSE;
  143. }
  144. }
  145. else if ($table == 'analysis') {
  146. $sql =
  147. "SELECT count(*)
  148. FROM {analysis} A
  149. INNER JOIN public.chado_analysis CA ON A.analysis_id = CA.analysis_id
  150. LEFT JOIN public.chado_entity CE ON CE.record_id = A.analysis_id
  151. AND CE.data_table = 'analysis'
  152. WHERE CE.record_id IS NULL";
  153. $ana_count = chado_query($sql)->fetchField();
  154. if ($ana_count > 0) {
  155. $key = urlencode('tv3_content_type--local--analysis--analysis');
  156. $form['step2']['step2_container']['tv3_content_type'][$key] = array(
  157. '#type' => 'checkbox',
  158. '#title' => 'Analysis (' . $ana_count . ')',
  159. );
  160. $no_data = FALSE;
  161. }
  162. }
  163. if ($no_data) {
  164. unset($form['step2']['step2_container']['tv3_content_type']['tv3_migrate_all']);
  165. drupal_set_message('No data for migration or all have been migrated.', 'warning');
  166. }
  167. }
  168. }
  169. // Migrate button
  170. if ($tv2_content_type == 'all' || key_exists('tv3_migrate_all', $form['step2']['step2_container']['tv3_content_type'])) {
  171. $form['step2']['step2_container']['migrate_btn'] = array(
  172. '#type' => 'submit',
  173. '#name' => 'migrate_btn',
  174. '#value' => "Migrate $tv2_options[$tv2_content_type]",
  175. );
  176. }
  177. // Step 3
  178. $form['step3'] = array(
  179. '#type' => 'fieldset',
  180. '#title' => 'Step3',
  181. '#description' => '<b>Use Legacy Templates (optional)</b>',
  182. '#collapsible' => TRUE,
  183. '#collapsed' => TRUE,
  184. '#group' => 'overview_vert_tabs'
  185. );
  186. // Get a list of enabled legacy modules with tv2 templates
  187. $mod_enabled = tripal_chado_migrate_get_enabled_legacy_modules(TRUE);
  188. $enabled_templates = variable_get('tripal_chado_enabled_legacy_templates', array());
  189. foreach ($mod_enabled AS $mod_name => $mod_path) {
  190. $form ['step3']['legacy_template--' . $mod_name] = array (
  191. '#type' => 'checkbox',
  192. '#title' => ucwords(str_replace(array('tripal', '_'), array('chado', ' '), $mod_name)),
  193. '#default_value' => key_exists('legacy_template--' . $mod_name, $enabled_templates) ? $enabled_templates['legacy_template--' . $mod_name] : 0,
  194. );
  195. }
  196. $form['step3']['save_btn'] = array(
  197. '#type' => 'button',
  198. '#name' => 'save_enabled_template_btn',
  199. '#value' => "Save",
  200. );
  201. // Step 4
  202. $form['step4'] = array(
  203. '#type' => 'fieldset',
  204. '#title' => 'Step4',
  205. '#description' => '<b>Complete Migration</b>',
  206. '#collapsible' => TRUE,
  207. '#collapsed' => TRUE,
  208. '#group' => 'overview_vert_tabs'
  209. );
  210. $opt_complete_migration = array (
  211. 'delete' => 'Delete Tripal v2 Content',
  212. 'unpublish' => 'Unpublish Tripal v2 Content',
  213. 'cp_title' => 'Copy Title over to Tripal v3 Content',
  214. 'mv_url' => 'Migrate URL Alias to Tripal v3 Content'
  215. );
  216. foreach ($tv2_options AS $opt_key => $opt) {
  217. $form['step4'][$opt_key . '_title'] = array(
  218. '#markup' => "<b>$opt</b>"
  219. );
  220. $form['step4']['complete_migration--' . $opt_key] = array(
  221. '#type' => 'checkboxes',
  222. '#options' => $opt_complete_migration,
  223. );
  224. }
  225. $form['step4']['submit_btn'] = array(
  226. '#type' => 'button',
  227. '#name' => 'complete_migration_btn',
  228. '#value' => "Submit",
  229. );
  230. return $form;
  231. }
  232. /**
  233. * Implements hook_validate()
  234. *
  235. * @param $form
  236. * @param $form_state
  237. */
  238. function tripal_chado_migrate_form_validate($form, &$form_state) {
  239. // Store the legacy template setting in a Drupal variable
  240. if ($form_state['clicked_button']['#name'] == 'save_enabled_template_btn') {
  241. $values = $form_state['values'];
  242. $enabled_templates = array();
  243. foreach ($values AS $key => $value) {
  244. if (preg_match('/^legacy_template--/', $key)) {
  245. $enabled_templates[$key] = $value;
  246. }
  247. }
  248. variable_set('tripal_chado_enabled_legacy_templates', $enabled_templates);
  249. drupal_theme_rebuild();
  250. }
  251. // Complete migration
  252. else if ($form_state['clicked_button']['#name'] == 'complete_migration_btn') {
  253. $values = $form_state['values'];
  254. $delete = array();
  255. $unpublish = array();
  256. $cp_title = array();
  257. $mv_url = array();
  258. foreach ($values AS $key => $value) {
  259. if (preg_match('/^complete_migration--/', $key)) {
  260. }
  261. }
  262. }
  263. }
  264. /**
  265. * Implements hook_submit()
  266. *
  267. * By submiting the form, a Tripal job to migrate Tripal v2 content is submitted
  268. *
  269. * @param $form
  270. * @param $form_state
  271. */
  272. function tripal_chado_migrate_form_submit($form, &$form_state) {
  273. if ($form_state['clicked_button']['#name'] == 'migrate_btn') {
  274. global $user;
  275. $values = $form_state['values'];
  276. $tv2_content_type = $form_state['values']['tv2_content_type'];
  277. $tv3_content_type = array();
  278. foreach ($values AS $key => $value) {
  279. if ($tv2_content_type != 'all') {
  280. $key = urldecode($key);
  281. if (preg_match('/^tv3_content_type--(.+)--(.+)--(.+)/', $key, $matches) &&
  282. ($value == 1 || $values['tv3_migrate_all'] == 1)) {
  283. $namespace = $matches[1];
  284. $accession = $matches[2];
  285. $type = $matches[3];
  286. $tv3_content_type [] = array(
  287. 'namespace' => $namespace,
  288. 'accession' => $accession,
  289. 'term_name' => $type
  290. );
  291. }
  292. }
  293. }
  294. // Submit a job to migrate content
  295. global $user;
  296. $args = array(
  297. array(
  298. 'tv2_content_type' => $tv2_content_type,
  299. 'tv3_content_type' => $tv3_content_type
  300. )
  301. );
  302. $includes = array(
  303. module_load_include('inc', 'tripal_chado', 'includes/tripal_chado.migrate'),
  304. );
  305. if ($tv2_content_type == 'all' || count($tv3_content_type) != 0) {
  306. return tripal_add_job("Migrate $tv2_content_type Tripal v2 content.",
  307. 'tripal_chado', 'tripal_chado_migrate_records', $args, $user->uid, 10, $includes);
  308. }
  309. else {
  310. return drupal_set_message('Nothing to do. All data have been migrated or no data for migration.');
  311. }
  312. }
  313. }
  314. /**
  315. * Ajax call back that returns the entire form
  316. *
  317. * The callback is triggered by ajax elements on the form which leads to the update of
  318. * entire form according to the values set on the form
  319. *
  320. * @param $form
  321. * @param $form_state
  322. * @return $form
  323. */
  324. function tripal_chado_migrate_form_step2_ajax_callback(&$form, &$form_state) {
  325. return $form['step2']['step2_container'];
  326. }
  327. /**
  328. * Get available Tripal v2 content types
  329. *
  330. * @param boolean $all_option
  331. * Include an 'all' option in the returned array
  332. * @return string[]
  333. * Return a string array keyed by the node type
  334. */
  335. function tripal_chado_get_tripal_v2_content_type_options($all_option = FALSE) {
  336. // Get all available Tripal v2 chado tables
  337. $sql =
  338. "SELECT table_name
  339. FROM information_schema.tables
  340. WHERE table_schema = 'public' AND table_name LIKE 'chado_%'";
  341. $result = db_query($sql);
  342. $tables = array();
  343. while ($field = $result->fetchField()) {
  344. $count = db_query("SELECT count(*) FROM $field")->fetchField();
  345. if ($count != 0) {
  346. array_push($tables, $field);
  347. }
  348. }
  349. // List all available Tripal v2 content types
  350. $result = db_select('node_type', 'nt')
  351. ->fields('nt', array('type', 'name', 'description'))
  352. ->condition('type', 'chado_%', 'LIKE')
  353. ->execute();
  354. $options = array();
  355. if ($all_option) {
  356. $options['all'] = 'All';
  357. }
  358. while ($obj = $result->fetchObject()) {
  359. if (in_array($obj->type, $tables)) {
  360. $options[$obj->type] = $obj->name;
  361. }
  362. }
  363. return $options;
  364. }
  365. /**
  366. * Tripal job callback to migrate Tripal v2 content into Tripal v3 content
  367. *
  368. * @param $migration
  369. * @param $job_id
  370. */
  371. function tripal_chado_migrate_records($migration, $job_id = NULL) {
  372. $tv2_content_type = $migration['tv2_content_type'];
  373. $tv3_content_type = $migration['tv3_content_type'];
  374. // If tv2_content_type is 'all', migrate all existing Tripal v2 content
  375. if ($tv2_content_type == 'all') {
  376. print "Migrating all Tripal v2 content...\n";
  377. tripal_chado_migrate_all_types();
  378. }
  379. // Otherwise, migrate only selected Tripal v2 content
  380. else {
  381. print "Migrating selected Tripal v2 content...\n";
  382. tripal_chado_migrate_selected_types($tv3_content_type);
  383. }
  384. }
  385. /**
  386. * Migrate all Tripal v2 content types
  387. *
  388. * Gather all available Tripal v2 content types and store the result in an associated array with
  389. * values of namespace, accession, term_name. The array is then pass to the function
  390. * tripal_chado_migrate_selected_types() that handles the migration
  391. */
  392. function tripal_chado_migrate_all_types() {
  393. // Get all available Tripal v2 content types
  394. $tv2_content_types = tripal_chado_get_tripal_v2_content_type_options();
  395. $types = array();
  396. foreach($tv2_content_types AS $tv2_content_type => $value) {
  397. $table = str_replace('chado_', '', $tv2_content_type);
  398. $schema = chado_get_schema($table);
  399. $pkey = $schema['primary key'][0];
  400. $fkeys = $schema['foreign keys'];
  401. if (key_exists('cvterm', $fkeys) && key_exists('type_id', $fkeys['cvterm']['columns'])) {
  402. // Get all Tripal v2 node types from the chad_* linking table
  403. $sql = "
  404. SELECT V.name AS type, X.accession, db.name AS namespace
  405. FROM {" . $table . "} T
  406. INNER JOIN public.$tv2_content_type CT ON T.$pkey = CT.$pkey
  407. INNER JOIN {cvterm} V ON V.cvterm_id = T.type_id
  408. INNER JOIN {dbxref} X ON X.dbxref_id = V.dbxref_id
  409. INNER JOIN {db} ON db.db_id = X.db_id
  410. GROUP BY V.name, X.accession, db.name
  411. ";
  412. $tv3_content_types = chado_query($sql);
  413. while($tv3_content_type = $tv3_content_types->fetchObject()) {
  414. array_push($types, array(
  415. 'namespace' => $tv3_content_type->namespace,
  416. 'accession' => $tv3_content_type->accession,
  417. 'term_name' => $tv3_content_type->type
  418. ));
  419. }
  420. }
  421. else if ($table == 'organism') {
  422. array_push($types, array(
  423. 'namespace' => 'local',
  424. 'accession' => 'organism',
  425. 'term_name' => 'organism'
  426. ));
  427. }
  428. else if ($table == 'analysis') {
  429. array_push($types, array(
  430. 'namespace' => 'local',
  431. 'accession' => 'analysis',
  432. 'term_name' => 'analysis'
  433. ));
  434. }
  435. }
  436. tripal_chado_migrate_selected_types($types);
  437. }
  438. /**
  439. * Migrate only selected Tripal v2 content types
  440. *
  441. * @param unknown $tv3_content_type
  442. */
  443. function tripal_chado_migrate_selected_types($tv3_content_types) {
  444. foreach ($tv3_content_types AS $tv3_content_type) {
  445. // Check if the term already exists
  446. $term = tripal_load_term_entity($tv3_content_type);
  447. // If term doesn't exist, create a new bundle for this term
  448. if (!$term) {
  449. print("Creating bundle for term '" . $tv3_content_type['term_name'] . "'...\n");
  450. $success = tripal_create_bundle($tv3_content_type['namespace'], $tv3_content_type['accession'], $tv3_content_type['term_name']);
  451. $term = tripal_load_term_entity($tv3_content_type);
  452. }
  453. // Create bundle name
  454. $bundle_name = 'bio_data_' . $term->id;
  455. // Publish records for the bundle
  456. $value = array(
  457. 'sync_node' => 1,
  458. 'bundle_name' => $bundle_name
  459. );
  460. tripal_chado_publish_records ($value);
  461. }
  462. }
  463. /**
  464. * Get a list of enabled legacy modules
  465. *
  466. * return an associated array with value of module directory and keyed by the module name
  467. */
  468. function tripal_chado_migrate_get_enabled_legacy_modules ($has_base_template = FALSE) {
  469. $mod_enabled = module_list();
  470. $legacy_mod = array ();
  471. foreach ($mod_enabled AS $mod) {
  472. if (preg_match('/^tripal_/', $mod)) {
  473. $mod_dir = drupal_get_path('module', $mod);
  474. if (preg_match('/\/legacy\//', $mod_dir) ) {
  475. if ($has_base_template) {
  476. if (file_exists($mod_dir . '/theme/templates/' . $mod . '_base.tpl.php')) {
  477. $legacy_mod[$mod] = $mod_dir;
  478. }
  479. } else {
  480. $legacy_mod[$mod] = $mod_dir;
  481. }
  482. }
  483. }
  484. }
  485. return $legacy_mod;
  486. }
  487. /**
  488. * Delete selected Tripal v2 content
  489. *
  490. * Delete all records from chado_* table then call the cleanup orphan nodes function
  491. *
  492. * @param unknown $tv2_content_types
  493. */
  494. function tripal_chado_delete_selected_types($tv2_content_types = array()) {
  495. foreach ($tv2_content_types AS $type) {
  496. $sql = "DELETE FROM $type";
  497. db_query($sql);
  498. }
  499. }
  500. /**
  501. * Unpublish selected Tripal v2 content
  502. *
  503. * Set status = 0 (unpublished) for all nodes of selected Tripal v2 content types
  504. *
  505. * @param unknown $tv2_content_types
  506. */
  507. function tripal_chado_unpublish_selected_types($tv2_content_types = array()) {
  508. foreach ($tv2_content_types AS $type) {
  509. $sql = "UPDATE node SET status = 0 WHERE nid IN (SELECT nid FROM $type)";
  510. db_query($sql);
  511. }
  512. }
  513. /**
  514. * Copy titles for selected Tripal v2 content
  515. *
  516. * Copy tiltles for all nodes of selected Tripal v2 content types
  517. *
  518. * @param unknown $tv2_content_types
  519. */
  520. function tripal_chado_copy_title_for_selected_types($tv2_content_types = array()) {
  521. foreach ($tv2_content_types AS $type) {
  522. $sql = "SELECT nid, entity_id FROM chado_entity WHERE nid IN (SELECT nid FROM $type)";
  523. $result = db_query($sql);
  524. while ($entity = $result->fetchObject()) {
  525. $usql = "
  526. UPDATE tripal_entity
  527. SET title = (SELECT title FROM node WHERE nid = :nid)
  528. WHERE id = :entity_id";
  529. db_query($usql, array(
  530. ':nid' => $entity->nid,
  531. ':entity_id' => $entity->entity_id)
  532. );
  533. }
  534. }
  535. }
  536. /**
  537. * Migrate URL alias for selected Tripal v2 content
  538. *
  539. * Migrate URL alias for all nodes of selected Tripal v2 content types
  540. *
  541. * @param unknown $tv2_content_types
  542. */
  543. function tripal_chado_migrate_url_alias_for_selected_types($tv2_content_types = array()) {
  544. foreach ($tv2_content_types AS $type) {
  545. $sql = "SELECT nid, entity_id FROM chado_entity WHERE nid IN (SELECT nid FROM $type)";
  546. $result = db_query($sql);
  547. while ($entity = $result->fetchObject()) {
  548. $usql = "
  549. UPDATE url_alias
  550. SET source = 'bio_data/'" . $entity->entity_id .
  551. "WHERE source = 'node/" . $entity->nid;
  552. db_query($usql);
  553. }
  554. }
  555. }