tripal_core.chado_nodes.api.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <?php
  2. /**
  3. * @file
  4. * Functions for managing Drupal Nodes corresponding to chado content
  5. *
  6. /**
  7. * Determine whether a given chado table is directly linked to a node
  8. *
  9. * @param $chado_table
  10. * The name of a chado table to check (ie: feature)
  11. * @return
  12. * TRUE if it is linked to a node and FALSE otherwise
  13. */
  14. function tripal_core_is_tripal_node_type($chado_table) {
  15. $linking_table = 'chado_' . $chado_table;
  16. if (db_table_exists($linking_table)) {
  17. return TRUE;
  18. }
  19. else {
  20. return FALSE;
  21. }
  22. }
  23. /**
  24. * Sync'ing chado records with Drupal by creating nodes
  25. *
  26. * How to Use:
  27. * @code
  28. function modulename_menu() {
  29. $module_name = 'tripal_example'; // the machine name of your module
  30. $linking_table = 'chado_example'; // the base specified in hook_node_info
  31. // This menu item will be a tab on the admin/tripal/chado/tripal_example page
  32. // that is not selected by default
  33. $items['admin/tripal/chado/tripal_example/sync'] = array(
  34. 'title' => ' Sync',
  35. 'description' => 'Sync examples from Chado with Drupal',
  36. 'page callback' => 'drupal_get_form',
  37. 'page arguments' => array('tripal_core_chado_node_sync_form', $module_name, $linking_table),
  38. 'access arguments' => array('administer tripal examples'),
  39. 'type' => MENU_LOCAL_TASK,
  40. 'weight' => 0
  41. );
  42. return $items;
  43. }
  44. modulename_node_info() {
  45. return array(
  46. 'chado_example' => array(
  47. 'name' => t('example'),
  48. 'base' => 'chado_example',
  49. 'description' => t('A Chado example is a collection of material that can be sampled and have experiments performed on it.'),
  50. 'has_title' => TRUE,
  51. 'has_body' => FALSE,
  52. // this is what differs from the regular Drupal-documented hook_node_info()
  53. 'chado_node_api' => array(
  54. 'base_table' => 'example', // the name of the chado base table
  55. 'hook_prefix' => 'chado_example', // usually the name of the node type
  56. 'record_type_title' => array(
  57. 'singular' => t('Example'), // Singular human-readable title
  58. 'plural' => t('Examples') // Plural human-readable title
  59. ),
  60. 'sync_filters' => array( // filters for syncing
  61. 'type_id' => TRUE, // TRUE if there is an example.type_id field
  62. 'organism_id' => TRUE, // TRUE if there is an example.organism_id field
  63. 'checkboxes' => array('name') // If the 'checkboxes' key is present then the
  64. // value must be an array of column names in
  65. // base table. The values from these columns will
  66. // be retreived, contentated with a space delimeter
  67. // and provided in a list of checkboxes
  68. // for the user to choose which to sync.
  69. ),
  70. )
  71. ),
  72. );
  73. }
  74. // Create New Node
  75. // @param $new_node: a basic new node object
  76. // @param $record: the record object from chado specifying the biological data for this node
  77. function chado_example_chado_node_sync_create_new_node($new_node, $record) {
  78. // Add relevant chado details to the new node object
  79. // This really only needs to be the fields from the node used during node creation
  80. // including values used to generate the title, etc.
  81. // All additional chado data will be added via nodetype_load when the node is later used
  82. $new_node->uniquename = $record->uniquename;
  83. return $new_node;
  84. }
  85. // Alter the sync form (optional)
  86. function chado_example_chado_node_sync_form($form, $form_state) {
  87. // Change or add to the form array as needed
  88. // Any changes should be made in accordance with the Drupal Form API
  89. return $form;
  90. }
  91. // Bypass chado node api sync form submit (optional)
  92. // Allows you to use this function as your own submit
  93. function chado_example_chado_node_sync_form ($form, $form_state) {
  94. global $user;
  95. $job_args = array(
  96. $base_table, // the base chado table (ie: feature)
  97. $max_sync, // the maximum number of records to sync or FALSE for sync all that match
  98. $organism_id, // the organism_id to restrict records to or FALSE if not to restrict by organism_id
  99. $types // A string with the cvterm.name of the types to restrict to separated by |||
  100. );
  101. // You should register a tripal job
  102. tripal_add_job(
  103. $title, // the title of the job -be descriptive
  104. $module, // the name of your module
  105. 'tripal_core_chado_node_sync_records', // the chado node api sync function
  106. $job_args, // an array with the arguments to pass to the above function
  107. $user->uid // the user who submitted the job
  108. );
  109. }
  110. // Alter the query for the chado database which gets the chado records to be sync'd (optional)
  111. // @param $select: an array of select clauses
  112. // @param $joins: an array of joins (ie: a single join could be 'LEFT JOIN {chadotable} alias ON base.id=alias.id')
  113. // @param $where_clauses: an array of where clauses which will all be AND'ed together. Use :placeholders for values.
  114. // @param $where_args: an associative array of arguments to be subbed in to the where clause
  115. // where the key = :placeholder and the value is the actual argument to be subbed in
  116. function chado_example_chado_node_sync_select_query (&$select, &$joins, &$where_clauses, &$where_args) {
  117. // You can add fields to be selected
  118. $select[] = 'example.myfavfield';
  119. // Or joins to important tables
  120. $joins[] = 'LEFT JOIN {exampleprop} PROP ON PROP.example_id=EXAMPLE.example_id';
  121. // Or filter the query using where clauses
  122. $where_clauses[] = 'example.myfavfield = :favvalue';
  123. $where_args[':favvalue'] = 'awesome-ness';
  124. }
  125. * @endcode
  126. */
  127. /**
  128. * Generic Sync Form
  129. */
  130. function tripal_core_chado_node_sync_form($form, &$form_state) {
  131. $form = array();
  132. if (isset($form_state['build_info']['args'][0])) {
  133. $module = $form_state['build_info']['args'][0];
  134. $linking_table = $form_state['build_info']['args'][1];
  135. $node_info = call_user_func($module . '_node_info');
  136. $args = $node_info[$linking_table]['chado_node_api'];
  137. $form_state['chado_node_api'] = $args;
  138. }
  139. // define the fieldsets
  140. $form['sync'] = array(
  141. '#type' => 'fieldset',
  142. '#title' => 'Sync ' . $args['record_type_title']['plural'],
  143. '#descrpition' => '',
  144. );
  145. $form['sync']['description'] = array(
  146. '#type' => 'item',
  147. '#value' => t("%title_plural of the types listed ".
  148. "below in the %title_singular Types box will be synced (leave blank to sync all types). You may limit the ".
  149. "%title_plural to be synced by a specific organism. Depending on the ".
  150. "number of %title_plural in the chado database this may take a long ".
  151. "time to complete. ",
  152. array(
  153. '%title_singular' => $args['record_type_title']['singular'],
  154. '%title_plural' => $args['record_type_title']['plural']
  155. )),
  156. );
  157. if ($args['sync_filters']['type_id']) {
  158. $form['sync']['type_ids'] = array(
  159. '#title' => t('%title_singular Types',
  160. array(
  161. '%title_singular' => $args['record_type_title']['singular'],
  162. '%title_plural' => $args['record_type_title']['plural']
  163. )),
  164. '#type' => 'textarea',
  165. '#description' => t("Enter the names of the %title_singular types to sync. " .
  166. "Leave blank to sync all %title_plural. Separate each type with a comma ".
  167. "or new line. Pages for these %title_singular ".
  168. "types will be created automatically for %title_plural that exist in the ".
  169. "chado database. The names must match ".
  170. "exactly (spelling and case) with terms in the ontologies",
  171. array(
  172. '%title_singular' => strtolower($args['record_type_title']['singular']),
  173. '%title_plural' => strtolower($args['record_type_title']['plural'])
  174. )),
  175. '#default_value' => (isset($form_state['values']['type_id'])) ? $form_state['values']['type_id'] : '',
  176. );
  177. }
  178. // get the list of organisms
  179. if ($args['sync_filters']['organism_id']) {
  180. $sql = "SELECT * FROM {organism} ORDER BY genus, species";
  181. $results = chado_query($sql);
  182. $organisms[] = '';
  183. foreach ($results as $organism) {
  184. $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
  185. }
  186. $form['sync']['organism_id'] = array(
  187. '#title' => t('Organism'),
  188. '#type' => t('select'),
  189. '#description' => t("Choose the organism for which %title_plural types set above will be synced.",
  190. array(
  191. '%title_singular' => $args['record_type_title']['singular'],
  192. '%title_plural' => $args['record_type_title']['plural']
  193. )),
  194. '#options' => $organisms,
  195. '#default_value' => (isset($form_state['values']['organism_id'])) ? $form_state['values']['organism_id'] : 0,
  196. );
  197. }
  198. // get the list of organisms
  199. if (array_key_exists('checkboxes', $args['sync_filters'])) {
  200. // get the base schema
  201. $base_table = $args['base_table'];
  202. $table_info = tripal_core_get_chado_table_schema($base_table);
  203. // if the base table does not have a primary key or has more than one then
  204. // we can't proceed, otherwise, generate the checkboxes
  205. if (array_key_exists('primary key', $table_info) and count($table_info['primary key']) == 1) {
  206. $pkey = $table_info['primary key'][0];
  207. $columns = $args['sync_filters']['checkboxes'];
  208. $select_cols = implode("|| ' ' ||", $columns);
  209. // get non-synced records
  210. $sql = "
  211. SELECT BT.$pkey as id, $select_cols as value
  212. FROM {" . $base_table . "} BT
  213. LEFT JOIN public.$linking_table LT ON LT.$pkey = BT.$pkey
  214. WHERE LT.$pkey IS NULL
  215. ORDER BY value ASC
  216. ";
  217. $results = chado_query($sql);
  218. $values = array();
  219. foreach ($results as $result) {
  220. $values[$result->id] = $result->value;
  221. }
  222. if (count($values) > 0) {
  223. $form['sync']['ids'] = array(
  224. '#title' => 'Avaliable ' . $args['record_type_title']['plural'],
  225. '#type' => 'checkboxes',
  226. '#description' => t("The above %title_plural have not been synced. Check those to be synced or leave all unchecked to sync them all.",
  227. array(
  228. '%title_singular' => strtolower($args['record_type_title']['singular']),
  229. '%title_plural' => strtolower($args['record_type_title']['plural'])
  230. )),
  231. '#options' => $values,
  232. '#default_value' => (isset($form_state['values']['ids'])) ? $form_state['values']['ids'] : array(),
  233. '#prefix' => '<div style="height: 200px; overflow: scroll">',
  234. '#suffix' => '</div><br>',
  235. );
  236. }
  237. else {
  238. $form['sync']['no_ids'] = array(
  239. '#markup' => "<p>There are no " . strtolower($args['record_type_title']['plural']) . " to sync.</p>",
  240. );
  241. }
  242. }
  243. }
  244. // if we provide a list of checkboxes we shouldn't need a max_sync
  245. else {
  246. $form['sync']['max_sync'] = array(
  247. '#type' => 'textfield',
  248. '#title' => t('Maximum number of records to Sync'),
  249. '#description' => t('Leave this field empty to sync all records, regardless of number'),
  250. '#default_value' => (isset($form_state['values']['max_sync'])) ? $form_state['values']['max_sync'] : '',
  251. );
  252. }
  253. $form['sync']['button'] = array(
  254. '#type' => 'submit',
  255. '#value' => t('Sync ' . $args['record_type_title']['plural']),
  256. '#weight' => 3,
  257. );
  258. $form['cleanup'] = array(
  259. '#type' => 'fieldset',
  260. '#title' => t('Clean Up')
  261. );
  262. $form['cleanup']['description'] = array(
  263. '#markup' => t("<p>With Drupal and chado residing in different databases " .
  264. "it is possible that nodes in Drupal and " . strtolower($args['record_type_title']['plural']) . " in Chado become " .
  265. "\"orphaned\". This can occur if a node in Drupal is " .
  266. "deleted but the corresponding chado records is not and/or vice " .
  267. "versa. Click the button below to resolve these discrepancies.</p>"),
  268. '#weight' => 1,
  269. );
  270. $form['cleanup']['button'] = array(
  271. '#type' => 'submit',
  272. '#value' => 'Clean up orphaned ' . strtolower($args['record_type_title']['plural']),
  273. '#weight' => 2,
  274. );
  275. // Allow each module to alter this form as needed
  276. $hook_form_alter = $args['hook_prefix'] . '_chado_node_sync_form';
  277. if (function_exists($hook_form_alter)) {
  278. $form = call_user_func($hook_form_alter, $form, $form_state);
  279. }
  280. return $form;
  281. }
  282. /**
  283. * Generic Sync Form Submit
  284. */
  285. function tripal_core_chado_node_sync_form_submit($form, $form_state) {
  286. global $user;
  287. if (preg_match('/^Sync/', $form_state['values']['op'])) {
  288. // get arguments
  289. $args = $form_state['chado_node_api'];
  290. $module = $form_state['chado_node_api']['hook_prefix'];
  291. $base_table = $form_state['chado_node_api']['base_table'];
  292. // Allow each module to hijack the submit if needed
  293. $hook_form_hijack_submit = $args['hook_prefix'] . '_chado_node_sync_form_submit';
  294. if (function_exists($hook_form_hijack_submit)) {
  295. return call_user_func($hook_form_hijack_submit, $form, $form_state);
  296. }
  297. // Get the types separated into a consistent string
  298. $types = array();
  299. if (isset($form_state['values']['type_ids'])) {
  300. // seperate by new line or comma.
  301. $temp_types = preg_split("/[,\n\r]+/", $form_state['values']['type_ids']);
  302. // remove any extra spacing around the types
  303. for($i = 0; $i < count($temp_types); $i++) {
  304. // skip empty types
  305. if (trim($temp_types[$i]) == '') {
  306. continue;
  307. }
  308. $types[$i] = trim($temp_types[$i]);
  309. }
  310. }
  311. // Get the ids to be synced
  312. $ids = array();
  313. if (array_key_exists('ids', $form_state['values'])){
  314. foreach ($form_state['values']['ids'] as $id => $selected) {
  315. if ($selected) {
  316. $ids[] = $id;
  317. }
  318. }
  319. }
  320. // get the organism to be synced
  321. $organism_id = FALSE;
  322. if (array_key_exists('organism_id', $form_state['values'])) {
  323. $organism_id = $form_state['values']['organism_id'];
  324. }
  325. // Job Arguments
  326. $job_args = array(
  327. 'base_table' => $base_table,
  328. 'max_sync' => (!empty($form_state['values']['max_sync'])) ? $form_state['values']['max_sync'] : FALSE,
  329. 'organism_id' => $organism_id,
  330. 'types' => $types,
  331. 'ids' => $ids,
  332. );
  333. $title = "Sync " . $args['record_type_title']['plural'];
  334. tripal_add_job($title, $module, 'tripal_core_chado_node_sync_records', $job_args, $user->uid);
  335. }
  336. if (preg_match('/^Clean up orphaned/', $form_state['values']['op'])) {
  337. $module = $form_state['chado_node_api']['hook_prefix'];
  338. $base_table = $form_state['chado_node_api']['base_table'];
  339. $job_args = array($base_table);
  340. tripal_add_job($form_state['values']['op'], $module, 'tripal_core_chado_node_cleanup_orphaned', $job_args, $user->uid);
  341. }
  342. }
  343. /**
  344. * Actual Sync Function. Works on a group of records
  345. */
  346. function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id = FALSE,
  347. $types = array(), $ids = array(), $job_id = NULL) {
  348. global $user;
  349. $base_table_id = $base_table . '_id';
  350. print "\nSync'ing $base_table records. ";
  351. // START BUILDING QUERY TO GET ALL RECORD FROM BASE TABLE THAT MATCH
  352. $select = array("$base_table.*");
  353. $joins = array();
  354. $where_clauses = array();
  355. $where_args = array();
  356. // If types are supplied then handle them
  357. $restrictions = '';
  358. if (count($types) > 0) {
  359. $restrictions .= " Type(s): " . implode(', ',$types) . "\n";
  360. $select[] = 'cvterm.name as cvtname';
  361. $joins[] = "LEFT JOIN {cvterm} cvterm ON $base_table.type_id = cvterm.cvterm_id";
  362. foreach ($types as $type) {
  363. $where_clauses['type'][] = "cvterm.name = :type_name_$type";
  364. $where_args['type'][":type_name_$type"] = $type;
  365. }
  366. }
  367. // if IDs have been supplied
  368. if ($ids) {
  369. $restrictions .= " Specific Records: " . count($ids) . " recored(s) specified.\n";
  370. foreach ($ids as $id) {
  371. $where_clauses['id'][] = "$base_table.$base_table_id = :id_$id";
  372. $where_args['id'][":id_$id"] = $id;
  373. }
  374. }
  375. // If Organism is supplied
  376. if ($organism_id) {
  377. $organism = tripal_core_chado_select('organism', array('*'), array('organism_id' => $organism_id));
  378. $restrictions .= " Organism: " . $organism[0]->genus . " " . $organism[0]->species . "\n";
  379. $select[] = 'organism.*';
  380. $joins[] = "LEFT JOIN {organism} organism ON organism.organism_id = $base_table.organism_id";
  381. $where_clauses['organism'][] = 'organism.organism_id = :organism_id';
  382. $where_args['organism'][':organism_id'] = $organism_id;
  383. }
  384. // Allow module to add to query
  385. $hook_query_alter = 'chado_' . $base_table . '_chado_node_sync_select_query';
  386. if (function_exists($hook_query_alter)) {
  387. call_user_func($hook_query_alter, $select, $joins, $where_clauses, $where_args);
  388. }
  389. // Build Query, we do a left join on the chado_xxxx table in the Drupal schema
  390. // so that if no criteria are specified we only get those items that have not
  391. // yet been synced.
  392. $query = "
  393. SELECT " . implode(', ',$select) . ' ' .
  394. 'FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins) . ' '.
  395. " LEFT JOIN public.chado_$base_table CT ON CT.$base_table_id = $base_table.$base_table_id " .
  396. "WHERE CT.$base_table_id IS NULL AND";
  397. // extend the where clause if needed
  398. $where = '';
  399. $sql_args = array();
  400. if (count($where_clauses['type']) > 0) {
  401. $where .= '(' . implode(' OR ', $where_clauses['type']) . ') AND';
  402. $sql_args = array_merge($sql_args, $where_args['type']);
  403. }
  404. if (count($where_clauses['organism']) > 0) {
  405. $where .= '(' . implode(' OR ', $where_clauses['organism']) . ') AND';
  406. $sql_args = array_merge($sql_args, $where_args['organism']);
  407. }
  408. if (count($where_clauses['id']) > 0) {
  409. $where .= '(' . implode(' OR ', $where_clauses['id']) . ') AND';
  410. $sql_args = array_merge($sql_args, $where_args['id']);
  411. }
  412. if ($where) {
  413. $query .= $where;
  414. }
  415. $query = substr($query, 0, -4); // remove the trailing 'AND'
  416. $query .- " ORDER BY " . $base_table_id;
  417. // If Maximum number to Sync is supplied
  418. if ($max_sync) {
  419. $query .= " LIMIT $max_sync";
  420. $restrictions .= " Limited to $max_sync records.\n";
  421. }
  422. if ($restrictions) {
  423. print "Records matching these criteria will be synced: \n$restrictions";
  424. }
  425. else {
  426. print "\n";
  427. }
  428. // execute the query
  429. $results = chado_query($query, $sql_args);
  430. // Iterate through features that need to be synced
  431. $count = $results->rowCount();
  432. $interval = intval($count * 0.01);
  433. if ($interval < 1) {
  434. $interval = 1;
  435. }
  436. print "\n$count $base_table records found.\n";
  437. $i = 0;
  438. $transaction = db_transaction();
  439. try {
  440. foreach ($results as $record) {
  441. print "\nLoading $base_table " . ($i + 1) . " of $count ($base_table_id=".$record->{$base_table_id}.")...";
  442. // update the job status every 1% features
  443. if ($job_id and $i % $interval == 0) {
  444. $percent = sprintf("%.2f", ($i / $count) * 100);
  445. print "Parsing Line $line_num (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\n";
  446. tripal_job_set_progress($job_id, intval(($i/$count)*100));
  447. }
  448. // Check if it is in the chado linking table (ie: check to see if it is already linked to a node)
  449. $result = db_select('chado_'.$base_table, 'lnk')
  450. ->fields('lnk',array('nid'))
  451. ->condition($base_table_id, $record->{$base_table_id}, '=')
  452. ->execute()
  453. ->fetchObject();
  454. if (!empty($result)) {
  455. print " Previously Sync'd";
  456. }
  457. else {
  458. // Create generic new node
  459. $new_node = new stdClass();
  460. $new_node->type = 'chado_' . $base_table;
  461. $new_node->uid = $user->uid;
  462. $new_node->{$base_table_id} = $record->{$base_table_id};
  463. $new_node->library = $record;
  464. // TODO: should we get rid of this hook and use hook_node_presave() instead?
  465. // allow base module to set additional fields as needed
  466. $hook_create_new_node = 'chado_' . $base_table . '_chado_node_sync_create_new_node';
  467. if (function_exists($hook_create_new_node)) {
  468. $new_node = call_user_func($hook_create_new_node, $new_node, $record);
  469. }
  470. // Validate and Save New Node
  471. $form = array();
  472. $form_state = array();
  473. node_validate($new_node, $form, $form_state);
  474. if (!form_get_errors()) {
  475. $node = node_submit($new_node);
  476. node_save($node);
  477. print " Node Created (nid=".$node->nid.")";
  478. }
  479. else {
  480. watchdog('trp-fsync', "Failed to insert $base_table: %title", array('%title' => $new_node->title), WATCHDOG_ERROR);
  481. }
  482. }
  483. $i++;
  484. }
  485. print "\n\nComplete!\n";
  486. }
  487. catch (Exception $e) {
  488. print "\n"; // make sure we start errors on new line
  489. watchdog_exception('trp-fsync', $e);
  490. $transaction->rollback();
  491. print "FAILED: Rolling back database changes...\n";
  492. }
  493. }
  494. /**
  495. * This function will delete Drupal nodes for any sync'ed table (e.g.
  496. * feature, organism, analysis, stock, library) if the chado record has been
  497. * deleted or the entry in the chado_[table] table has been removed.
  498. *
  499. * @param $table
  500. * The name of the table that corresonds to the node type we want to clean up.
  501. * @param $job_id
  502. * This should be the job id from the Tripal jobs system. This function
  503. * will update the job status using the provided job ID.
  504. *
  505. * @ingroup tripal_core_api
  506. */
  507. function tripal_core_chado_node_cleanup_orphaned($table, $job_id = NULL) {
  508. $count = 0;
  509. // build the SQL statments needed to check if nodes point to valid analyses
  510. $dsql = "SELECT * FROM {node} WHERE type = 'chado_" . $table . "' order by nid";
  511. $nsql = "SELECT * FROM {node} WHERE nid = :nid";
  512. $csql = "SELECT * FROM {chado_" . $table . "} WHERE nid = :nid ";
  513. $clsql= "SELECT * FROM {chado_" . $table . "}";
  514. $lsql = "SELECT * FROM {" . $table . "} where " . $table . "_id = :" . $table . "_id ";
  515. // load into nodes array
  516. print "Getting nodes\n";
  517. $nodes = array();
  518. $res = db_query($dsql);
  519. foreach ($res as $node) {
  520. $nodes[$count] = $node;
  521. $count++;
  522. }
  523. // load the chado_$table into an array
  524. print "Getting chado_$table\n";
  525. $cnodes = array();
  526. $res = db_query($clsql);
  527. foreach ($res as $node) {
  528. $cnodes[$count] = $node;
  529. $count++;
  530. }
  531. $interval = intval($count * 0.01);
  532. if ($interval < 1) {
  533. $interval = 1;
  534. }
  535. // iterate through all of the chado_$table entries and remove those
  536. // that don't have a node or don't have a $table record in chado.libary
  537. print "Verifying all chado_$table Entries\n";
  538. $deleted = 0;
  539. foreach ($cnodes as $nid) {
  540. // update the job status every 1% analyses
  541. if ($job_id and $i % $interval == 0) {
  542. tripal_job_set_progress($job_id, intval(($i / $count) * 100));
  543. }
  544. // see if the node exits, if not remove the entry from the chado_$table table
  545. $results = db_query($nsql, array(':nid' => $nid->nid));
  546. $node = $results->fetchObject();
  547. if (!$node) {
  548. $deleted++;
  549. db_query("DELETE FROM {chado_" . $table . "} WHERE nid = :nid", array(':nid' => $nid->nid));
  550. $message = "chado_$table missing node.... DELETING: $nid->nid";
  551. watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
  552. }
  553. // see if the record in chado exist, if not remove the entry from the chado_$table
  554. $table_id = $table . "_id";
  555. $results = chado_query($lsql, array(":" . $table . "_id" => $nid->$table_id));
  556. $record = $results->fetchObject();
  557. if (!$record) {
  558. $deleted++;
  559. $sql = "DELETE FROM {chado_" . $table . "} WHERE " . $table . "_id = :" . $table . "_id";
  560. db_query($sql, array(":" . $table . "_id" => $nid->$table_id));
  561. $message = "chado_$table missing $table.... DELETING entry.";
  562. watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
  563. }
  564. $i++;
  565. }
  566. print "\t$deleted chado_$table entries missing either a node or chado entry.\n";
  567. // iterate through all of the nodes and delete those that don't
  568. // have a corresponding entry in chado_$table
  569. $deleted = 0;
  570. foreach ($nodes as $node) {
  571. // update the job status every 1% libraries
  572. if ($job_id and $i % $interval == 0) {
  573. tripal_job_set_progress($job_id, intval(($i / $count) * 100));
  574. }
  575. // check to see if the node has a corresponding entry
  576. // in the chado_$table table. If not then delete the node.
  577. $results = db_query($csql, array(":nid" => $node->nid));
  578. $link = $results->fetchObject();
  579. if (!$link) {
  580. if (node_access('delete', $node)) {
  581. $deleted++;
  582. $message = "Node missing in chado_$table table.... DELETING node $node->nid";
  583. watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
  584. node_delete($node->nid);
  585. }
  586. else {
  587. $message = "Node missing in chado_$table table.... but cannot delete due to improper permissions (node $node->nid)";
  588. watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
  589. }
  590. }
  591. $i++;
  592. }
  593. print "\t$deleted nodes did not have corresponding chado_$table entries.\n";
  594. return '';
  595. }