tripal_pub.pub_search.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <?php
  2. /**
  3. * @file
  4. *
  5. * Functions responsible for creating the publication search form that
  6. * allows a user of the site to search for publications that are currently
  7. * in Chado.
  8. */
  9. /**
  10. * The page that contains the publication search form and the results for the search
  11. *
  12. * @ingroup tripal_pub
  13. */
  14. function tripal_pub_search_page() {
  15. // This line may not be required, but on some sites the $_SESSION
  16. // variable wasn't being set for anonymous users. This line solves that
  17. // problem
  18. drupal_session_start();
  19. $limit = 25;
  20. // generate the search form
  21. $form = drupal_get_form('tripal_pub_search_form');
  22. $output = drupal_render($form);
  23. // retrieve any results
  24. if (array_key_exists('tripal_pub_search_form', $_SESSION) and
  25. $_SESSION['tripal_pub_search_form']['perform_search']) {
  26. $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'];
  27. $from_year = $_SESSION['tripal_pub_search_form']['from_year'];
  28. $to_year = $_SESSION['tripal_pub_search_form']['to_year'];
  29. $search_array = array();
  30. $search_array['num_criteria'] = $num_criteria;
  31. $search_array['from_year'] = $from_year;
  32. $search_array['to_year'] = $to_year;
  33. for ($i = 0; $i <= $num_criteria; $i++) {
  34. $search_array['criteria'][$i]['search_terms'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'];
  35. $search_array['criteria'][$i]['scope'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope'];
  36. $search_array['criteria'][$i]['mode'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode'];
  37. $search_array['criteria'][$i]['operation'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation'];
  38. }
  39. // get the list of publications from the remote database using the search criteria.
  40. $page = isset($_GET['page']) ? $_GET['page'] : '0';
  41. $offset = $page * $limit;
  42. $total_records = 0;
  43. $pubs = tripal_search_publications($search_array, $offset, $limit, $total_records);
  44. pager_default_initialize($total_records, $limit, 0);
  45. // iterate through the results and construct the table displaying the publications
  46. $rows = array();
  47. $i = $page * $limit + 1;
  48. foreach ($pubs as $pub) {
  49. // get the citation for this publication
  50. $values = array(
  51. 'pub_id' => $pub->pub_id,
  52. 'type_id' => array(
  53. 'name' => 'Citation',
  54. ),
  55. );
  56. $citation_rec = chado_generate_var('pubprop', $values);
  57. $citation_rec = chado_expand_var($citation_rec, 'field', 'pubprop.value');
  58. // if we have the citation then use it, otherwise, just use the title
  59. $title = htmlspecialchars($pub->title);
  60. $result = $title;
  61. if ($pub->nid) {
  62. $result = l($title ,'node/' . $pub->nid, array('attributes' => array('target' => '_blank')));
  63. }
  64. if ($citation_rec->value) {
  65. $citation = htmlspecialchars($citation_rec->value);
  66. $result .= '<br>' . $citation;
  67. }
  68. $rows[] = array(
  69. number_format($i) . ".",
  70. $pub->pyear,
  71. $result
  72. );
  73. $i++;
  74. }
  75. if (count($rows) == 0) {
  76. $rows[] = array(
  77. array(
  78. 'data' => 'No results found',
  79. 'colspan' => 3
  80. )
  81. );
  82. }
  83. $headers = array('', 'Year', 'Publication');
  84. $table = array(
  85. 'header' => $headers,
  86. 'rows' => $rows,
  87. 'attributes' => array(
  88. 'id' => 'tripal-pub-search-results-table',
  89. 'border' => '0',
  90. 'class' => array('tripal-data-table')
  91. ),
  92. 'sticky' => TRUE,
  93. 'caption' => '',
  94. 'colgroups' => array(),
  95. 'empty' => '',
  96. );
  97. $results = theme_table($table);
  98. // generate the pager
  99. $pager = array(
  100. 'tags' => array(),
  101. 'element' => 0,
  102. 'parameters' => array(),
  103. 'quantity' => $limit,
  104. );
  105. $pager = theme_pager($pager);
  106. // join all to form the results
  107. $output .= "<p><b>Found " . number_format($total_records) .
  108. " Results</b></br>" . $results . $pager;
  109. }
  110. return $output;
  111. }
  112. /**
  113. * Provides the form to search pubmed
  114. *
  115. * @ingroup tripal_pub
  116. */
  117. function tripal_pub_search_form($form, &$form_state) {
  118. // Default values can come in the following ways:
  119. //
  120. // 1) as elements of the $pub_importer object. This occurs when editing an existing importer
  121. // 2) in the $form_state['values'] array which occurs on a failed validation or
  122. // ajax callbacks from non submit form elements
  123. // 3) in the $form_state['input'] array which occurs on ajax callbacks from submit
  124. // form elements and the form is being rebuilt
  125. //
  126. // Set the default values. If the pub_import_id isn't already defined by the form values
  127. // and one is provided then look it up in the database
  128. $criteria = NULL;
  129. $num_criteria = 2;
  130. $from_year = '';
  131. $to_year = '';
  132. // if the session has variables then use those. This should only happen when
  133. // the 'Test Criteria' button is clicked.
  134. if (array_key_exists('storage', $form_state)) {
  135. $num_criteria = $form_state['storage']['num_criteria'];
  136. }
  137. if (array_key_exists('tripal_pub_search_form', $_SESSION)) {
  138. $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'] ? $_SESSION['tripal_pub_search_form']['num_criteria'] : $num_criteria;
  139. $from_year = $_SESSION['tripal_pub_search_form']['from_year'] ? $_SESSION['tripal_pub_search_form']['from_year'] : '';
  140. $to_year = $_SESSION['tripal_pub_search_form']['to_year'] ? $_SESSION['tripal_pub_search_form']['to_year'] : '';
  141. }
  142. if (array_key_exists('values', $form_state)) {
  143. $from_year = $form_state['values']['from_year'] ? $form_state['values']['from_year'] : $from_year;
  144. $to_year = $form_state['values']['to_year'] ? $form_state['values']['to_year'] : $to_year;
  145. }
  146. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  147. $from_year = $form_state['input']['from_year'] ? $form_state['input']['from_year'] : $from_year;
  148. $to_year = $form_state['input']['to_year'] ? $form_state['input']['to_year'] : $to_year;
  149. }
  150. if (array_key_exists('triggering_element', $form_state) and
  151. $form_state['triggering_element']['#name'] == 'add') {
  152. $num_criteria++;
  153. }
  154. if (array_key_exists('triggering_element', $form_state) and
  155. $form_state['triggering_element']['#name'] == 'remove') {
  156. $num_criteria--;
  157. }
  158. $form_state['storage']['num_criteria'] = $num_criteria;
  159. $form['admin-instructions'] = array(
  160. '#markup' => tripal_set_message(
  161. t('Administrators, you can select the fields with which a user can use to search, by checking the desired fields on the ' .
  162. l('Publication Module Settings Page', 'admin/tripal/legacy/tripal_pub/configuration', array('attributes' => array('target' => '_blank'))) . '
  163. in the section titled "Search Options". The selected fields will appear in the dropdowns below.'),
  164. TRIPAL_INFO,
  165. array('return_html' => 1)),
  166. );
  167. $form['instructions'] = array(
  168. '#markup' => t('To search for publications enter keywords in the text boxes below.
  169. You can limit your search by selecting the field in the dropdown box. Click the
  170. add and remove buttons to add additional fields for searching. '),
  171. );
  172. // get publication properties list
  173. $properties = array();
  174. $properties[] = 'Any Field';
  175. $sql = "
  176. SELECT DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
  177. FROM {cvtermpath} CVTP
  178. INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
  179. INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
  180. INNER JOIN {cv} ON CVTO.cv_id = CV.cv_id
  181. WHERE CV.name = 'tripal_pub' and
  182. (CVTO.name = 'Publication Details' or CVTS.name = 'Publication Type') and
  183. NOT CVTS.is_obsolete = 1
  184. ORDER BY CVTS.name ASC
  185. ";
  186. $allowed_fields = variable_get('tripal_pub_allowed_search_fields', array());
  187. $prop_types = chado_query($sql);
  188. foreach ($prop_types as $prop) {
  189. if(array_key_exists($prop->cvterm_id, $allowed_fields) and $allowed_fields[$prop->cvterm_id] > 0) {
  190. $properties[$prop->cvterm_id] = $prop->name;
  191. }
  192. }
  193. for($i = 1; $i <= $num_criteria; $i++) {
  194. $search_terms = '';
  195. $scope = '';
  196. $operation = '';
  197. $mode = '';
  198. // first populate defaults using any values in the SESSION variable
  199. if (array_key_exists('tripal_pub_search_form', $_SESSION)) {
  200. $search_terms = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] : $search_terms;
  201. $scope = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope'] : $scope;
  202. $mode = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode'] : $mode;
  203. $operation = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation'] : $operation;
  204. }
  205. if (array_key_exists('values', $form_state)) {
  206. $search_terms = array_key_exists("search_terms-$i", $form_state['values']) ? $form_state['values']["search_terms-$i"] : $search_terms;
  207. $scope = array_key_exists("scope-$i", $form_state['values']) ? $form_state['values']["scope-$i"] : $scope;
  208. $mode = array_key_exists("mode-$i", $form_state['values']) ? $form_state['values']["mode-$i"] : $mode;
  209. $operation = array_key_exists("operation-$i", $form_state['values']) ? $form_state['values']["operation-$i"] : $operation;
  210. }
  211. if (array_key_exists('input', $form_state)) {
  212. $search_terms = array_key_exists("search_terms-$i", $form_state['input']) ? $form_state['input']["search_terms-$i"] : $search_terms;
  213. $scope = array_key_exists("scope-$i", $form_state['input']) ? $form_state['input']["scope-$i"] : $scope;
  214. $mode = array_key_exists("mode-$i", $form_state['input']) ? $form_state['input']["mode-$i"] : $mode;
  215. $operation = array_key_exists("operation-$i", $form_state['input']) ? $form_state['input']["operation-$i"] : $operation;
  216. }
  217. // default to searching the title and abstract
  218. if (!$scope) {
  219. $scope = 'abstract';
  220. }
  221. $form['criteria'][$i]["search_terms-$i"] = array(
  222. '#type' => 'textfield',
  223. '#default_value' => $search_terms,
  224. '#required' => FALSE,
  225. );
  226. $form['criteria'][$i]["scope-$i"] = array(
  227. '#type' => 'select',
  228. '#options' => $properties,
  229. '#default_value' => $scope,
  230. '#attributes' => array('class' => array('tripal-pub-search-form-scope-select')),
  231. );
  232. /*
  233. $form['criteria'][$i]["mode-$i"] = array(
  234. '#type' => 'select',
  235. '#options' => array(
  236. 'Contains' => 'Contains',
  237. 'Starts With' => 'Starts With',
  238. 'Ends With' => 'Ends With',
  239. 'Exactly' => 'Exactly'),
  240. '#default_value' => $mode,
  241. );*/
  242. if ($i > 1) {
  243. $form['criteria'][$i]["operation-$i"] = array(
  244. '#type' => 'select',
  245. '#options' => array(
  246. 'AND' => 'AND',
  247. 'OR' => 'OR',
  248. 'NOT' => 'NOT'),
  249. '#default_value' => $operation,
  250. );
  251. }
  252. if ($i == $num_criteria) {
  253. if($i > 1) {
  254. $form['criteria'][$i]["remove-$i"] = array(
  255. '#type' => 'button',
  256. '#name' => 'remove',
  257. '#value' => t('Remove'),
  258. '#ajax' => array(
  259. 'callback' => "tripal_pubs_search_form_ajax_update",
  260. 'wrapper' => 'tripal-pub-search-form-criteria',
  261. 'effect' => 'fade',
  262. 'method' => 'replace',
  263. 'prevent' => 'click'
  264. ),
  265. // When this button is clicked, the form will be validated and submitted.
  266. // Therefore, we set custom submit and validate functions to override the
  267. // default form submit. In the validate function we set the form_state
  268. // to rebuild the form so the submit function never actually gets called,
  269. // but we need it or Drupal will run the default validate anyway.
  270. // we also set #limit_validation_errors to empty so fields that
  271. // are required that don't have values won't generate warnings.
  272. '#submit' => array('tripal_pub_search_form_ajax_button_submit'),
  273. '#validate' => array('tripal_pub_search_form_ajax_button_validate'),
  274. '#limit_validation_errors' => array(),
  275. );
  276. }
  277. $form['criteria'][$i]["add-$i"] = array(
  278. '#type' => 'button',
  279. '#name' => 'add',
  280. '#value' => t('Add'),
  281. '#ajax' => array(
  282. 'callback' => "tripal_pubs_search_form_ajax_update",
  283. 'wrapper' => 'tripal-pub-search-form-criteria',
  284. 'effect' => 'fade',
  285. 'method' => 'replace',
  286. 'prevent' => 'click'
  287. ),
  288. // When this button is clicked, the form will be validated and submitted.
  289. // Therefore, we set custom submit and validate functions to override the
  290. // default form submit. In the validate function we set the form_state
  291. // to rebuild the form so the submit function never actually gets called,
  292. // but we need it or Drupal will run the default validate anyway.
  293. // we also set #limit_validation_errors to empty so fields that
  294. // are required that don't have values won't generate warnings.
  295. '#submit' => array('tripal_pub_search_form_ajax_button_submit'),
  296. '#validate' => array('tripal_pub_search_form_ajax_button_validate'),
  297. '#limit_validation_errors' => array(),
  298. );
  299. }
  300. }
  301. $form['criteria']["date"] = array(
  302. '#type' => 'select',
  303. '#options' => array('Years' => 'Years'),
  304. '#attributes' => array('class' => array('tripal-pub-search-form-scope-select')),
  305. );
  306. $form['criteria']["from_year"] = array(
  307. '#type' => 'textfield',
  308. '#default_value' => $from_year,
  309. '#required' => FALSE,
  310. '#title' => 'from',
  311. '#size' => 4,
  312. '#maxlength' => 4,
  313. );
  314. $form['criteria']["to_year"] = array(
  315. '#type' => 'textfield',
  316. '#default_value' => $to_year,
  317. '#required' => FALSE,
  318. '#title' => 'to',
  319. '#size' => 4,
  320. '#maxlength' => 4,
  321. );
  322. $form['search'] = array(
  323. '#type' => 'submit',
  324. '#value' => t('Search'),
  325. );
  326. $form['reset'] = array(
  327. '#type' => 'submit',
  328. '#value' => t('Reset'),
  329. );
  330. $form['criteria']['#theme'] = 'tripal_pub_search_setup_form_elements';
  331. return $form;
  332. }
  333. /**
  334. * This function is used to rebuild the form if an ajax call is made vai a button.
  335. * The button causes the form to be submitted. We don't want this so we override
  336. * the validate and submit routines on the form button. Therefore, this function
  337. * only needs to tell Drupal to rebuild the form
  338. *
  339. * @ingroup tripal_pub
  340. */
  341. function tripal_pub_search_form_ajax_button_submit() {
  342. $form_state['rebuild'] = TRUE;
  343. }
  344. /**
  345. * This function is just a dummy to override the default form submit on ajax calls for buttons
  346. *
  347. * @ingroup tripal_pub
  348. */
  349. function tripal_pub_search_form_ajax_button_validate() {
  350. // do nothing
  351. }
  352. /**
  353. * Validate the tripal_pub_search_form form
  354. *
  355. * @ingroup tripal_pub
  356. */
  357. function tripal_pub_search_form_validate($form, &$form_state) {
  358. $num_criteria = $form_state['storage']['num_criteria'];
  359. $from_year = $form_state['values']['from_year'];
  360. $to_year = $form_state['values']['to_year'];
  361. $op = $form_state['values']['op'];
  362. // no need to vlaidate on a reset
  363. if ($op == 'Reset') {
  364. return;
  365. }
  366. if($from_year and !$to_year) {
  367. form_set_error('to_year', 'Please provide a 4-digit year.');
  368. }
  369. if(!$from_year and $to_year) {
  370. form_set_error('from_year', 'Please provide a 4-digit year.');
  371. }
  372. if($from_year and !preg_match('/\d\d\d\d/' , $from_year)) {
  373. form_set_error('from_year', 'Please provide a 4-digit year.');
  374. }
  375. if($to_year and !preg_match('/\d\d\d\d/' , $to_year)) {
  376. form_set_error('to_year', 'Please provide a 4-digit year.');
  377. }
  378. }
  379. /**
  380. * Submit the tripal_pub_search_form form
  381. *
  382. * @ingroup tripal_pub
  383. */
  384. function tripal_pub_search_form_submit($form, &$form_state) {
  385. $num_criteria = $form_state['storage']['num_criteria'];
  386. $from_year = $form_state['values']['from_year'];
  387. $to_year = $form_state['values']['to_year'];
  388. $op = $form_state['values']['op'];
  389. // set the session variables
  390. if($op == 'Search') {
  391. $_SESSION['tripal_pub_search_form']['num_criteria'] = $num_criteria;
  392. unset($_SESSION['tripal_pub_search_form']['criteria']);
  393. for ($i = 0; $i <= $num_criteria; $i++) {
  394. $search_terms = '';
  395. $scope = '';
  396. $mode = 'Contains';
  397. $operation = '';
  398. if (array_key_exists("search_terms-$i", $form_state['values'])) {
  399. $search_terms = trim($form_state['values']["search_terms-$i"]);
  400. }
  401. if (array_key_exists("scope-$i", $form_state['values'])) {
  402. $scope = $form_state['values']["scope-$i"];
  403. }
  404. if (array_key_exists("operation-$i", $form_state['values'])) {
  405. $operation = $form_state['values']["operation-$i"];
  406. }
  407. //$mode = $form_state['values']["mode-$i"];
  408. $_SESSION['tripal_pub_search_form']['criteria'][$i] = array(
  409. 'search_terms' => $search_terms,
  410. 'scope' => $scope,
  411. 'mode' => $mode,
  412. 'operation' => $operation
  413. );
  414. }
  415. $_SESSION['tripal_pub_search_form']['from_year'] = $from_year;
  416. $_SESSION['tripal_pub_search_form']['to_year'] = $to_year;
  417. $_SESSION['tripal_pub_search_form']['perform_search'] = 1;
  418. }
  419. if($op == 'Reset') {
  420. unset($_SESSION['tripal_pub_search_form']);
  421. }
  422. }
  423. /**
  424. * Ajax callback to update the form
  425. *
  426. * @param $form
  427. * The form array
  428. * @param $form_state
  429. * The form state array
  430. *
  431. * @ingroup tripal_pub
  432. */
  433. function tripal_pubs_search_form_ajax_update($form, $form_state) {
  434. return $form['criteria'];
  435. }
  436. /**
  437. * Theme the tripal_pub_search_setup_form form
  438. *
  439. * @ingroup tripal_pub
  440. */
  441. function theme_tripal_pub_search_setup_form_elements($variables) {
  442. $form = $variables['form'];
  443. $rows = array();
  444. // put each criteria element in a single table row
  445. foreach ($form as $i => $element) {
  446. if(is_numeric($i)) {
  447. $rows[] = array(
  448. drupal_render($element["operation-$i"]),
  449. drupal_render($element["scope-$i"]),
  450. //drupal_render($element["mode-$i"]) .
  451. drupal_render($element["search_terms-$i"]),
  452. array(
  453. 'data' => drupal_render($element["add-$i"]) . drupal_render($element["remove-$i"]),
  454. 'nowrap' => 'nowrap',
  455. ),
  456. );
  457. }
  458. }
  459. // add in the from_year and to_year elements as the final row of the table
  460. $rows[] = array(
  461. '&nbsp;',
  462. drupal_render($form['date']),
  463. array(
  464. 'data' =>
  465. "<div id=\"pub-search-form-dates-row\">
  466. <div id=\"pub-search-form-dates\"> ".
  467. drupal_render($form['from_year']) .
  468. drupal_render($form['to_year']) . "
  469. </div>
  470. </div>
  471. ",
  472. ),
  473. ''
  474. );
  475. $headers = array();
  476. $table = array(
  477. 'header' => $headers,
  478. 'rows' => $rows,
  479. 'attributes' => array(
  480. 'id' => 'tripal-pub-search-form-table',
  481. 'border' => '0',
  482. 'class' => 'tripal-data-table'
  483. ),
  484. 'sticky' => TRUE,
  485. 'caption' => '',
  486. 'colgroups' => array(),
  487. 'empty' => '',
  488. );
  489. $results = '<div id="tripal-pub-search-form-criteria">';
  490. $results .= theme_table($table);
  491. $results .= '</div>';
  492. return $results;
  493. }
  494. /**
  495. * Builds the SQL statement need to search Chado for the publications
  496. * that match the user supplied criteria. Tpyically, this function is
  497. * called by the search form generated by the tripal_pub_search_form() function
  498. * but this function is included in the API for calling by anyone.
  499. *
  500. * @param $search_array
  501. * An array of search criteria provided by the user. The search array is
  502. * an associative array with the following keys:
  503. * 'num_criteria': an integer indicating the number of search criteria supplied
  504. * 'from_year': filters records by a start year
  505. * 'to_year': filters records by an end year
  506. * 'criteria': an array of criteria. Each criteria is an associative
  507. * array with the following keys:
  508. * 'search_terms': The text used for searching
  509. * 'scope': The cvterm_id of the property used for filtering
  510. * 'mode': The operation (e.g. AND, OR or NOT)
  511. * @param $offset
  512. * The offset for paging records. The first record returned will be
  513. * at the offset indicated here, and the next $limit number of records
  514. * will be returned.
  515. *
  516. * @param $limit
  517. * The number of records to retrieve
  518. *
  519. * @param total_records
  520. * A value passed by reference. This value will get set to the total
  521. * number of matching records
  522. *
  523. * @return
  524. * a PDO database object of the query results.
  525. *
  526. * @ingroup tripal_pub
  527. */
  528. function tripal_search_publications($search_array, $offset, $limit, &$total_records) {
  529. // build the SQL based on the criteria provided by the user
  530. $select = "SELECT DISTINCT P.*, CP.nid ";
  531. $from = "FROM {pub} P
  532. LEFT JOIN {chado_pub} CP on P.pub_id = CP.pub_id
  533. INNER JOIN {cvterm} CVT on CVT.cvterm_id = P.type_id
  534. ";
  535. $where = "WHERE (NOT P.title = 'null') "; // always exclude the dummy pub
  536. $order = "ORDER BY P.pyear DESC, P.title ASC";
  537. $args = array(); // arguments for where clause
  538. $join = 0;
  539. $num_criteria = $search_array['num_criteria'];
  540. $from_year = $search_array['from_year'];
  541. $to_year = $search_array['to_year'];
  542. for ($i = 1; $i <= $num_criteria; $i++) {
  543. $value = $search_array['criteria'][$i]['search_terms'];
  544. $type_id = $search_array['criteria'][$i]['scope'];
  545. $mode = $search_array['criteria'][$i]['mode'];
  546. $op = $search_array['criteria'][$i]['operation'];
  547. // skip criteria with no values
  548. if(!$value) {
  549. continue;
  550. }
  551. // to prevent SQL injection make sure our operator is
  552. // what we expect
  553. if ($op and $op != "AND" and $op != "OR" and $op != 'NOT') {
  554. $op = 'AND';
  555. }
  556. if ($op == 'NOT') {
  557. $op = 'AND NOT';
  558. }
  559. if (!$op) {
  560. $op = 'AND';
  561. }
  562. // get the scope type
  563. $values = array('cvterm_id' => $type_id);
  564. $cvterm = chado_select_record('cvterm', array('name'), $values);
  565. $type_name = '';
  566. if (count($cvterm) > 0) {
  567. $type_name = $cvterm[0]->name;
  568. }
  569. if ($type_name == 'Title') {
  570. $where .= " $op (lower(P.title) LIKE lower(:crit$i)) ";
  571. $args[":crit$i"] = '%' . $value . '%';
  572. }
  573. elseif ($type_name == 'Year') {
  574. $where .= " $op (lower(P.pyear) = lower(:crit$i)) ";
  575. $args[":crit$i"] = '%' . $value . '%';
  576. }
  577. elseif ($type_name == 'Volume') {
  578. $where .= " $op (lower(P.volume) = lower(:crit$i)) ";
  579. $args[":crit$i"] = '%' . $value . '%';
  580. }
  581. elseif ($type_name == 'Issue') {
  582. $where .= " $op (lower(P.issue) = lower(:crit$i)) ";
  583. $args[":crit$i"] = '%' . $value . '%';
  584. }
  585. elseif ($type_name == 'Journal Name') {
  586. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
  587. $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Journal Article') OR
  588. (lower(PP$i.value) = lower(:crit$i))) ";
  589. $args[":crit$i"] = $type_id;
  590. }
  591. elseif ($type_name == 'Conference Name') {
  592. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
  593. $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Conference Proceedings') OR
  594. (lower(PP$i.value) = lower(:crit$i))) ";
  595. $args[":crit$i"] = $type_id;
  596. }
  597. elseif ($type_name == 'Publication Type') {
  598. $where .= " $op (lower(CVT.name) = lower(:crit$i))";
  599. $args[":crit$i"] = $value;
  600. }
  601. elseif ($type_id == 0) { //'Any Field'
  602. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id ";
  603. $where .= " $op (lower(PP$i.value) LIKE lower(:crit$i) OR
  604. lower(P.title) LIKE lower(:crit$i) OR
  605. lower(P.volumetitle) LIKE lower(:crit$i) OR
  606. lower(P.publisher) LIKE lower(:crit$i) OR
  607. lower(P.uniquename) LIKE lower(:crit$i) OR
  608. lower(P.pubplace) LIKE lower(:crit$i) OR
  609. lower(P.miniref) LIKE lower(:crit$i) OR
  610. lower(P.series_name) LIKE lower(:crit$i)) ";
  611. $args[":crit$i"] = '%' . $value . '%';
  612. }
  613. // for all other properties
  614. else {
  615. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :type_id$i ";
  616. $where .= " $op (lower(PP$i.value) LIKE lower(:crit$i)) ";
  617. $args[":crit$i"] = '%' . $value . '%';
  618. $args[":type_id$i"] = $type_id;
  619. }
  620. }
  621. if($from_year and $to_year) {
  622. $where .= " AND (P.pyear ~ '....' AND to_number(P.pyear,'9999') >= :from$i AND to_number(P.pyear,'9999') <= :to$i) ";
  623. $args[":from$i"] = $from_year;
  624. $args[":to$i"] = $to_year;
  625. }
  626. $sql = "$select $from $where $order LIMIT " . (int) $limit . ' OFFSET ' . (int) $offset;
  627. $count = "SELECT count(*) FROM ($select $from $where $order) as t1";
  628. // first get the total number of matches
  629. $total_records = chado_query($count, $args)->fetchField();
  630. $results = chado_query($sql, $args);
  631. return $results;
  632. }