blast_ui.node.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <?php
  2. /**
  3. * @file
  4. * Contains all functions for creating the blastdb node type
  5. */
  6. /**
  7. * Implements hook_node_info().
  8. */
  9. function blast_ui_node_info() {
  10. return array(
  11. 'blastdb' => array(
  12. 'name' => t('Blast Database'),
  13. 'base' => 'blastdb',
  14. 'description' => t('Registers a BLAST Database for use with the BLAST UI.'),
  15. ),
  16. );
  17. }
  18. /**
  19. * Implements hook_node_access().
  20. */
  21. function blastdb_node_access($node, $op, $account) {
  22. $node_type = $node;
  23. if (is_object($node)) {
  24. $node_type = $node->type;
  25. }
  26. if($node_type == 'blastdb') {
  27. if ($op == 'create') {
  28. if (!user_access('create Blast Database', $account)) {
  29. return NODE_ACCESS_DENY;
  30. }
  31. return NODE_ACCESS_ALLOW;
  32. }
  33. if ($op == 'update') {
  34. if (!user_access('edit Blast Database', $account)) {
  35. return NODE_ACCESS_DENY;
  36. }
  37. }
  38. if ($op == 'delete') {
  39. if (!user_access('delete Blast Database', $account)) {
  40. return NODE_ACCESS_DENY;
  41. }
  42. }
  43. if ($op == 'view') {
  44. if (!user_access('access Blast Database', $account)) {
  45. return NODE_ACCESS_DENY;
  46. }
  47. }
  48. return NODE_ACCESS_IGNORE;
  49. }
  50. }
  51. /**
  52. * Form constructor for the blastdb node
  53. *
  54. * @see blastdb_insert()
  55. * @see blastdb_update()
  56. * @see blastdb_delete()
  57. * @see blastdb_load()
  58. */
  59. function blastdb_form($node, &$form_state) {
  60. $form = array();
  61. $form['#validate'] = array('blastdb_form_validate');
  62. $form['#attached']['css'] = array(
  63. drupal_get_path('module', 'blast_ui') . '/theme/css/form.css',
  64. );
  65. $form['core'] = array(
  66. '#type' => 'fieldset',
  67. '#title' => 'General'
  68. );
  69. $form['core']['db_name']= array(
  70. '#type' => 'textfield',
  71. '#title' => t('Human-readable Name for Blast database'),
  72. '#required' => TRUE,
  73. '#default_value' => isset($node->db_name) ? $node->db_name : '',
  74. );
  75. $form['core']['db_path']= array(
  76. '#type' => 'textfield',
  77. '#title' => t('File Prefix including Full Path'),
  78. '#description' => t('The full path to your blast database including the file name but not the file type suffix. For example, /var/www/website/sites/default/files/myblastdb'),
  79. '#required' => TRUE,
  80. '#default_value' => isset($node->db_path) ? $node->db_path : '',
  81. );
  82. $form['core']['db_dbtype'] = array(
  83. '#type' => 'radios',
  84. '#title' => t('Type of the blast database'),
  85. '#options' => array(
  86. 'nucleotide' => t('Nucleotide'),
  87. 'protein' => t('Protein'),
  88. ),
  89. '#required' => TRUE,
  90. '#default_value' => isset($node->db_dbtype) ? $node->db_dbtype : 'n',
  91. );
  92. $form['dbxref'] = array(
  93. '#type' => 'fieldset',
  94. '#title' => 'Link-outs',
  95. '#description' => 'These settings will be used to <em>transform the hit name into a
  96. link to additional information</em>.',
  97. '#prefix' => '<div id="link-outs">',
  98. '#suffix' => '</div>',
  99. );
  100. $types = module_invoke_all('blast_linkout_info');
  101. $options = array();
  102. foreach ($types as $machine_name => $details) {
  103. $options[$machine_name] = (isset($details['name'])) ? $details['name'] : $machine_name;
  104. }
  105. $linkout_type = (isset($node->linkout->type)) ? $node->linkout->type : 'none';
  106. $linkout_type = (isset($form_state['values'])) ? $form_state['values']['dbxref_linkout_type'] : $linkout_type;
  107. $form['dbxref']['dbxref_linkout_type'] = array(
  108. '#type' => 'radios',
  109. '#title' => 'Link-out Type',
  110. '#description' => 'This determines how the URL to be linked to is formed. <strong>Make
  111. sure the database chosen supports this type of link</strong> (ie: the database
  112. should point to a GBrowse instance if you choose GBrowse here).',
  113. '#options' => $options,
  114. '#default_value' => $linkout_type,
  115. );
  116. // Add information about each format to the description.
  117. if ($linkout_type) {
  118. $form['dbxref']['dbxref_linkout_type']['#description'] .= '
  119. <p class="blastdb-extra-info"><strong>'.$types[$linkout_type]['name'].'</strong>: '.$types[$linkout_type]['help'].'</p>';
  120. }
  121. if ($types[$linkout_type]['require_regex']) {
  122. $regex = array(
  123. 'default' => array(
  124. 'title' => 'Generic',
  125. 'help' => 'A single word followed by a free-text definition. '
  126. . 'The first word contains only alphanumeric characters and optionally '
  127. . 'underscores and will be used as the ID of the sequence.'
  128. ),
  129. 'genbank' => array(
  130. 'title' => 'NCBI GenBank',
  131. 'help' => 'Follows the same format as the first option '
  132. . 'except that the first "word" is of the following form: '
  133. . 'gb|accession|locus. The accession will be used as the ID of the sequence.'
  134. ),
  135. 'embl' => array(
  136. 'title' => 'EMBL Data Library',
  137. 'help' => 'Follows the same format as the first option '
  138. . 'except that the first "word" is of the following form: '
  139. . 'emb|accession|locus. The accession will be used as the ID of the sequence.'
  140. ),
  141. 'swissprot' => array(
  142. 'title' => 'SWISS-PROT',
  143. 'help' => 'Follows the same format as the first option '
  144. . 'except that the first "word" is of the following form: '
  145. . 'sp|accession|entry name. The accession will be used as the ID of the sequence.'
  146. ),
  147. 'custom' => array(
  148. 'title' => 'Custom Format',
  149. 'help' => 'Allows you to use a regular expression (define one below) to '
  150. . 'extract a specifc portion of the FASTA header to be used as the ID.'
  151. ),
  152. );
  153. $regex_type = (isset($node->linkout->regex_type)) ? $node->linkout->regex_type : 'default';
  154. $regex_type = (isset($form_state['values'])) ? $form_state['values']['dbxref_id_type'] : $regex_type;
  155. $form['dbxref']['dbxref_id_type'] = array(
  156. '#type' => 'radios',
  157. '#title' => 'FASTA header format',
  158. '#description' => 'Choose the format that matches the format of the FASTA '
  159. . 'headers in this BLAST database or choose custom to define your own '
  160. . 'using regular expressions. This ID will be used to create the URL for the link-out.',
  161. '#options' => array(
  162. 'default' => '<span title="' . $regex['default']['help'] . '">' . $regex['default']['title'] . '</span>',
  163. 'genbank' => '<span title="' . $regex['genbank']['help'] . '">' . $regex['genbank']['title'] . '</span>',
  164. 'embl' => '<span title="' . $regex['embl']['help'] . '">' . $regex['embl']['title'] . '</span>',
  165. 'swissprot' => '<span title="' . $regex['swissprot']['help'] . '">' . $regex['swissprot']['title'] . '</span>',
  166. 'custom' => '<span title="' . $regex['custom']['help'] . '">' . $regex['custom']['title'] . '</span>',
  167. ),
  168. '#default_value' => $regex_type,
  169. '#required' => TRUE,
  170. '#ajax' => array(
  171. 'callback' => 'ajax_blast_ui_node_linkout_custom_callback',
  172. 'wrapper' => 'link-outs',
  173. )
  174. );
  175. // Add information about each format to the description.
  176. if ($regex_type) {
  177. $form['dbxref']['dbxref_id_type']['#description'] .= '
  178. <p class="blastdb-extra-info"><strong>'.$regex[$regex_type]['title'].'</strong>: '.$regex[$regex_type]['help'].'</p>';
  179. }
  180. if ($regex_type == 'custom') {
  181. $form['dbxref']['regex'] = array(
  182. '#type' => 'textfield',
  183. '#title' => 'Regular Expression',
  184. '#description' => t('A PHP Regular expression with curved brackets '
  185. . 'surrounding the ID that should be used in the URL to provide a link-'
  186. . 'out to additional information. See <a href="@url" target="_blank">PHP.net Regular '
  187. . 'Expression Documentation</a> for more information. <strong>Be sure '
  188. . 'to include the opening and closing slashes</strong>. This is only '
  189. . 'available if custom was choosen for the FASTA header format above.',
  190. array('@url' => 'http://php.net/manual/en/reference.pcre.pattern.syntax.php')),
  191. '#required' => TRUE,
  192. '#default_value' => (isset($node->linkout->regex)) ? $node->linkout->regex : ''
  193. );
  194. }
  195. }
  196. if ($types[$linkout_type]['require_db']) {
  197. $db_options = tripal_get_db_select_options();
  198. $db_options[0] = '';
  199. asort($db_options);
  200. $form['dbxref']['db_id'] = array(
  201. '#type' => 'select',
  202. '#title' => 'External Database',
  203. '#description' => 'The external database you would like to link-out to. '
  204. . 'Note that this list includes all Tripal Databases and if the database '
  205. . 'you would like to link-out to is not included you can add it through '
  206. . l('Administration > Tripal > Chado Modules > Databases','admin/tripal/chado/tripal_db/add', array('attributes' => array('target' => '_blank')))
  207. . '.',
  208. '#options' => $db_options,
  209. '#required' => TRUE,
  210. '#default_value' => (isset($node->linkout->db_id->db_id)) ? $node->linkout->db_id->db_id : 0
  211. );
  212. }
  213. // CViTjs settings, if enabled
  214. if (variable_get('blast_ui_cvitjs_enabled', false)) {
  215. $form['cvitjs'] = array(
  216. '#type' => 'fieldset',
  217. '#title' => 'Whole Genome Visualization',
  218. '#description' => 'Settings for the display of BLAST hits on an entire genome assembly using CViTjs.',
  219. '#prefix' => '<div id="cvitjs-settings">',
  220. '#suffix' => '</div>',
  221. );
  222. $form['cvitjs']['cvitjs_enabled'] = array(
  223. '#type' => 'checkbox',
  224. '#title' => t('Show BLAST hits on the genome in the results page.'),
  225. '#description' => t('Uses CViTjs to display BLAST hits on the entire genome'),
  226. '#default_value' => (isset($node->cvitjs_enabled)) ? $node->cvitjs_enabled : false,
  227. // '#ajax' => array(
  228. // 'callback' => 'ajax_blast_ui_node_cvitjs_custom_callback',
  229. // 'wrapper' => 'cvitjs-settings',
  230. // )
  231. );
  232. $form['cvitjs']['cvitjs_enabled']['#description'] .= '
  233. <p class="blastdb-extra-info">Target Genome Configuration should be under <strong>[data.'.$node->db_name.']</strong> in the main cvit.conf.</p>';
  234. if (isset($form_state['values'])) {
  235. $cvitjs_enabled = $form_state['values']['cvitjs_enabled'];
  236. }
  237. else if (isset($node->cvitjs_enabled)) {
  238. $cvitjs_enabled = $node->cvitjs_enabled;
  239. }
  240. else {
  241. $cvitjs_enabled = false;
  242. }
  243. }
  244. return $form;
  245. }
  246. function blastdb_form_validate($form, $form_state) {
  247. if (isset($form_state['values']['regex']) AND !empty($form_state['values']['regex'])) {
  248. // Check that any supplied regex includes //.
  249. if (!preg_match('/\/.*\//', $form_state['values']['regex'])) {
  250. form_set_error('regex', 'Regular Expressions require opening and closing slashes to delinate them. For example, <em>/^(\s+) .*/</em>');
  251. }
  252. // Check that the supplied regex is valid.
  253. elseif (@preg_match($form_state['values']['regex'], NULL) === FALSE) {
  254. form_set_error('regex', 'Regular Expression not valid. See '
  255. . '<a href="http://php.net/manual/en/reference.pcre.pattern.syntax.php" target="_blank">PHP.net Regular '
  256. . 'Expression Documentation</a> for more information.');
  257. }
  258. }
  259. // Check that the supplied db actually contains a URL prefix.
  260. if (isset($form_state['values']['db_id'])) {
  261. $db = tripal_get_db(array('db_id' => $form_state['values']['db_id']));
  262. if (empty($db)) {
  263. form_set_error('db_id', 'The database chosen no longer exists.');
  264. }
  265. if (empty($db->urlprefix)) {
  266. form_set_error('db_id', 'The database choosen does not have a URL prefix '
  267. . 'listed which means a link-out could not be created for BLAST hits. '
  268. . 'Please edit the database '
  269. . l('here', 'admin/tripal/chado/tripal_db/edit/' . $db->db_id,
  270. array('attributes' => array('target' => '_blank')))
  271. . ' to include a URL prefix before continuing'
  272. );
  273. }
  274. }
  275. }
  276. /**
  277. * Implements hook_insert().
  278. */
  279. function blastdb_insert($node) {
  280. // Handle Link-out Rules.
  281. $regex = '';
  282. if (isset($node->dbxref_id_type)) {
  283. if ($node->dbxref_id_type == 'custom') {
  284. $regex = $node->regex;
  285. }
  286. else {
  287. $regex = $node->dbxref_id_type;
  288. }
  289. }
  290. $db_id = 0;
  291. if (isset($node->db_id)) {
  292. $db_id = $node->db_id;
  293. }
  294. if (!$node->dbxref_linkout_type) {
  295. $node->dbxref_linkout_type = 'none';
  296. }
  297. if (!isset($node->cvitjs_enabled)) {
  298. $node->cvitjs_enabled = 0;
  299. }
  300. // Actually insert the record.
  301. db_insert('blastdb')->fields(array(
  302. 'nid' => $node->nid,
  303. 'name' => $node->db_name,
  304. 'path' => $node->db_path,
  305. 'dbtype' => $node->db_dbtype,
  306. 'dbxref_id_regex' => $regex,
  307. 'dbxref_db_id' => $db_id,
  308. 'dbxref_linkout_type' => $node->dbxref_linkout_type,
  309. 'cvitjs_enabled' => $node->cvitjs_enabled,
  310. ))->execute();
  311. }
  312. /**
  313. * Implements hook_node_insert().
  314. * This function acts on ALL NODES
  315. */
  316. function blast_ui_node_insert($node) {
  317. if ($node->type == 'blastdb') {
  318. $node->title = $node->db_name;
  319. }
  320. }
  321. /**
  322. * Implements hook_update().
  323. */
  324. function blastdb_update($node) {
  325. // Handle Link-out Rules.
  326. $regex = '';
  327. if (isset($node->dbxref_id_type)) {
  328. if ($node->dbxref_id_type == 'custom') {
  329. $regex = $node->regex;
  330. }
  331. else {
  332. $regex = $node->dbxref_id_type;
  333. }
  334. }
  335. $db_id = 0;
  336. if (isset($node->db_id)) {
  337. $db_id = $node->db_id;
  338. }
  339. if (!$node->cvitjs_enabled) {
  340. $node->cvitjs_enabled = 0;
  341. }
  342. if (!$node->dbxref_linkout_type) {
  343. $node->dbxref_linkout_type = 'none';
  344. }
  345. // Update the record.
  346. db_update('blastdb')->fields(array(
  347. 'name' => $node->db_name,
  348. 'path' => $node->db_path,
  349. 'dbtype' => $node->db_dbtype,
  350. 'dbxref_id_regex' => $regex,
  351. 'dbxref_db_id' => $db_id,
  352. 'dbxref_linkout_type' => $node->dbxref_linkout_type,
  353. 'cvitjs_enabled' => $node->cvitjs_enabled,
  354. ))->condition('nid', $node->nid)->execute();
  355. }
  356. /**
  357. * Implements hook_node_update().
  358. * This function acts on ALL NODES
  359. */
  360. function blast_ui_node_update($node) {
  361. if ($node->type == 'blastdb') {
  362. $node->title = $node->db_name;
  363. }
  364. }
  365. /**
  366. * Implements hook_delete().
  367. */
  368. function blastdb_delete($node) {
  369. db_delete('blastdb')->condition('nid',$node->nid)->execute();
  370. }
  371. /**
  372. * Implements hook_load().
  373. */
  374. function blastdb_load($nodes) {
  375. $sql = "
  376. SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id,
  377. dbxref_linkout_type, cvitjs_enabled
  378. FROM {blastdb}
  379. WHERE nid IN (:nids)";
  380. $result = db_query($sql, array(':nids' => array_keys($nodes)));
  381. foreach ($result as $record) {
  382. // Add basic blast node information.
  383. $nodes[$record->nid]->db_name = $record->name;
  384. $nodes[$record->nid]->db_path = $record->path;
  385. $nodes[$record->nid]->title = $record->name;
  386. $nodes[$record->nid]->db_dbtype = $record->dbtype;
  387. // CViTjs status
  388. $nodes[$record->nid]->cvitjs_enabled = $record->cvitjs_enabled;
  389. // Determine the type of link-out chosen.
  390. $types = module_invoke_all('blast_linkout_info');
  391. $type = NULL;
  392. if (isset($types[ $record->dbxref_linkout_type ])) {
  393. $type = $types[ $record->dbxref_linkout_type ];
  394. }
  395. else {
  396. tripal_report_error(
  397. 'blast_ui',
  398. TRIPAL_ERROR,
  399. 'Unable to find details on the type of link-out choosen (%type). Have you defined hook_blast_linkout_info()? Make sure to clear the cache once you do so.',
  400. array('%type' => $record->dbxref_linkout_type)
  401. );
  402. }
  403. // Now determine if this node meets the requirements for the linkout
  404. // chosen before adding linkout information.
  405. $add_linkout = TRUE;
  406. if (!$type OR $record->dbxref_linkout_type == 'none') {
  407. $add_linkout = FALSE;
  408. }
  409. else {
  410. if ($type['require_regex'] AND !$record->dbxref_id_regex) {
  411. $add_linkout = FALSE;
  412. }
  413. if ($type['require_db'] AND !$record->dbxref_db_id) {
  414. $add_linkout = FALSE;
  415. }
  416. }
  417. // Add information related to link-outs to the node.
  418. if ($add_linkout) {
  419. $nodes[$record->nid]->linkout = new stdClass();
  420. // If the link-out type requires a regex then provide one.
  421. if ($type['require_regex']) {
  422. if (preg_match('/\/.*\//', $record->dbxref_id_regex)) {
  423. $nodes[$record->nid]->linkout->regex_type = 'custom';
  424. $nodes[$record->nid]->linkout->regex = $record->dbxref_id_regex;
  425. }
  426. else {
  427. $nodes[$record->nid]->linkout->regex_type = $record->dbxref_id_regex;
  428. $nodes[$record->nid]->linkout->regex = get_blastdb_linkout_regex($nodes[$record->nid]);
  429. }
  430. }
  431. else {
  432. $nodes[$record->nid]->linkout->regex_type = 'none';
  433. $nodes[$record->nid]->linkout->regex = NULL;
  434. }
  435. // If the link-out type requires a db then provide one.
  436. if (isset($type['require_db'])) {
  437. $nodes[$record->nid]->linkout->db_id = tripal_get_db(array('db_id' => $record->dbxref_db_id));
  438. }
  439. else {
  440. $nodes[$record->nid]->linkout->db_id = NULL;
  441. }
  442. $nodes[$record->nid]->linkout->none = FALSE;
  443. // Support complex link-outs.
  444. $nodes[$record->nid]->linkout->type = $record->dbxref_linkout_type;
  445. $nodes[$record->nid]->linkout->url_function = $type['process function'];
  446. }
  447. // If there is no linkout then provide some defaults.
  448. else {
  449. $nodes[$record->nid]->linkout = new stdClass();
  450. $nodes[$record->nid]->linkout->regex = '';
  451. $nodes[$record->nid]->linkout->db_id = 0;
  452. $nodes[$record->nid]->linkout->none = TRUE;
  453. }
  454. }
  455. }
  456. /**
  457. * AJAX Callback: Update Node Link-out Regex Textfield.
  458. *
  459. * On BlastDB node form the Link-out (dbxref) options allow for settings of a
  460. * custom regex which should only be enabled when "Custom" is selected. This
  461. * callback refreshes the regex textfield so it can change (ie: become enabled)
  462. * when someone selects custom.
  463. */
  464. function ajax_blast_ui_node_linkout_custom_callback($form, $form_state) {
  465. return $form['dbxref'];
  466. }