tripal_phylogeny.chado_node.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. <?php
  2. /**
  3. * @file
  4. * Implements the phylotree node content type
  5. */
  6. /**
  7. * Implements hook_node_info().
  8. *
  9. * Provide information to drupal about the node types that we're creating
  10. * in this module.
  11. *
  12. * @ingroup tripal_legacy_phylogeny
  13. */
  14. function tripal_phylogeny_node_info() {
  15. $nodes = [];
  16. $nodes['chado_phylotree'] = [
  17. 'name' => t('Phylotree (Tripal v2 legacy)'),
  18. 'base' => 'chado_phylotree',
  19. 'description' => t('A phylotree from the chado database'),
  20. 'has_title' => TRUE,
  21. 'locked' => TRUE,
  22. 'chado_node_api' => [
  23. 'base_table' => 'phylotree',
  24. 'hook_prefix' => 'chado_phylotree',
  25. 'record_type_title' => [
  26. 'singular' => t('Phylotree'),
  27. 'plural' => t('Phylotrees'),
  28. ],
  29. /* sync_filters: tripal is hardcoded to look for this
  30. sync_filter settings: type_id and organism_id. (phylotree does
  31. not have organism_id but need to set it false anyways. */
  32. 'sync_filters' => [
  33. 'type_id' => FALSE,
  34. 'organism_id' => FALSE,
  35. ],
  36. ],
  37. ];
  38. return $nodes;
  39. }
  40. /**
  41. * Implements hook_node_view(). Acts on all content types
  42. *
  43. * @ingroup tripal_legacy_phylogeny
  44. */
  45. function tripal_phylogeny_node_view($node, $view_mode, $langcode) {
  46. if ($node->type != 'chado_phylotree') {
  47. return;
  48. }
  49. switch ($view_mode) {
  50. case 'full':
  51. $node->content['tripal_phylogeny_base'] = [
  52. '#theme' => 'tripal_phylogeny_base',
  53. '#node' => $node,
  54. '#tripal_toc_id' => 'base',
  55. '#tripal_toc_title' => 'Overview',
  56. '#weight' => -100,
  57. ];
  58. $node->content['tripal_phylogeny_phylogram'] = [
  59. '#theme' => 'tripal_phylogeny_phylogram',
  60. '#node' => $node,
  61. '#tripal_toc_id' => 'phylotree_phylogram',
  62. '#tripal_toc_title' => 'Phylogram',
  63. '#weight' => -90,
  64. ];
  65. $node->content['tripal_phylogeny_taxonomic_tree'] = [
  66. '#theme' => 'tripal_phylogeny_taxonomic_tree',
  67. '#node' => $node,
  68. '#tripal_toc_id' => 'tripal_phylogeny_taxonomic_tree',
  69. '#tripal_toc_title' => 'Taxonomic Tree',
  70. '#weight' => -80,
  71. ];
  72. $node->content['tripal_phylogeny_organisms'] = [
  73. '#theme' => 'tripal_phylogeny_organisms',
  74. '#node' => $node,
  75. '#tripal_toc_id' => 'phylotree_organisms',
  76. '#tripal_toc_title' => 'Organisms',
  77. '#weight' => -70,
  78. ];
  79. $node->content['tripal_phylogeny_references'] = [
  80. '#theme' => 'tripal_phylogeny_references',
  81. '#node' => $node,
  82. '#tripal_toc_id' => 'phylotree_references',
  83. '#tripal_toc_title' => 'Cross References',
  84. ];
  85. $node->content['tripal_phylogeny_analysis'] = [
  86. '#theme' => 'tripal_phylogeny_analysis',
  87. '#node' => $node,
  88. '#tripal_toc_id' => 'phylotree_analysis',
  89. '#tripal_toc_title' => 'Analysis',
  90. ];
  91. break;
  92. case 'teaser':
  93. $node->content['tripal_phylogeny_teaser'] = [
  94. '#theme' => 'tripal_phylogeny_teaser',
  95. '#node' => $node,
  96. ];
  97. break;
  98. }
  99. }
  100. /**
  101. * Implementation of hook_form().
  102. *
  103. * @ingroup tripal_legacy_phylogeny
  104. */
  105. function chado_phylotree_form($node, &$form_state) {
  106. $form = [];
  107. // Default values can come in the following ways:
  108. //
  109. // 1) as elements of the $node object. This occurs when editing an existing phylotree
  110. // 2) in the $form_state['values'] array which occurs on a failed validation or
  111. // ajax callbacks from non submit form elements
  112. // 3) in the $form_state['input'[ array which occurs on ajax callbacks from submit
  113. // form elements and the form is being rebuilt
  114. //
  115. // set form field defaults
  116. $phylotree = NULL;
  117. $phylotree_id = NULL;
  118. $tree_name = '';
  119. $leaf_type = '';
  120. $analysis_id = '';
  121. $dbxref = '';
  122. $comment = '';
  123. $tree_required = TRUE;
  124. $tree_file = '';
  125. $name_re = '';
  126. $match = '';
  127. // If we are editing an existing node then the phylotree is already part of the node.
  128. if (property_exists($node, 'phylotree')) {
  129. $phylotree = $node->phylotree;
  130. $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
  131. $phylotree_id = $phylotree->phylotree_id;
  132. $tree_name = $phylotree->name;
  133. $leaf_type = $phylotree->type_id ? $phylotree->type_id->name : '';
  134. $comment = $phylotree->comment;
  135. $analysis_id = $phylotree->analysis_id ? $phylotree->analysis_id->analysis_id : '';
  136. $dbxref = $phylotree->dbxref_id->db_id->name . ":" . $phylotree->dbxref_id->accession;
  137. $name_re = $phylotree->tripal_variables->phylotree_name_re;
  138. $match = $phylotree->tripal_variables->phylotree_use_uniquename;
  139. // If the dbxref is the null db then hide it.
  140. if ($phylotree->dbxref_id->db_id->name == 'null') {
  141. $dbxref = '';
  142. }
  143. // Get the tree file name. If the file was added via the Drupal interface
  144. // then a numeric file_id will be present in the phylotree_tree_file
  145. // variable. If not then the tree was loaded on the command-line and
  146. // the actual filename is in this variable.
  147. $file_id = $phylotree->tripal_variables->phylotree_tree_file;
  148. if (is_numeric($file_id)) {
  149. $file = file_load($file_id);
  150. if ($file) {
  151. $tree_file = $file->filename;
  152. }
  153. }
  154. else {
  155. $tree_file = $file_id;
  156. }
  157. // The tree file is not a required input field when editing the node.
  158. $tree_required = FALSE;
  159. // Keep track of the phylotree id.
  160. $form['phylotree_id'] = [
  161. '#type' => 'value',
  162. '#value' => $phylotree_id,
  163. ];
  164. }
  165. // If we are re constructing the form from a failed validation or ajax callback
  166. // then use the $form_state['values'] values.
  167. if (array_key_exists('values', $form_state) and isset($form_state['values']['tree_name'])) {
  168. $tree_name = $form_state['values']['tree_name'];
  169. $leaf_type = $form_state['values']['leaf_type'];
  170. $analysis_id = $form_state['values']['analysis_id'];
  171. $dbxref = $form_state['values']['dbxref'];
  172. $comment = $form_state['values']['description'];
  173. }
  174. // If we are re building the form from after submission (from ajax call) then
  175. // the values are in the $form_state['input'] array.
  176. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  177. $tree_name = $form_state['input']['tree_name'];
  178. $leaf_type = $form_state['input']['leaf_type'];
  179. $analysis_id = $form_state['input']['analysis_id'];
  180. $comment = $form_state['input']['description'];
  181. $dbxref = $form_state['input']['dbxref'];
  182. }
  183. $form['tree_name'] = [
  184. '#type' => 'textfield',
  185. '#title' => t('Tree Name'),
  186. '#required' => TRUE,
  187. '#default_value' => $tree_name,
  188. '#description' => t('Enter the name used to refer to this phylogenetic tree.'),
  189. '#maxlength' => 255,
  190. ];
  191. $type_cv = tripal_get_default_cv('phylotree', 'type_id');
  192. $so_cv = tripal_get_cv(['name' => 'sequence']);
  193. $cv_id = $so_cv->cv_id;
  194. if (!$so_cv) {
  195. drupal_set_message('The Sequence Ontolgoy does not appear to be imported.
  196. Please import the Sequence Ontology before adding a tree.', 'error');
  197. }
  198. $form['leaf_type'] = [
  199. '#title' => t('Tree Type'),
  200. '#type' => 'textfield',
  201. '#description' => t("Choose the tree type. The type is
  202. a valid Sequence Ontology (SO) term. For example, trees derived
  203. from protein sequences should use the SO term 'polypeptide'.
  204. Alternatively, a phylotree can be used for representing a taxonomic
  205. tree. In this case, the word 'taxonomy' should be used."),
  206. '#required' => TRUE,
  207. '#default_value' => $leaf_type,
  208. '#autocomplete_path' => "admin/tripal/legacy/tripal_cv/cvterm/auto_name/$cv_id",
  209. ];
  210. // Get the list of analyses.
  211. $sql = "SELECT * FROM {analysis} ORDER BY name";
  212. $arset = chado_query($sql);
  213. $analyses = [];
  214. $analyses[''] = '';
  215. while ($analysis = $arset->fetchObject()) {
  216. $analyses[$analysis->analysis_id] = $analysis->name;
  217. }
  218. $form['analysis_id'] = [
  219. '#title' => t('Analysis'),
  220. '#type' => 'select',
  221. '#description' => t("Choose the analysis from which this phylogenetic tree was derived"),
  222. '#required' => TRUE,
  223. '#default_value' => $analysis_id,
  224. '#options' => $analyses,
  225. ];
  226. $form['dbxref'] = [
  227. '#title' => t('Database Cross-Reference'),
  228. '#type' => 'textfield',
  229. '#description' => t("Enter a database cross-reference of the form
  230. [DB name]:[accession]. The database name must already exist in the
  231. database. If the accession does not exist it is automatically added."),
  232. '#required' => FALSE,
  233. '#default_value' => $dbxref,
  234. ];
  235. $form['description'] = [
  236. '#type' => 'textarea',
  237. '#title' => t('Description'),
  238. '#required' => TRUE,
  239. '#default_value' => $comment,
  240. '#description' => t('Enter a description for this tree.'),
  241. ];
  242. $upload_location = tripal_get_files_stream('tripal_phylogeny');
  243. $form['tree_file'] = [
  244. '#type' => 'fieldset',
  245. '#title' => t('Tree File Import'),
  246. '#collapsible' => FALSE,
  247. ];
  248. $description = t('Please provide a file in the Newick format that contains
  249. the nodes of this tree.');
  250. if ($tree_file) {
  251. $form['tree_file']['curr_file'] = [
  252. '#type' => 'item',
  253. '#title' => 'Current Tree File',
  254. '#markup' => $tree_file,
  255. ];
  256. $description = t('Please provide a file in the Newick format that
  257. contains the nodes of this tree. Please note that uploading a new
  258. file will overwrite the current tree.');
  259. }
  260. $form['tree_file']['tree_file'] = [
  261. '#type' => 'managed_file',
  262. '#title' => t('New Tree File'),
  263. '#description' => $description,
  264. '#upload_location' => $upload_location,
  265. '#upload_validators' => [
  266. // We don't want to require a specific file extension so leave the array empty.
  267. 'file_validate_extensions' => [],
  268. // The following is for checking the Newick file format.
  269. 'chado_phylotree_validate_newick_format' => [],
  270. ],
  271. '#required' => $tree_required,
  272. ];
  273. $form['tree_file']['name_re'] = [
  274. '#title' => t('Feature Name Regular Expression'),
  275. '#type' => 'textfield',
  276. '#description' => t('If this is a phylogenetic (non taxonomic) tree, then
  277. the tree nodes will be automatically associated with features. However,
  278. if the nodes in the tree file are not exactly as the names of features
  279. but have enough information to uniquely identify the feature then you
  280. may provide a regular expression that the importer will use to extract
  281. the feature names from the node names.'),
  282. '#default_value' => $name_re,
  283. ];
  284. $form['tree_file']['match'] = [
  285. '#title' => t('Use Unique Feature Name'),
  286. '#type' => 'checkbox',
  287. '#description' => t('If this is a phylogenetic (non taonomic tree) and the nodes ' .
  288. 'should match the unique name of the feature rather than the name of the feautre ' .
  289. 'then select this box. If unselected the loader will try to match the feature ' .
  290. 'using the feature name.'),
  291. '#default_value' => $match,
  292. ];
  293. return $form;
  294. }
  295. /**
  296. * A validation function for checking the newick file format.
  297. *
  298. * @param stdClass $file
  299. * A Drupal file object.
  300. */
  301. function chado_phylotree_validate_newick_format(stdClass $file) {
  302. // An array of strings where each string represents a unique error
  303. // when examining the file.
  304. $errors = [];
  305. // TODO: check the newick file format for errors.
  306. return $errors;
  307. }
  308. /**
  309. * Implementation of hook_validate().
  310. *
  311. * This validation is being used for three activities:
  312. * CASE A: Update a node that exists in both drupal and chado
  313. * CASE B: Synchronizing a node from chado to drupal
  314. * CASE C: Inserting a new node that exists in niether drupal nor chado
  315. *
  316. * @ingroup tripal_legacy_phylogeny
  317. */
  318. function chado_phylotree_validate($node, $form, &$form_state) {
  319. // We are syncing if we do not have a node ID but we do have a phylotree_id. We don't
  320. // need to validate during syncing so just skip it.
  321. if (is_null($node->nid) and property_exists($node, 'phylotree_id') and $node->phylotree_id != 0) {
  322. return;
  323. }
  324. // Remove surrounding white-space on submitted values.
  325. $node->tree_name = trim($node->tree_name);
  326. $node->description = trim($node->description);
  327. $node->dbxref = trim($node->dbxref);
  328. // if this is a delete then don't validate
  329. if ($node->op == 'Delete') {
  330. return;
  331. }
  332. $errors = [];
  333. $warnings = [];
  334. $options = [
  335. 'name' => $node->tree_name,
  336. 'description' => $node->description,
  337. 'analysis_id' => $node->analysis_id,
  338. 'leaf_type' => $node->leaf_type,
  339. 'tree_file' => $node->tree_file,
  340. 'format' => 'newick',
  341. 'dbxref' => $node->dbxref,
  342. 'match' => $node->match,
  343. 'name_re' => $node->name_re,
  344. ];
  345. // If we have a node id already then this is an update:
  346. if ($node->nid) {
  347. $options['phylotree_id'] = $node->phylotree_id;
  348. tripal_validate_phylotree('update', $options, $errors, $warnings);
  349. }
  350. else {
  351. tripal_validate_phylotree('insert', $options, $errors, $warnings);
  352. }
  353. // Now set form errors if any errors were detected.
  354. if (count($errors) > 0) {
  355. foreach ($errors as $field => $message) {
  356. if ($field == 'name') {
  357. $field = 'tree_name';
  358. }
  359. form_set_error($field, $message);
  360. }
  361. }
  362. // Add any warnings if any were detected
  363. if (count($warnings) > 0) {
  364. foreach ($warnings as $field => $message) {
  365. drupal_set_message($message, 'warning');
  366. }
  367. }
  368. }
  369. /**
  370. * Implements hook_node_presave(). Acts on all node content types.
  371. *
  372. * @ingroup tripal_legacy_phylogeny
  373. */
  374. function tripal_phylogeny_node_presave($node) {
  375. switch ($node->type) {
  376. // This step is for setting the title for the Drupal node. This title
  377. // is permanent and thus is created to be unique. Title changes provided
  378. // by tokens are generated on the fly dynamically, but the node title
  379. // seen in the content listing needs to be set here. Do not call
  380. // the chado_get_node_title() function here to set the title as the node
  381. // object isn't properly filled out and the function will fail.
  382. case 'chado_phylotree':
  383. // for a form submission the 'phylotreename' field will be set,
  384. // for a sync, we must pull from the phylotree object
  385. if (property_exists($node, 'phylotreename')) {
  386. // set the title
  387. $node->title = $node->tree_name;
  388. }
  389. else {
  390. if (property_exists($node, 'phylotree')) {
  391. $node->title = $node->phylotree->name;
  392. }
  393. }
  394. break;
  395. }
  396. }
  397. /**
  398. * Implements hook_node_insert().
  399. * Acts on all content types.
  400. *
  401. * @ingroup tripal_legacy_phylogeny
  402. */
  403. function tripal_phylogeny_node_insert($node) {
  404. switch ($node->type) {
  405. case 'chado_phylotree':
  406. $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
  407. $values = ['phylotree_id' => $phylotree_id];
  408. $phylotree = chado_generate_var('phylotree', $values);
  409. $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
  410. $node->phylotree = $phylotree;
  411. // Now use the API to set the path.
  412. chado_set_node_url($node);
  413. // Now get the title.
  414. $node->title = chado_get_node_title($node);
  415. break;
  416. }
  417. }
  418. /**
  419. * Implements hook_node_update().
  420. * Acts on all content types.
  421. *
  422. * @ingroup tripal_legacy_phylogeny
  423. */
  424. function tripal_phylogeny_node_update($node) {
  425. switch ($node->type) {
  426. case 'chado_phylotree':
  427. $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
  428. $values = ['phylotree_id' => $phylotree_id];
  429. $phylotree = chado_generate_var('phylotree', $values);
  430. $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
  431. $node->phylotree = $phylotree;
  432. // Now get the title
  433. $node->title = chado_get_node_title($node);
  434. break;
  435. }
  436. }
  437. /**
  438. * Implements [content_type]_chado_node_default_title_format().
  439. *
  440. * Defines a default title format for the Chado Node API to set the titles on
  441. * Chado phylotree nodes based on chado fields.
  442. *
  443. * @ingroup tripal_legacy_phylogeny
  444. */
  445. function chado_phylotree_chado_node_default_title_format() {
  446. return '[phylotree.name]';
  447. }
  448. /**
  449. * Implements hook_chado_node_default_url_format().
  450. *
  451. * Designates a default URL format for phylotree nodes.
  452. */
  453. function chado_phylotree_chado_node_default_url_format() {
  454. return '/phylotree/[phylotree.name]';
  455. }
  456. /**
  457. * Implements hook_insert().
  458. *
  459. * When a new chado_phylotree node is created we also need to add
  460. * information to our chado_phylotree table. This function is called
  461. * on insert of a new node of type 'chado_phylotree' and inserts the
  462. * necessary information.
  463. *
  464. * @ingroup tripal_legacy_phylogeny
  465. */
  466. function chado_phylotree_insert($node) {
  467. global $user;
  468. $node->tree_name = trim($node->tree_name);
  469. $node->description = trim($node->description);
  470. $node->dbxref = trim($node->dbxref);
  471. // if there is a phylotree_id in the $node object then this must
  472. // be a sync (not an insert) so we can skip adding the phylotree as it is
  473. // already there, although we do need to proceed with the rest of the
  474. // insert.
  475. $phylotree_id = NULL;
  476. if (!property_exists($node, 'phylotree_id')) {
  477. $options = [
  478. 'name' => $node->tree_name,
  479. 'description' => $node->description,
  480. 'analysis_id' => $node->analysis_id,
  481. 'leaf_type' => $node->leaf_type,
  482. 'tree_file' => $node->tree_file,
  483. 'format' => 'newick',
  484. 'dbxref' => $node->dbxref,
  485. 'match' => $node->match,
  486. 'name_re' => $node->name_re,
  487. ];
  488. $errors = [];
  489. $warnings = [];
  490. if (tripal_insert_phylotree($options, $errors, $warnings)) {
  491. $phylotree_id = $options['phylotree_id'];
  492. // Add the Tripal variables to this node.
  493. tripal_add_node_variable($node->nid, 'phylotree_name_re', $node->name_re);
  494. tripal_add_node_variable($node->nid, 'phylotree_use_uniquename', $node->match);
  495. tripal_add_node_variable($node->nid, 'phylotree_tree_file', $node->tree_file);
  496. }
  497. else {
  498. drupal_set_message(t('Unable to insert phylotree.'), 'error');
  499. tripal_report_error('tripal_phylogeny', TRIPAL_WARNING,
  500. 'Insert phylotree: Unable to insert phylotree where values: %values',
  501. ['%values' => print_r($options, TRUE)]
  502. );
  503. }
  504. }
  505. else {
  506. $phylotree_id = $node->phylotree_id;
  507. }
  508. // Make sure the entry for this phylotree doesn't already exist in the
  509. // chado_phylotree table if it doesn't exist then we want to add it.
  510. $check_org_id = chado_get_id_from_nid('phylotree', $node->nid);
  511. if (!$check_org_id) {
  512. $record = new stdClass();
  513. $record->nid = $node->nid;
  514. $record->vid = $node->vid;
  515. $record->phylotree_id = $phylotree_id;
  516. drupal_write_record('chado_phylotree', $record);
  517. }
  518. }
  519. /**
  520. * Implements hook_update().
  521. *
  522. * @ingroup tripal_legacy_phylogeny
  523. */
  524. function chado_phylotree_update($node) {
  525. global $user;
  526. $node->tree_name = trim($node->tree_name);
  527. $node->description = trim($node->description);
  528. $node->dbxref = trim($node->dbxref);
  529. // Get the phylotree_id for this node.
  530. $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
  531. $options = [
  532. 'phylotree_id' => $node->phylotree_id,
  533. 'name' => $node->tree_name,
  534. 'description' => $node->description,
  535. 'analysis_id' => $node->analysis_id,
  536. 'leaf_type' => $node->leaf_type,
  537. 'tree_file' => $node->tree_file,
  538. 'format' => 'newick',
  539. 'dbxref' => $node->dbxref,
  540. 'match' => $node->match,
  541. 'name_re' => $node->name_re,
  542. ];
  543. $success = tripal_update_phylotree($phylotree_id, $options);
  544. if (!$success) {
  545. drupal_set_message("Unable to update phylotree.", "error");
  546. tripal_report_error('tripal_phylogeny', TRIPAL_WARNING,
  547. 'Update phylotree: Unable to update phylotree where values: %values',
  548. ['%values' => print_r($options, TRUE)]
  549. );
  550. return;
  551. }
  552. // Remove any variables and then add back the variables from the form.
  553. tripal_delete_node_variables($node->nid);
  554. tripal_add_node_variable($node->nid, 'phylotree_name_re', $node->name_re);
  555. tripal_add_node_variable($node->nid, 'phylotree_use_uniquename', $node->match);
  556. tripal_add_node_variable($node->nid, 'phylotree_tree_file', $node->tree_file);
  557. }
  558. /**
  559. * Implements hook_load().
  560. *
  561. * When a node is requested by the user this function is called to allow us
  562. * to add auxiliary data to the node object.
  563. *
  564. * @ingroup tripal_legacy_phylogeny
  565. */
  566. function chado_phylotree_load($nodes) {
  567. foreach ($nodes as $nid => $node) {
  568. $phylotree_id = chado_get_id_from_nid('phylotree', $nid);
  569. // If the nid does not have a matching record then skip this node.
  570. // this can happen with orphaned nodes.
  571. if (!$phylotree_id) {
  572. continue;
  573. }
  574. // Build the Chado variable for the phylotree.
  575. $values = ['phylotree_id' => $phylotree_id];
  576. $phylotree = chado_generate_var('phylotree', $values);
  577. $nodes[$nid]->phylotree = $phylotree;
  578. // Expand the comment field, chado_generate_var() omits it by default
  579. // because it is a large text field.
  580. $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
  581. // Add non Chado information to the object. These variables are needed
  582. // for the edit/update forms.
  583. $phylotree->tripal_variables = new stdClass;
  584. $variables = tripal_get_node_variables($nid, 'phylotree_name_re');
  585. $phylotree->tripal_variables->phylotree_name_re = count($variables) > 0 ? $variables[0]->value : '';
  586. $variables = tripal_get_node_variables($nid, 'phylotree_use_uniquename');
  587. $phylotree->tripal_variables->phylotree_use_uniquename = count($variables) > 0 ? $variables[0]->value : '';
  588. $variables = tripal_get_node_variables($nid, 'phylotree_tree_file');
  589. $phylotree->tripal_variables->phylotree_tree_file = count($variables) > 0 ? $variables[0]->value : '';
  590. // Set the title for this node.
  591. $node->title = chado_get_node_title($node);
  592. }
  593. }
  594. /**
  595. * Implements hook_delete().
  596. *
  597. * Delete data from drupal and chado databases when a node is deleted
  598. *
  599. * @ingroup tripal_legacy_phylogeny
  600. */
  601. function chado_phylotree_delete(&$node) {
  602. $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
  603. // if we don't have a phylotree id for this node then this isn't a node of
  604. // type chado_phylotree or the entry in the chado_phylotree table was lost.
  605. if (!$phylotree_id) {
  606. return;
  607. }
  608. // Remove data from {chado_phylotree}, {node} and {node_revisions} tables of
  609. // drupal database
  610. $sql_del = "DELETE FROM {chado_phylotree} WHERE nid = :nid AND vid = :vid";
  611. db_query($sql_del, [':nid' => $node->nid, ':vid' => $node->vid]);
  612. $sql_del = "DELETE FROM {node_revision} WHERE nid = :nid AND vid = :vid";
  613. db_query($sql_del, [':nid' => $node->nid, ':vid' => $node->vid]);
  614. $sql_del = "DELETE FROM {node} WHERE nid = :nid AND vid = :vid";
  615. db_query($sql_del, [':nid' => $node->nid, ':vid' => $node->vid]);
  616. // Remove data from phylotree and phylotreeprop tables of chado
  617. // database as well
  618. chado_query("DELETE FROM {phylotree} WHERE phylotree_id = :phylotree_id", [':phylotree_id' => $phylotree_id]);
  619. }
  620. /**
  621. * Implement hook_node_access().
  622. *
  623. * This hook allows node modules to limit access to the node types they define.
  624. *
  625. * @param $node
  626. * The node on which the operation is to be performed, or, if it does not yet
  627. * exist, the type of node to be created
  628. *
  629. * @param $op
  630. * The operation to be performed
  631. *
  632. * @param $account
  633. * A user object representing the user for whom the operation is to be
  634. * performed
  635. *
  636. * @return
  637. * If the permission for the specified operation is not set then return FALSE.
  638. * If the permission is set then return NULL as this allows other modules to
  639. * disable access. The only exception is when the $op == 'create'. We will
  640. * always return TRUE if the permission is set.
  641. *
  642. * @ingroup tripal_legacy_phylogeny
  643. */
  644. function chado_phylotree_node_access($node, $op, $account) {
  645. $node_type = $node;
  646. if (is_object($node)) {
  647. $node_type = $node->type;
  648. }
  649. if ($node_type == 'chado_phylotree') {
  650. if ($op == 'create') {
  651. if (!user_access('create chado_phylotree content', $account)) {
  652. return NODE_ACCESS_DENY;
  653. }
  654. return NODE_ACCESS_ALLOW;
  655. }
  656. if ($op == 'update') {
  657. if (!user_access('edit chado_phylotree content', $account)) {
  658. return NODE_ACCESS_DENY;
  659. }
  660. }
  661. if ($op == 'delete') {
  662. if (!user_access('delete chado_phylotree content', $account)) {
  663. return NODE_ACCESS_DENY;
  664. }
  665. }
  666. if ($op == 'view') {
  667. if (!user_access('access chado_phylotree content', $account)) {
  668. return NODE_ACCESS_DENY;
  669. }
  670. }
  671. return NODE_ACCESS_IGNORE;
  672. }
  673. }
  674. /**
  675. * Phylotree feature summary.
  676. *
  677. * Get an array of feature counts by organism. key = organism
  678. * abbreviation. value = number of features for this phylotree having
  679. * this organism.
  680. *
  681. * @param int phylotree_id
  682. *
  683. * @return array
  684. * @ingroup tripal_legacy_phylogeny
  685. */
  686. function phylotree_feature_summary($phylotree_id) {
  687. $sql = "
  688. SELECT o.abbreviation, COUNT(o.organism_id) AS count
  689. FROM {phylonode} n
  690. LEFT OUTER JOIN {feature} f ON n.feature_id = f.feature_id
  691. LEFT OUTER JOIN {organism} o ON f.organism_id = o.organism_id
  692. WHERE n.phylotree_id = :phylotree_id
  693. AND n.feature_id IS NOT NULL
  694. GROUP BY o.organism_id
  695. ";
  696. $args = [':phylotree_id' => $phylotree_id];
  697. $result = chado_query($sql, $args);
  698. $summary = [];
  699. foreach ($result as $r) {
  700. $summary[$r->abbreviation] = $r->count;
  701. }
  702. return $summary;
  703. }