tripal_chado.pub_importers.inc 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820
  1. <?php
  2. /**
  3. * @file
  4. * Management of importers
  5. */
  6. require_once('tripal_chado.pub_importer_AGL.inc');
  7. require_once('tripal_chado.pub_importer_PMID.inc');
  8. /**
  9. * A function to generate a table containing the list of publication importers
  10. *
  11. * @ingroup tripal_pub
  12. */
  13. function tripal_pub_importers_list() {
  14. // Check to make sure that the tripal_pub vocabulary is loaded. If not, then
  15. // warn the user that they should load it before continuing.
  16. $pub_cv = chado_select_record('cv', ['cv_id'], ['name' => 'tripal_pub']);
  17. if (count($pub_cv) == 0) {
  18. drupal_set_message(t('The Tripal Pub vocabulary is currently not loaded. ' .
  19. 'This vocabulary is required to be loaded before importing of ' .
  20. 'publications. <br>Please !import',
  21. ['!import' => l('load the Tripal Publication vocabulary', 'aadmin/tripal/loaders/chado_vocabs/obo_loader')]), 'warning');
  22. }
  23. // clear out the session variable when we view the list.
  24. unset($_SESSION['tripal_pub_import']);
  25. $headers = [
  26. '',
  27. 'Importer Name',
  28. 'Database',
  29. 'Search String',
  30. 'Disabled',
  31. 'Create Contact',
  32. '',
  33. ];
  34. $rows = [];
  35. $importers = db_query("SELECT * FROM {tripal_pub_import} ORDER BY name");
  36. while ($importer = $importers->fetchObject()) {
  37. $criteria = unserialize($importer->criteria);
  38. $num_criteria = $criteria['num_criteria'];
  39. $criteria_str = '';
  40. for ($i = 1; $i <= $num_criteria; $i++) {
  41. $search_terms = $criteria['criteria'][$i]['search_terms'];
  42. $scope = $criteria['criteria'][$i]['scope'];
  43. $is_phrase = $criteria['criteria'][$i]['is_phrase'];
  44. $operation = $criteria['criteria'][$i]['operation'];
  45. $criteria_str .= "$operation ($scope: $search_terms) ";
  46. }
  47. $rows[] = [
  48. [
  49. 'data' => l(t('Edit/Test'), "admin/tripal/loaders/pub/edit/$importer->pub_import_id") . '<br>' .
  50. l(t('Import Pubs'), "admin/tripal/loaders/pub/submit/$importer->pub_import_id"),
  51. 'nowrap' => 'nowrap',
  52. ],
  53. $importer->name,
  54. $criteria['remote_db'],
  55. $criteria_str,
  56. $importer->disabled ? 'Yes' : 'No',
  57. $importer->do_contact ? 'Yes' : 'No',
  58. l(t('Delete'), "admin/tripal/loaders/pub/delete/$importer->pub_import_id"),
  59. ];
  60. }
  61. $page = "<ul class='action-links'>";
  62. $page .= ' <li>' . l('New Importer', 'admin/tripal/loaders/pub/new') . '</li>';
  63. $page .= '</ul>';
  64. $page .= '<p>' . t(
  65. "A publication importer is used to create a set of search criteria that can be used
  66. to query a remote database, find publications that match the specified criteria
  67. and then import those publications into the Chado database. An example use case would
  68. be to peridocially add new publications to this Tripal site that have appeared in PubMed
  69. in the last 30 days. You can import publications in one of two ways:
  70. <ol>
  71. <li>Create a new importer by clicking the 'New Importer' link above, and after saving it should appear in the list below. Click the
  72. link labeled 'Import Pubs' to schedule a job to import the publications</li>
  73. <li>The first method only performs the import once. However, you can schedule the
  74. importer to run peridically by adding a cron job. </li>
  75. </ol><br>");
  76. $form = drupal_get_form('tripal_pub_importer_ncbi_api_key_form');
  77. $page .= drupal_render($form);
  78. $table = [
  79. 'header' => $headers,
  80. 'rows' => $rows,
  81. 'attributes' => [
  82. ],
  83. 'caption' => '',
  84. 'sticky' => TRUE,
  85. 'colgroups' => [],
  86. 'empty' => 'There are no currently importers',
  87. ];
  88. $page .= theme_table($table);
  89. return $page;
  90. }
  91. /**
  92. * Creates the page that contains the publication importer setup form and
  93. * test results.
  94. *
  95. * @param $action
  96. * The action to perform
  97. * @param $pub_import_id
  98. * The importer ID
  99. *
  100. * @return
  101. * The HTML for the importer setup page
  102. *
  103. * @ingroup tripal_pub
  104. */
  105. function tripal_pub_importer_setup_page($action = 'new', $pub_import_id = NULL) {
  106. global $base_path;
  107. // make sure the tripal_pub and tripal_contact ontologies are loaded
  108. $values = ['name' => 'tripal_pub'];
  109. $tpub_cv = chado_select_record('cv', ['cv_id'], $values);
  110. if (count($tpub_cv) == 0) {
  111. drupal_set_message(t('Before importing publications you must first ') . l(t('load the Tripal Pub Ontology'), 'admin/tripal/loaders/chado_vocabs/obo_loader'), 'error');
  112. }
  113. $values = ['name' => 'tripal_contact'];
  114. $tpub_cv = chado_select_record('cv', ['cv_id'], $values);
  115. if (count($tpub_cv) == 0) {
  116. drupal_set_message(t('If you want to create contact pages for authors, you must first ') . l(t('load the Tripal Contact Ontology'), 'admin/tripal/loaders/chado_vocabs/obo_loader'), 'error');
  117. }
  118. if(!extension_loaded ('yaz')){
  119. drupal_set_message(t('<b>Note:</b> In order to create an importer using the USDA National Agricultural Library (AGL) you must install the yaz libraries. See the ') . l(t('Users Guide for Instructions'), 'https://tripal.readthedocs.io/en/latest/user_guide/example_genomics/pub_import.html#import-from-the-usda-national-agricultural-library') . ' for assistance. If you do not want to use AGL you can ignore this warning.', 'warning');
  120. }
  121. // generate the search form
  122. $form = drupal_get_form('tripal_pub_importer_setup_form', $pub_import_id, $action);
  123. $output = l("Return to publication importers list", "admin/tripal/loaders/pub");
  124. $output .= drupal_render($form);
  125. // retrieve any results
  126. if (array_key_exists('tripal_pub_import', $_SESSION)) {
  127. $remote_db = array_key_exists('remote_db', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['remote_db'] : '';
  128. $num_criteria = array_key_exists('num_criteria', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['num_criteria'] : '';
  129. $days = array_key_exists('days', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['days'] : '';
  130. $latestyear = array_key_exists('latestyear', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['latestyear'] : '';
  131. $search_array = [];
  132. $search_array['remote_db'] = $remote_db;
  133. $search_array['num_criteria'] = $num_criteria;
  134. $search_array['days'] = $days;
  135. $search_array['latestyear'] = $latestyear;
  136. for ($i = 1; $i <= $num_criteria; $i++) {
  137. $search_array['criteria'][$i]['search_terms'] = $_SESSION['tripal_pub_import']['criteria'][$i]['search_terms'];
  138. $search_array['criteria'][$i]['scope'] = $_SESSION['tripal_pub_import']['criteria'][$i]['scope'];
  139. $search_array['criteria'][$i]['is_phrase'] = $_SESSION['tripal_pub_import']['criteria'][$i]['is_phrase'];
  140. $search_array['criteria'][$i]['operation'] = $_SESSION['tripal_pub_import']['criteria'][$i]['operation'];
  141. }
  142. // if the form has been submitted with the 'test' button then get the results
  143. if ($_SESSION['tripal_pub_import']['perform_search']) {
  144. $limit = 25;
  145. // get the list of publications from the remote database using the search criteria.
  146. $page = isset($_GET['page']) ? $_GET['page'] : '0';
  147. $results = tripal_get_remote_pubs($remote_db, $search_array, $limit, $page);
  148. $total_records = $results['total_records'];
  149. $search_str = $results['search_str'];
  150. $pubs = $results['pubs'];
  151. // iterate through the results and construct the table displaying the publications
  152. $rows = [];
  153. $i = $page * $limit + 1;
  154. if (count($pubs) > 0) {
  155. foreach ($pubs as $pub) {
  156. $citation = array_key_exists('Citation', $pub) ? htmlspecialchars($pub['Citation']) : 'Unable to generate citation';
  157. $raw_link = '';
  158. if (array_key_exists('Publication Dbxref', $pub) and $pub['Publication Dbxref']) {
  159. $raw_link = l('raw', 'admin/tripal/loaders/pub/raw/' . $pub['Publication Dbxref'], ['attributes' => ['target' => '_blank']]);
  160. }
  161. // indicate those that will be excluded by AGL year filtering parameters
  162. if ((array_key_exists('passfilter', $pub)) and ($pub['passfilter'] == 0 )) {
  163. $citation = '<span style="text-decoration: line-through;">' . $citation . '</span>';
  164. }
  165. $rows[] = [
  166. number_format($i),
  167. $citation,
  168. $raw_link,
  169. ];
  170. $i++;
  171. }
  172. }
  173. if (count($rows) == 0) {
  174. $rows[] = [
  175. [
  176. 'data' => 'No results found',
  177. 'colspan' => 3,
  178. ],
  179. ];
  180. }
  181. $headers = ['', 'Publication', 'Raw Results'];
  182. $table = [
  183. 'header' => $headers,
  184. 'rows' => $rows,
  185. 'attributes' => [
  186. 'id' => 'tripal_pub-importer-test',
  187. 'class' => 'tripal-data-table',
  188. ],
  189. 'sticky' => FALSE,
  190. 'caption' => '',
  191. 'colgroups' => [],
  192. 'empty' => '',
  193. ];
  194. // once we have our table array structure defined, we call Drupal's theme_table()
  195. // function to generate the table.
  196. $table = theme_table($table);
  197. // generate the pager
  198. pager_default_initialize($total_records, $limit);
  199. $pager = [
  200. 'tags' => [],
  201. 'element' => 0,
  202. 'parameters' => [],
  203. 'quantity' => $limit,
  204. ];
  205. $pager = theme_pager($pager);
  206. // because this is an ajax callback, the theme_pager will set the URL to be
  207. // "system/ajax", so we need to reset that
  208. $pager = str_replace($base_path . "system/ajax", "", $pager);
  209. // join all to form the results
  210. $total_pages = (int) ($total_records / $limit) + 1;
  211. $page = isset($_GET['page']) ? $_GET['page'] : '0';
  212. $output .= "$pager<br><b>Found " . number_format($total_records) . " publications. Page " . ($page + 1) . " of $total_pages.</b> " .
  213. "<br>$remote_db Search String: $search_str $table<br>$pager";
  214. }
  215. }
  216. return $output;
  217. }
  218. /**
  219. * The form used for creating publication importers.
  220. *
  221. * @param $form
  222. * The Drupal form
  223. * @param $form_state
  224. * The form state
  225. * @param $pub_import_id
  226. * The publication importer ID
  227. * @param $action
  228. * The action to perform
  229. *
  230. * @return
  231. * A form array
  232. *
  233. * @ingroup tripal_pub
  234. */
  235. function tripal_pub_importer_setup_form($form, &$form_state = NULL, $pub_import_id = NULL, $action = 'new') {
  236. // Default values can come in the following ways:
  237. //
  238. // 1) as elements of the $pub_importer object. This occurs when editing an existing importer
  239. // 2) in the $form_state['values'] array which occurs on a failed validation or
  240. // ajax callbacks from non submit form elements
  241. // 3) in the $form_state['input'] array which occurs on ajax callbacks from submit
  242. // form elements and the form is being rebuilt
  243. //
  244. // set form field defaults
  245. // Set the default values. If the pub_import_id isn't already defined by the form values
  246. // and one is provided then look it up in the database
  247. $criteria = NULL;
  248. $remote_db = '';
  249. $days = '';
  250. $latestyear = '';
  251. $disabled = '';
  252. $do_contact = '';
  253. $num_criteria = 1;
  254. $loader_name = '';
  255. // if this is an edit then we are pulling an import object from the database
  256. if ($action == "edit") {
  257. $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :pub_import_id";
  258. $importer = db_query($sql, [':pub_import_id' => $pub_import_id])->fetchObject();
  259. $criteria = unserialize($importer->criteria);
  260. $remote_db = $criteria['remote_db'];
  261. $days = $criteria['days'];
  262. $latestyear = $criteria['latestyear'];
  263. $disabled = $criteria['disabled'];
  264. $do_contact = $criteria['do_contact'];
  265. $num_criteria = $criteria['num_criteria'];
  266. $loader_name = $criteria['loader_name'];
  267. }
  268. // if there are any session variables then use those
  269. if (array_key_exists('tripal_pub_import', $_SESSION)) {
  270. $remote_db = $_SESSION['tripal_pub_import']['remote_db'];
  271. $days = $_SESSION['tripal_pub_import']['days'];
  272. $latestyear = $_SESSION['tripal_pub_import']['latestyear'];
  273. $disabled = $_SESSION['tripal_pub_import']['disabled'];
  274. $do_contact = $_SESSION['tripal_pub_import']['do_contact'];
  275. $num_criteria = $_SESSION['tripal_pub_import']['num_criteria'];
  276. $loader_name = $_SESSION['tripal_pub_import']['loader_name'];
  277. // check if the pub_import_id in the session variable is not the same as the one we've been provided
  278. // if so, then clear the session variable
  279. if ($pub_import_id and $pub_import_id != $_SESSION['tripal_pub_import']['pub_import_id']) {
  280. unset($_SESSION['tripal_pub_import']);
  281. }
  282. }
  283. // if we are re constructing the form from a failed validation or ajax callback
  284. // then use the $form_state['values'] values
  285. if (array_key_exists('values', $form_state)) {
  286. $remote_db = $form_state['values']['remote_db'] ?? null;
  287. $days = $form_state['values']['days'] ?? null;
  288. $latestyear = $form_state['values']['latestyear'] ?? null;
  289. $disabled = $form_state['values']['disabled'] ?? null;
  290. $do_contact = $form_state['values']['do_contact'] ?? null;
  291. $num_criteria = $form_state['values']['num_criteria'] ?? null;
  292. $loader_name = $form_state['values']['loader_name'] ?? null;
  293. }
  294. // if we are re building the form from after submission (from ajax call) then
  295. // the values are in the $form_state['input'] array
  296. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  297. $remote_db = $form_state['input']['remote_db'] ?? null;
  298. $days = $form_state['input']['days'] ?? null;
  299. $latestyear = $form_state['input']['latestyear'] ?? null;
  300. $disabled = $form_state['input']['disabled'] ?? null;
  301. $do_contact = $form_state['input']['do_contact'] ?? null;
  302. $loader_name = $form_state['input']['loader_name'] ?? null;
  303. // because the num_criteria is a value and not a visible or hidden form
  304. // element it is not part of the ['input'] array, so we need to get it from the form
  305. $num_criteria = $form_state['complete form']['num_criteria']['#value'];
  306. }
  307. if (array_key_exists('triggering_element', $form_state) and
  308. $form_state['triggering_element']['#name'] == 'add') {
  309. $num_criteria++;
  310. }
  311. if (array_key_exists('triggering_element', $form_state) and
  312. $form_state['triggering_element']['#name'] == 'remove') {
  313. $num_criteria--;
  314. }
  315. // set the values we need for later but that should not be shown on the form
  316. $form['num_criteria'] = [
  317. '#type' => 'value',
  318. '#value' => $num_criteria,
  319. ];
  320. $form['pub_import_id'] = [
  321. '#type' => 'value',
  322. '#value' => $pub_import_id,
  323. ];
  324. $form['action'] = [
  325. '#type' => 'value',
  326. '#value' => $action,
  327. ];
  328. // add in the elements that will be organized via a theme function
  329. $form['themed_element']['loader_name'] = [
  330. '#type' => 'textfield',
  331. '#title' => t('Loader Name'),
  332. '#description' => t('Please provide a name for this loader setup.'),
  333. '#default_value' => $loader_name,
  334. '#required' => TRUE,
  335. ];
  336. $supported_dbs = variable_get('tripal_pub_supported_dbs', ['PMID']);
  337. $remote_dbs = [];
  338. $values = [
  339. 'name' => $supported_dbs,
  340. ];
  341. $dbs = chado_select_record('db', ['*'], $values);
  342. foreach ($dbs as $index => $db) {
  343. $remote_dbs[$db->name] = $db->description ? $db->description : $db->name;
  344. };
  345. // use PubMed as the default
  346. if (!$remote_db) {
  347. $remote_db = 'PMID';
  348. }
  349. $form['themed_element']['remote_db'] = [
  350. '#title' => t('Source'),
  351. '#type' => 'select',
  352. '#options' => $remote_dbs,
  353. '#default_value' => $remote_db,
  354. '#ajax' => [
  355. 'callback' => "tripal_pubs_setup_form_ajax_update",
  356. 'wrapper' => 'tripal-pubs-importer-setup',
  357. 'effect' => 'fade',
  358. 'method' => 'replace',
  359. ],
  360. ];
  361. $form['themed_element']['days'] = [
  362. '#type' => 'textfield',
  363. '#title' => t('Days since record modified'),
  364. '#description' => t('Limit the search to include pubs that have been added no more than this many days before today.'),
  365. '#default_value' => $days,
  366. '#size' => 5,
  367. ];
  368. // AGL only, this field will be removed for the pubmed loader
  369. $form['themed_element']['latestyear'] = [
  370. '#type' => 'textfield',
  371. '#title' => t('Latest year of publication'),
  372. '#description' => t('Filter returned publications for those that have been published no later than this year.'),
  373. '#default_value' => $latestyear,
  374. '#size' => 5,
  375. ];
  376. $form['themed_element']['disabled'] = [
  377. '#type' => 'checkbox',
  378. '#title' => t('Disabled'),
  379. '#description' => t('Check to disable this importer.'),
  380. '#default_value' => $disabled,
  381. ];
  382. $form['themed_element']['do_contact'] = [
  383. '#type' => 'checkbox',
  384. '#title' => t('Create Contact'),
  385. '#description' => t('Check to create an entry in the contact table for each author of a matching publication during import. This allows storage of
  386. additional information such as affilation, etc. Otherwise, only authors names are retrieved.'),
  387. '#default_value' => $do_contact,
  388. ];
  389. // add in the form for the criteria
  390. tripal_pub_importer_setup_add_criteria_fields($form, $form_state, $num_criteria, $criteria);
  391. // add in the buttons
  392. $form['save'] = [
  393. '#type' => 'submit',
  394. '#value' => t('Save Importer'),
  395. ];
  396. $form['test'] = [
  397. '#type' => 'submit',
  398. '#value' => t('Test Importer'),
  399. ];
  400. $form['delete'] = [
  401. '#type' => 'submit',
  402. '#value' => t('Delete Importer'),
  403. '#attributes' => ['style' => 'float: right;'],
  404. ];
  405. // add in the section where the test results will appear
  406. $form['results'] = [
  407. '#markup' => '<div id="tripal-pub-importer-test-section"></div>',
  408. ];
  409. // allow the selected remote database to make changes to the form if needed
  410. $callback = "tripal_pub_remote_alter_form_$remote_db";
  411. $form = call_user_func($callback, $form, $form_state, $num_criteria);
  412. $form['themed_element']['#theme'] = 'tripal_pub_importer_setup_form_elements';
  413. return $form;
  414. }
  415. /**
  416. * The form used for setting the optional NCBI API key.
  417. *
  418. * @param $form
  419. * The form element to be populated.
  420. * @param $form_state
  421. * The state of the form element to be populated.
  422. *
  423. * @return array
  424. * The populated form element.
  425. *
  426. * @ingroup tripal_pub
  427. */
  428. function tripal_pub_importer_ncbi_api_key_form($form, $form_state) {
  429. $description = t('Tripal imports publications using NCBI\'s ')
  430. . l('EUtils API', 'https://www.ncbi.nlm.nih.gov/books/NBK25500/')
  431. . t(', which limits users and programs to a maximum of 3 requests per second without an API key. '
  432. . 'However, NCBI allows users and programs to an increased maximum of 10 requests per second if '
  433. . 'they provide a valid API key. This is particularly useful in speeding up large publication imports. '
  434. . 'For more information on NCBI API keys, please ')
  435. . l('see here', 'https://www.ncbi.nlm.nih.gov/books/NBK25497/#chapter2.Coming_in_December_2018_API_Key', array(
  436. 'attributes' => array(
  437. 'target' => 'blank',
  438. ),
  439. )) . '.';
  440. $form['ncbi_api_key'] = array(
  441. '#type' => 'textfield',
  442. '#title' => t('(Optional) NCBI API key:'),
  443. '#description' => $description,
  444. '#default_value' => variable_get('tripal_pub_importer_ncbi_api_key', NULL),
  445. '#ajax' => array(
  446. 'callback' => 'tripal_pub_importer_set_ncbi_api_key',
  447. 'wrapper' => 'ncbi_api_key',
  448. ),
  449. '#prefix' => '<div id="ncbi_api_key">',
  450. '#suffix' => '</div>',
  451. );
  452. return $form;
  453. }
  454. /**
  455. * This function saves the NCBI API key to the database.
  456. *
  457. * It is called when the user makes a change to the NCBI API key field and then
  458. * moves their cursor out of the field.
  459. *
  460. * @param $form
  461. * The new form element.
  462. * @param $form_state
  463. * The state of the new form element.
  464. *
  465. * @return array
  466. * The new api key field.
  467. *
  468. * @ingroup tripal_pub
  469. */
  470. function tripal_pub_importer_set_ncbi_api_key($form, $form_state) {
  471. variable_set('tripal_pub_importer_ncbi_api_key', check_plain($form_state['values']['ncbi_api_key']));
  472. drupal_set_message('NCBI API key has been saved successfully!');
  473. return $form['ncbi_api_key'];
  474. }
  475. /**
  476. * A helper function for the importer setup form that adds the criteria to
  477. * the form that belong to the importer.
  478. *
  479. * @param $form
  480. * The form
  481. * @param $form_state
  482. * The form state
  483. * @param $num_criteria
  484. * The number of criteria that exist for the importer
  485. * @param $criteria
  486. * An array containing the criteria
  487. *
  488. * @return
  489. * A form array
  490. *
  491. * @ingroup tripal_pub
  492. */
  493. function tripal_pub_importer_setup_add_criteria_fields(&$form, &$form_state, $num_criteria, $criteria) {
  494. // choices array
  495. $scope_choices = [
  496. 'any' => 'Any Field',
  497. 'abstract' => 'Abstract',
  498. 'author' => 'Author',
  499. 'id' => 'Accession',
  500. 'title' => 'Title',
  501. 'journal' => 'Journal Name',
  502. ];
  503. $first_op_choices = [
  504. '' => '',
  505. 'NOT' => 'NOT',
  506. ];
  507. $op_choices = [
  508. 'AND' => 'AND',
  509. 'OR' => 'OR',
  510. 'NOT' => 'NOT',
  511. ];
  512. for ($i = 1; $i <= $num_criteria; $i++) {
  513. $is_phrase = 1;
  514. $search_terms = '';
  515. $scope = '';
  516. $is_phrase = '';
  517. $operation = '';
  518. // if we have criteria supplied from the database then use that as the initial defaults
  519. if ($criteria) {
  520. if (array_key_exists('criteria', $criteria)) {
  521. if (array_key_exists($i, $criteria['criteria'])) {
  522. $search_terms = $criteria['criteria'][$i]['search_terms'];
  523. $scope = $criteria['criteria'][$i]['scope'];
  524. $is_phrase = $criteria['criteria'][$i]['is_phrase'];
  525. $operation = $criteria['criteria'][$i]['operation'];
  526. }
  527. }
  528. }
  529. // if the criteria comes the session
  530. if (array_key_exists('tripal_pub_import', $_SESSION)) {
  531. $search_terms = isset($_SESSION['tripal_pub_import']['criteria'][$i]['search_terms']) ? $_SESSION['tripal_pub_import']['criteria'][$i]['search_terms'] : $search_terms;
  532. $scope = isset($_SESSION['tripal_pub_import']['criteria'][$i]['scope']) ? $_SESSION['tripal_pub_import']['criteria'][$i]['scope'] : $scope;
  533. $is_phrase = isset($_SESSION['tripal_pub_import']['criteria'][$i]['is_phrase']) ? $_SESSION['tripal_pub_import']['criteria'][$i]['is_phrase'] : $is_phrase;
  534. $operation = isset($_SESSION['tripal_pub_import']['criteria'][$i]['operation']) ? $_SESSION['tripal_pub_import']['criteria'][$i]['operation'] : $operation;
  535. }
  536. // If the form_state has variables then use those. This happens when an error occurs on the form or the
  537. // form is resubmitted using AJAX
  538. if (array_key_exists('values', $form_state)) {
  539. $search_terms = $form_state['values']["search_terms-$i"] ?? null;
  540. $scope = $form_state['values']["scope-$i"] ?? null;
  541. $is_phrase = $form_state['values']["is_phrase-$i"] ?? null;
  542. $operation = $form_state['values']["operation-$i"] ?? null;
  543. }
  544. $form['themed_element']['criteria'][$i]["scope-$i"] = [
  545. '#type' => 'select',
  546. '#description' => t('Please select the fields to search for this term.'),
  547. '#options' => $scope_choices,
  548. '#default_value' => $scope,
  549. ];
  550. $form['themed_element']['criteria'][$i]["search_terms-$i"] = [
  551. '#type' => 'textfield',
  552. '#description' => t('<span style="white-space: normal">Please provide a list of words for searching. You may use
  553. conjunctions such as "AND" or "OR" to separate words if they are expected in
  554. the same scope, but do not mix ANDs and ORs. Check the "Is Phrase" checkbox to use conjunctions as part of the text to search</span>'),
  555. '#default_value' => $search_terms,
  556. '#required' => TRUE,
  557. '#maxlength' => 2048,
  558. ];
  559. $form['themed_element']['criteria'][$i]["is_phrase-$i"] = [
  560. '#type' => 'checkbox',
  561. '#title' => t('Is Phrase?'),
  562. '#default_value' => $is_phrase,
  563. ];
  564. if ($i == 1) {
  565. /*
  566. $form['criteria'][$i]["operation-$i"] = array(
  567. '#type' => 'select',
  568. '#options' => $first_op_choices,
  569. '#default_value' => $operation,
  570. );*/
  571. }
  572. if ($i > 1) {
  573. $form['themed_element']['criteria'][$i]["operation-$i"] = [
  574. '#type' => 'select',
  575. '#options' => $op_choices,
  576. '#default_value' => $operation,
  577. ];
  578. }
  579. if ($i == $num_criteria) {
  580. if ($i > 1) {
  581. $form['themed_element']['criteria'][$i]["remove-$i"] = [
  582. '#type' => 'button',
  583. '#name' => 'remove',
  584. '#value' => t('Remove'),
  585. '#ajax' => [
  586. 'callback' => "tripal_pubs_setup_form_ajax_update",
  587. 'wrapper' => 'tripal-pubs-importer-setup',
  588. 'effect' => 'fade',
  589. 'method' => 'replace',
  590. 'prevent' => 'click',
  591. ],
  592. // When this button is clicked, the form will be validated and submitted.
  593. // Therefore, we set custom submit and validate functions to override the
  594. // default form submit. In the validate function we set the form_state
  595. // to rebuild the form so the submit function never actually gets called,
  596. // but we need it or Drupal will run the default validate anyway.
  597. // we also set #limit_validation_errors to empty so fields that
  598. // are required that don't have values won't generate warnings.
  599. '#submit' => ['tripal_pub_setup_form_ajax_button_submit'],
  600. '#validate' => ['tripal_pub_setup_form_ajax_button_validate'],
  601. '#limit_validation_errors' => [],
  602. ];
  603. }
  604. $form['themed_element']['criteria'][$i]["add-$i"] = [
  605. '#type' => 'button',
  606. '#name' => 'add',
  607. '#value' => t('Add'),
  608. '#ajax' => [
  609. 'callback' => "tripal_pubs_setup_form_ajax_update",
  610. 'wrapper' => 'tripal-pubs-importer-setup',
  611. 'effect' => 'fade',
  612. 'method' => 'replace',
  613. 'prevent' => 'click',
  614. ],
  615. // When this button is clicked, the form will be validated and submitted.
  616. // Therefore, we set custom submit and validate functions to override the
  617. // default form submit. In the validate function we set the form_state
  618. // to rebuild the form so the submit function never actually gets called,
  619. // but we need it or Drupal will run the default validate anyway.
  620. // we also set #limit_validation_errors to empty so fields that
  621. // are required that don't have values won't generate warnings.
  622. '#submit' => ['tripal_pub_setup_form_ajax_button_submit'],
  623. '#validate' => ['tripal_pub_setup_form_ajax_button_validate'],
  624. '#limit_validation_errors' => [],
  625. ];
  626. }
  627. }
  628. }
  629. /**
  630. * This function is used to rebuild the form if an ajax call is made vai a
  631. * button. The button causes the form to be submitted. We don't want this so we
  632. * override the validate and submit routines on the form button. Therefore,
  633. * this function only needs to tell Drupal to rebuild the form
  634. *
  635. * @ingroup tripal_pub
  636. */
  637. function tripal_pub_setup_form_ajax_button_validate($form, &$form_state) {
  638. $form_state['rebuild'] = TRUE;
  639. }
  640. /**
  641. * This function is just a dummy to override the default form submit on ajax
  642. * calls for buttons
  643. *
  644. * @ingroup tripal_pub
  645. */
  646. function tripal_pub_setup_form_ajax_button_submit($form, &$form_state) {
  647. // do nothing
  648. }
  649. /**
  650. * Validate the tripal_pub_importer_setup_form form
  651. *
  652. * @ingroup tripal_pub
  653. */
  654. function tripal_pub_importer_setup_form_validate($form, &$form_state) {
  655. $num_criteria = $form_state['values']['num_criteria'];
  656. $remote_db = $form_state['values']["remote_db"];
  657. $days = trim($form_state['values']["days"]);
  658. $latestyear = trim($form_state['values']["latestyear"]);
  659. $disabled = $form_state['values']["disabled"];
  660. $do_contact = $form_state['values']["do_contact"];
  661. $loader_name = trim($form_state['values']["loader_name"]);
  662. for ($i = 1; $i <= $num_criteria; $i++) {
  663. $search_terms = trim($form_state['values']["search_terms-$i"]);
  664. $scope = $form_state['values']["scope-$i"];
  665. $is_phrase = $form_state['values']["is_phrase-$i"];
  666. $operation = '';
  667. if ($i > 1) {
  668. $operation = $form_state['values']["operation-$i"];
  669. }
  670. if (!$is_phrase) {
  671. if (preg_match('/\sand\s/i', $search_terms) and preg_match('/\sor\s/i', $search_terms)) {
  672. form_set_error("search_terms-$i", "You may use 'AND' or 'OR' but cannot use both. Add a new entry below with the same scope for the other conunction.");
  673. $_SESSION['tripal_pub_import']['perform_search'] = 0;
  674. }
  675. }
  676. }
  677. if ($days and !is_numeric($days) or preg_match('/\./', $days)) {
  678. form_set_error("days", "Please enter a numeric, non decimal value, for the number of days.");
  679. $_SESSION['tripal_pub_import']['perform_search'] = 0;
  680. }
  681. if ($latestyear and !is_numeric($latestyear) or preg_match('/\./', $latestyear)) {
  682. form_set_error("latestyear", "Please enter a numeric, non decimal value, for latestyear.");
  683. $_SESSION['tripal_pub_import']['perform_search'] = 0;
  684. }
  685. // allow the selected remote database to validate any changes to the form if needed
  686. $callback = "tripal_pub_remote_validate_form_$remote_db";
  687. $form = call_user_func($callback, $form, $form_state);
  688. }
  689. /**
  690. * Submit the tripal_pub_importer_setup_form form
  691. *
  692. * @ingroup tripal_pub
  693. */
  694. function tripal_pub_importer_setup_form_submit($form, &$form_state) {
  695. $pub_import_id = $form_state['values']['pub_import_id'];
  696. $num_criteria = $form_state['values']['num_criteria'];
  697. $remote_db = $form_state['values']["remote_db"];
  698. $days = trim($form_state['values']["days"]);
  699. $latestyear = trim($form_state['values']["latestyear"]);
  700. $loader_name = trim($form_state['values']["loader_name"]);
  701. $disabled = $form_state['values']["disabled"];
  702. $do_contact = $form_state['values']["do_contact"];
  703. // set the session variables
  704. $_SESSION['tripal_pub_import']['remote_db'] = $remote_db;
  705. $_SESSION['tripal_pub_import']['days'] = $days;
  706. $_SESSION['tripal_pub_import']['latestyear'] = $latestyear;
  707. $_SESSION['tripal_pub_import']['num_criteria'] = $num_criteria;
  708. $_SESSION['tripal_pub_import']['loader_name'] = $loader_name;
  709. $_SESSION['tripal_pub_import']['disabled'] = $disabled;
  710. $_SESSION['tripal_pub_import']['do_contact'] = $do_contact;
  711. $_SESSION['tripal_pub_import']['pub_import_id'] = $pub_import_id;
  712. unset($_SESSION['tripal_pub_import']['criteria']);
  713. for ($i = 1; $i <= $num_criteria; $i++) {
  714. $search_terms = trim($form_state['values']["search_terms-$i"]);
  715. $scope = $form_state['values']["scope-$i"];
  716. $is_phrase = $form_state['values']["is_phrase-$i"];
  717. $operation = '';
  718. if ($i > 1) {
  719. $operation = $form_state['values']["operation-$i"];
  720. }
  721. $_SESSION['tripal_pub_import']['criteria'][$i] = [
  722. 'search_terms' => $search_terms,
  723. 'scope' => $scope,
  724. 'is_phrase' => $is_phrase,
  725. 'operation' => $operation,
  726. ];
  727. }
  728. // now perform the appropriate action for the button clicked
  729. if ($form_state['values']['op'] == 'Test Importer') {
  730. $_SESSION['tripal_pub_import']['perform_search'] = 1;
  731. }
  732. if ($form_state['values']['op'] == 'Save Importer' or
  733. $form_state['values']['op'] == 'Save & Import Now') {
  734. $record = [
  735. 'name' => $loader_name,
  736. 'criteria' => serialize($_SESSION['tripal_pub_import']),
  737. 'disabled' => $disabled,
  738. 'do_contact' => $do_contact,
  739. ];
  740. // first check to see if this pub_import_id is already present. If so,
  741. // do an update rather than an insert
  742. $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :pub_import_id";
  743. $importer = db_query($sql, [':pub_import_id' => $pub_import_id])->fetchObject();
  744. if ($importer) {
  745. // do the update
  746. $record['pub_import_id'] = $pub_import_id;
  747. if (drupal_write_record('tripal_pub_import', $record, 'pub_import_id')) {
  748. unset($_SESSION['tripal_pub_import']);
  749. drupal_set_message('Publication import settings updated.');
  750. drupal_goto('admin/tripal/loaders/pub');
  751. }
  752. else {
  753. drupal_set_message('Could not update publication import settings.', 'error');
  754. }
  755. }
  756. else {
  757. // do the insert
  758. if (drupal_write_record('tripal_pub_import', $record)) {
  759. unset($_SESSION['tripal_pub_import']);
  760. drupal_set_message('Publication import settings saved.');
  761. // if the user wants to do the import now then do it (may time out
  762. // for long jobs)
  763. if ($form_state['values']['op'] == 'Save & Import Now') {
  764. chado_execute_pub_importer($record['pub_import_id']);
  765. }
  766. drupal_goto('admin/tripal/loaders/pub');
  767. }
  768. else {
  769. drupal_set_message('Could not save publication import settings.', 'error');
  770. }
  771. }
  772. }
  773. if ($form_state['values']['op'] == 'Delete Importer') {
  774. $sql = "DELETE FROM {tripal_pub_import} WHERE pub_import_id = :pub_import_id";
  775. $success = db_query($sql, [':pub_import_id' => $pub_import_id]);
  776. if ($success) {
  777. drupal_set_message('Publication importer deleted.');
  778. drupal_goto('admin/tripal/loaders/pub');
  779. }
  780. else {
  781. drupal_set_message('Could not delete publication importer.', 'error');
  782. }
  783. }
  784. }
  785. /**
  786. * AJAX callback for updating the form.
  787. *
  788. * @ingroup tripal_pub
  789. */
  790. function tripal_pubs_setup_form_ajax_update($form, $form_state) {
  791. return $form['themed_element'];
  792. }
  793. /**
  794. * Theme the tripal_pub_importer_setup_form form.
  795. *
  796. * @ingroup tripal_pub
  797. */
  798. function theme_tripal_pub_importer_setup_form_elements($variables) {
  799. $form = $variables['form'];
  800. // first render the fields at the top of the form
  801. $markup = '';
  802. $markup .= '<div id="pub-search-form-row0">';
  803. $markup .= ' <div id="pub-search-form-row0-col1" style="float: left">' . drupal_render($form['remote_db']) . '</div>';
  804. $markup .= ' <div id="pub-search-form-row0-col2" style="float: left; margin-left: 10px">' . drupal_render($form['loader_name']) . '</div>';
  805. $markup .= '</div>';
  806. $markup .= '<div id="pub-search-form-row1" style="clear:both">';
  807. $markup .= ' <div id="pub-search-form-row1-col1">' . drupal_render($form['days']) . '</div>';
  808. // latest year field is used ony for AGL importer
  809. if ($variables['form']['remote_db']['#value'] == 'AGL') {
  810. $markup .= ' <div id="pub-search-form-row1-col2">' . drupal_render($form['latestyear']) . '</div>';
  811. }
  812. $markup .= '</div>';
  813. $markup .= '<div id="pub-search-form-row2">' . drupal_render($form['disabled']) . '</div>';
  814. $markup .= '<div id="pub-search-form-row3">' . drupal_render($form['do_contact']) . '</div>';
  815. // next render the criteria fields into a table format
  816. $rows = [];
  817. foreach ($form['criteria'] as $i => $element) {
  818. if (is_numeric($i)) {
  819. $rows[] = [
  820. drupal_render($element["operation-$i"]),
  821. drupal_render($element["scope-$i"]),
  822. drupal_render($element["search_terms-$i"]),
  823. drupal_render($element["is_phrase-$i"]),
  824. drupal_render($element["add-$i"]) . drupal_render($element["remove-$i"]),
  825. ];
  826. }
  827. }
  828. $headers = ['Operation', 'Scope', 'Search Terms', '', ''];
  829. $table = [
  830. 'header' => $headers,
  831. 'rows' => $rows,
  832. 'attributes' => [
  833. 'class' => ['tripal-data-table'],
  834. ],
  835. 'sticky' => TRUE,
  836. 'caption' => '',
  837. 'colgroups' => [],
  838. 'empty' => '',
  839. ];
  840. $criteria_table = theme_table($table);
  841. $markup .= $criteria_table;
  842. // add the rendered form
  843. $form = [
  844. '#markup' => $markup,
  845. '#prefix' => '<div id="tripal-pubs-importer-setup">',
  846. '#suffix' => '</div>',
  847. ];
  848. return drupal_render($form);
  849. }
  850. /**
  851. * Add a job to import publications
  852. *
  853. * @param $pub_importer_id
  854. * The id of the importer to submit a job to update
  855. *
  856. * @ingroup tripal_pub
  857. */
  858. function tripal_pub_importer_submit_job($import_id) {
  859. global $user;
  860. // get all of the loaders
  861. $args = [':import_id' => $import_id];
  862. $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :import_id ";
  863. $import = db_query($sql, $args)->fetchObject();
  864. $args = [$import_id, TRUE, FALSE];
  865. $includes = [];
  866. $includes[] = module_load_include('inc', 'tripal_chado', 'includes/loaders/tripal_chado.pub_importers');
  867. tripal_add_job("Import publications $import->name", 'tripal_chado',
  868. 'chado_execute_pub_importer', $args, $user->uid, 10, $includes);
  869. drupal_goto('admin/tripal/loaders/pub');
  870. }
  871. /**
  872. * Deletes a publication importer.
  873. *
  874. */
  875. function tripal_pub_importer_delete($import_id) {
  876. $args = [':import_id' => $import_id];
  877. $sql = "DELETE FROM {tripal_pub_import} WHERE pub_import_id = :import_id";
  878. $success = db_query($sql, $args);
  879. if ($success) {
  880. drupal_set_message('Publication importer deleted.');
  881. drupal_goto('admin/tripal/loaders/pub');
  882. }
  883. else {
  884. drupal_set_message('Could not delete publication importer.', 'error');
  885. }
  886. }
  887. /**
  888. * Adds publications that have been retrieved from a remote database and
  889. * consolidated into an array of details.
  890. *
  891. * @param $pubs
  892. * An array containing a list of publications to add to Chado. The
  893. * array contains a set of details for the publication.
  894. * @param $do_contact
  895. * Set to TRUE if authors should automatically have a contact record added
  896. * to Chado.
  897. * @param $update
  898. * If set to TRUE then publications that already exist in the Chado database
  899. * will be updated, whereas if FALSE only new publications will be added
  900. * @param $job
  901. * The jobs management object for the job if this function is run as a job.
  902. * This argument is added by Tripal during a job run and is not needed if
  903. * this function is run directly.
  904. *
  905. * @return
  906. * Returns an array containing the number of publications that were
  907. * inserted, updated, skipped and which had an error during import.
  908. *
  909. * @ingroup tripal_pub
  910. */
  911. function tripal_pub_add_publications($pubs, $do_contact, $update = FALSE, $job = NULL) {
  912. // These are options for the tripal_report_error function. We do not
  913. // want to log messages to the watchdog but we do for the job and to
  914. // the terminal
  915. $message_type = 'pub_import';
  916. $message_opts = [
  917. 'watchdog' == TRUE,
  918. 'job' => $job,
  919. 'print' => TRUE,
  920. ];
  921. $report = [];
  922. $report['error'] = [];
  923. $report['inserted'] = [];
  924. $report['skipped'] = [];
  925. $report['updated'] = [];
  926. $total_pubs = count($pubs);
  927. // iterate through the publications and add each one
  928. $i = 1;
  929. foreach ($pubs as $pub) {
  930. $memory = number_format(memory_get_usage()) . " bytes";
  931. print "Processing $i of $total_pubs. Memory usage: $memory.\r";
  932. // implementation of year limits for AGL uses a 'passfilter' flag
  933. if ((!array_key_exists('passfilter', $pub)) or ($pub['passfilter'] == 1 )) {
  934. // add the publication to Chado
  935. $action = '';
  936. $pub_id = tripal_pub_add_publication($pub, $action, $do_contact, $update, $job);
  937. // $pub_id will be null if publication already existed
  938. if ($pub_id) {
  939. // add the publication cross reference (e.g. to PubMed)
  940. if ($pub_id and $pub['Publication Dbxref']) {
  941. $dbxref = [];
  942. if (preg_match('/^(.*?):(.*?)$/', trim($pub['Publication Dbxref']), $matches)) {
  943. $dbxref['db_name'] = $matches[1];
  944. $dbxref['accession'] = $matches[2];
  945. }
  946. else {
  947. tripal_report_error($message_type, TRIPAL_ERROR,
  948. 'Unable to extract the dbxref to be associated with the publication (pub ID=@pub_id) from @dbxref. This reference should be [database-name]:[accession]',
  949. [
  950. '@pub_id' => $pub_id,
  951. '@dbxref' => $pub['Publication Dbxref'],
  952. $message_opts,
  953. ]
  954. );
  955. }
  956. $pub_dbxref = tripal_associate_dbxref('pub', $pub_id, $dbxref);
  957. }
  958. $pub['pub_id'] = $pub_id;
  959. }
  960. switch ($action) {
  961. case 'error':
  962. $report['error'][] = $pub['Citation'];
  963. break;
  964. case 'inserted':
  965. $report['inserted'][] = $pub['Citation'];
  966. break;
  967. case 'updated':
  968. $report['updated'][] = $pub['Citation'];
  969. break;
  970. case 'skipped':
  971. $report['skipped'][] = $pub['Citation'];
  972. break;
  973. }
  974. }
  975. // else pub failed AGL year filter
  976. else { $report['skipped'][] = $pub['Citation']; }
  977. $i++;
  978. }
  979. return $report;
  980. }
  981. /**
  982. * Adds a new publication to Chado.
  983. *
  984. * In addition, all properties and
  985. * database cross-references. If the publication does not already exist
  986. * in Chado then it is added. If it does exist nothing is done. If
  987. * the $update parameter is TRUE then the publication is updated if it exists.
  988. *
  989. * @param $pub_details
  990. * An associative array containing all of the details about the publication.
  991. * @param $action
  992. * This variable will get set to a text value indicating the action that was
  993. * performed. The values include 'skipped', 'inserted', 'updated' or 'error'.
  994. * @param $do_contact
  995. * Optional. Set to TRUE if a contact entry should be added to the Chado
  996. * contact table for authors of the publication.
  997. * @param $update_if_exists
  998. * Optional. If the publication already exists then this function will
  999. * return without adding a new publication. However, set this value to
  1000. * TRUE to force the function to pudate the publication using the
  1001. * $pub_details that are provided.
  1002. * @param $job
  1003. * The jobs management object for the job if this function is run as a job.
  1004. * This argument is added by Tripal during a job run and is not needed if
  1005. * this function is run directly.
  1006. *
  1007. * @return
  1008. * If the publication already exists, is inserted or updated then the
  1009. * publication ID is returned, otherwise FALSE is returned. If the
  1010. * publication already exists and $update_if_exists is not TRUE then the
  1011. * $action variable is set to 'skipped'. If the publication already exists
  1012. * and $update_if_exists is TRUE and if the update was successful then
  1013. * $action is set to 'updated'. Otherwise on successful insert the
  1014. * $action variable is set to 'inserted'. If the function fails then the
  1015. * $action variable is set to 'error'
  1016. *
  1017. * @ingroup tripal_pub
  1018. */
  1019. function tripal_pub_add_publication($pub_details, &$action, $do_contact = FALSE, $update_if_exists = FALSE, $job = NULL) {
  1020. $pub_id = 0;
  1021. // These are options for the tripal_report_error function. We do not
  1022. // want to log messages to the watchdog except for errors and to the job and
  1023. // to the terminal
  1024. $message_type = 'pub_import';
  1025. $message_opts = [
  1026. 'watchdog' == FALSE,
  1027. 'job' => $job,
  1028. 'print' => TRUE,
  1029. ];
  1030. $error_opts = [
  1031. 'watchdog' == TRUE,
  1032. 'job' => $job,
  1033. 'print' => TRUE,
  1034. ];
  1035. if (!is_array($pub_details)) {
  1036. return FALSE;
  1037. }
  1038. // Before proceeding check to see if the publication already exists. If there
  1039. // is only one match and the $update_if_exists is NOT set then return FALSE.
  1040. $pub_ids = chado_publication_exists($pub_details);
  1041. if (count($pub_ids) == 1 and !$update_if_exists) {
  1042. tripal_report_error($message_type, TRIPAL_NOTICE,
  1043. "The following publication already exists on this site: %title %dbxref (Matching Pub id: %ids). Skipping.",
  1044. [
  1045. '%title' => $pub_details['Citation'],
  1046. '%dbxref' => $pub_details['Publication Dbxref'],
  1047. '%ids' => implode(",", $pub_ids),
  1048. ],
  1049. $message_opts
  1050. );
  1051. $action = 'skipped';
  1052. return FALSE;
  1053. }
  1054. // If we have more than one matching pub then return an error as we don't
  1055. // know which to update even if update_if_exists is set to TRUE.
  1056. if (count($pub_ids) > 1) {
  1057. tripal_report_error($message_type, TRIPAL_NOTICE,
  1058. "The following publication exists %num times on this site: %title %dbxref (Matching Pub id: %ids). Skipping.",
  1059. [
  1060. '%num' => count($pub_ids),
  1061. '%title' => $pub_details['Citation'],
  1062. '%dbxref' => $pub_details['Publication Dbxref'],
  1063. '%ids' => implode(",", $pub_ids),
  1064. ],
  1065. $message_opts
  1066. );
  1067. $action = 'skipped';
  1068. return FALSE;
  1069. }
  1070. if (count($pub_ids) == 1 and $update_if_exists) {
  1071. $pub_id = $pub_ids[0];
  1072. }
  1073. // Get the publication type (use the first publication type).
  1074. if (array_key_exists('Publication Type', $pub_details)) {
  1075. $pub_type = '';
  1076. if (is_array($pub_details['Publication Type'])) {
  1077. $pub_type = $pub_details['Publication Type'][0];
  1078. }
  1079. else {
  1080. $pub_type = $pub_details['Publication Type'];
  1081. }
  1082. $identifiers = [
  1083. 'name' => $pub_type,
  1084. 'cv_id' => [
  1085. 'name' => 'tripal_pub',
  1086. ],
  1087. ];
  1088. $pub_type = chado_get_cvterm($identifiers);
  1089. }
  1090. else {
  1091. tripal_report_error($message_type, TRIPAL_ERROR,
  1092. "The Publication Type is a required property but is missing", [], $error_opts);
  1093. $action = 'error';
  1094. return FALSE;
  1095. }
  1096. if (!$pub_type) {
  1097. tripal_report_error($message_type, TRIPAL_ERROR,
  1098. "Cannot find publication type: '%type'",
  1099. ['%type' => $pub_details['Publication Type'][0]], $error_opts);
  1100. $action = 'error';
  1101. return FALSE;
  1102. }
  1103. // The series name field in the pub table is only 255 characters, so we
  1104. // should trim just in case.
  1105. $series_name = '';
  1106. if (array_key_exists('Series_Name', $pub_details)) {
  1107. $series_name = substr($pub_details['Series Name'], 0, 255);
  1108. }
  1109. if (array_key_exists('Journal Name', $pub_details)) {
  1110. $series_name = substr($pub_details['Journal Name'], 0, 255);
  1111. }
  1112. // Build the values array for inserting or updating.
  1113. $values = [
  1114. 'title' => $pub_details['Title'],
  1115. 'volume' => (isset($pub_details['Volume'])) ? $pub_details['Volume'] : '',
  1116. 'series_name' => $series_name,
  1117. 'issue' => (isset($pub_details['Issue'])) ? $pub_details['Issue'] : '',
  1118. 'pyear' => (isset($pub_details['Year'])) ? $pub_details['Year'] : '',
  1119. 'pages' => (isset($pub_details['Pages'])) ? $pub_details['Pages'] : '',
  1120. 'uniquename' => $pub_details['Citation'],
  1121. 'type_id' => $pub_type->cvterm_id,
  1122. ];
  1123. // If there is no pub_id then we need to do an insert.
  1124. if (!$pub_id) {
  1125. $options = ['statement_name' => 'ins_pub_tivoseispypaunty'];
  1126. $pub = chado_insert_record('pub', $values, $options);
  1127. if (!$pub) {
  1128. tripal_report_error($message_type, TRIPAL_ERROR,
  1129. "Cannot insert the publication with title: %title",
  1130. ['%title' => $pub_details['Title']], $error_opts);
  1131. $action = 'error';
  1132. return FALSE;
  1133. }
  1134. $pub_id = $pub['pub_id'];
  1135. $action = 'inserted';
  1136. }
  1137. // If there is a pub_id and we've been told to update, then do the update.
  1138. else {
  1139. if ($pub_id and $update_if_exists) {
  1140. $match = ['pub_id' => $pub_id];
  1141. $options = ['statement_name' => 'up_pub_tivoseispypaunty'];
  1142. $success = chado_update_record('pub', $match, $values, $options);
  1143. if (!$success) {
  1144. tripal_report_error($message_type, TRIPAL_ERROR,
  1145. "Cannot update the publication with title: %title",
  1146. ['%title' => $pub_details['Title']], $error_opts);
  1147. $action = 'error';
  1148. return FALSE;
  1149. }
  1150. $action = 'updated';
  1151. }
  1152. }
  1153. // Before we add any new properties we need to remove those that are there
  1154. // if this is an update. The only thing we don't want to remove are the
  1155. // 'Publication Dbxref'.
  1156. if ($update_if_exists) {
  1157. $sql = "
  1158. DELETE FROM {pubprop}
  1159. WHERE
  1160. pub_id = :pub_id AND
  1161. NOT type_id in (
  1162. SELECT cvterm_id
  1163. FROM {cvterm}
  1164. WHERE name = 'Publication Dbxref'
  1165. )
  1166. ";
  1167. chado_query($sql, [':pub_id' => $pub_id]);
  1168. }
  1169. // Iterate through the properties and add them.
  1170. foreach ($pub_details as $key => $value) {
  1171. // The pub_details may have the raw search data (e.g. in XML from PubMed.
  1172. // We'll irgnore this for now.
  1173. if ($key == 'raw') {
  1174. continue;
  1175. }
  1176. // Filtering flag for AGL, not a property to add here
  1177. if ($key == 'passfilter') {
  1178. continue;
  1179. }
  1180. // Since we're not updating the 'Publication Dbxref' on an update
  1181. // skip this property.
  1182. if ($update_if_exists and $key == 'Publication Dbxref') {
  1183. continue;
  1184. }
  1185. // Get the cvterm by name.
  1186. $identifiers = [
  1187. 'name' => $key,
  1188. 'cv_id' => [
  1189. 'name' => 'tripal_pub',
  1190. ],
  1191. ];
  1192. $cvterm = chado_get_cvterm($identifiers);
  1193. // If we could not find the cvterm by name then try by synonym.
  1194. if (!$cvterm) {
  1195. $identifiers = [
  1196. 'synonym' => [
  1197. 'name' => $key,
  1198. 'cv_name' => 'tripal_pub',
  1199. ],
  1200. ];
  1201. $cvterm = chado_get_cvterm($identifiers);
  1202. }
  1203. if (!$cvterm) {
  1204. tripal_report_error($message_type, TRIPAL_ERROR,
  1205. "Cannot find term: '%prop'. Skipping.", ['%prop' => $key], $error_opts);
  1206. continue;
  1207. }
  1208. // Skip details that won't be stored as properties.
  1209. if ($key == 'Author List') {
  1210. tripal_pub_add_authors($pub_id, $value, $do_contact);
  1211. continue;
  1212. }
  1213. if ($key == 'Title' or $key == 'Volume' or $key == 'Journal Name' or $key == 'Issue' or
  1214. $key == 'Year' or $key == 'Pages') {
  1215. continue;
  1216. }
  1217. $success = 0;
  1218. if (is_array($value)) {
  1219. foreach ($value as $subkey => $subvalue) {
  1220. // If the key is an integer then this array is a simple list and
  1221. // we will insert using the primary key. Otheriwse, use the new key.
  1222. if (is_int($subkey)) {
  1223. $success = chado_insert_property(
  1224. ['table' => 'pub', 'id' => $pub_id],
  1225. [
  1226. 'type_name' => $key,
  1227. 'cv_name' => 'tripal_pub',
  1228. 'value' => $subvalue,
  1229. ]
  1230. );
  1231. }
  1232. else {
  1233. $success = chado_insert_property(
  1234. ['table' => 'pub', 'id' => $pub_id],
  1235. [
  1236. 'type_name' => $subkey,
  1237. 'cv_name' => 'tripal_pub',
  1238. 'value' => $subvalue,
  1239. ]
  1240. );
  1241. }
  1242. }
  1243. }
  1244. else {
  1245. $success = chado_insert_property(
  1246. ['table' => 'pub', 'id' => $pub_id],
  1247. ['type_name' => $key, 'cv_name' => 'tripal_pub', 'value' => $value],
  1248. ['update_if_present' => TRUE]
  1249. );
  1250. }
  1251. if (!$success) {
  1252. tripal_report_error($message_type, TRIPAL_ERROR,
  1253. "Cannot add property '%prop' to pubprop table. Skipping.",
  1254. ['%prop' => $key], $error_opts);
  1255. continue;
  1256. }
  1257. }
  1258. return $pub_id;
  1259. }
  1260. /**
  1261. * Add one or more authors to a publication
  1262. *
  1263. * @param $pub_id
  1264. * The publication ID of the pub in Chado.
  1265. * @param $authors
  1266. * An array of authors. Each author should have a set of keys/value pairs
  1267. * describing the author.
  1268. * @param $do_contact
  1269. * Optional. Set to TRUE if a contact entry should be added to the Chado
  1270. * contact table for authors of the publication.
  1271. *
  1272. * @ingroup tripal_pub
  1273. */
  1274. function tripal_pub_add_authors($pub_id, $authors, $do_contact) {
  1275. $rank = 0;
  1276. // First remove any of the existing pubauthor entires.
  1277. $sql = "DELETE FROM {pubauthor} WHERE pub_id = :pub_id";
  1278. chado_query($sql, [':pub_id' => $pub_id]);
  1279. // Iterate through the authors and add them to the pubauthors and contact
  1280. // tables of chado, then link them through the custom pubauthors_contact
  1281. // table.
  1282. foreach ($authors as $author) {
  1283. // Skip invalid author entires.
  1284. if (isset($author['valid']) AND $author['valid'] == 'N') {
  1285. continue;
  1286. }
  1287. // remove the 'valid' property as we don't have a CV term for it
  1288. unset($author['valid']);
  1289. $values = [
  1290. 'pub_id' => $pub_id,
  1291. 'rank' => $rank,
  1292. ];
  1293. // construct the contact.name field using the author information
  1294. $name = '';
  1295. $type = 'Person';
  1296. if (isset($author['Given Name'])) {
  1297. $name .= $author['Given Name'];
  1298. $values['givennames'] = $author['Given Name'];
  1299. }
  1300. if (isset($author['Surname'])) {
  1301. $name .= ' ' . $author['Surname'];
  1302. $values['surname'] = substr($author['Surname'], 0, 100);
  1303. }
  1304. if (isset($author['Suffix'])) {
  1305. $name .= ' ' . $author['Suffix'];
  1306. $values['suffix'] = $author['Suffix'];
  1307. }
  1308. if (isset($author['Collective'])) {
  1309. $name = $author['Collective'];
  1310. $type = 'Collective';
  1311. if (!isset($author['Surname'])) {
  1312. $values['surname'] = substr($author['Collective'], 0, 100);
  1313. }
  1314. }
  1315. $name = trim($name);
  1316. // add an entry to the pubauthors table
  1317. $options = ['statement_name' => 'ins_pubauthor_idrasugisu'];
  1318. $pubauthor = chado_insert_record('pubauthor', $values, $options);
  1319. // if the user wants us to create a contact for each author then do it.
  1320. if ($do_contact) {
  1321. // Add the contact
  1322. $contact = chado_insert_contact([
  1323. 'name' => $name,
  1324. 'description' => '',
  1325. 'type_name' => $type,
  1326. 'properties' => $author,
  1327. ]);
  1328. // if we have succesfully added the contact and the pubauthor entries then we want to
  1329. // link them together
  1330. if ($contact and $pubauthor) {
  1331. // link the pubauthor entry to the contact
  1332. $values = [
  1333. 'pubauthor_id' => $pubauthor['pubauthor_id'],
  1334. 'contact_id' => $contact['contact_id'],
  1335. ];
  1336. $options = ['statement_name' => 'ins_pubauthorcontact_puco'];
  1337. $pubauthor_contact = chado_insert_record('pubauthor_contact', $values, $options);
  1338. if (!$pubauthor_contact) {
  1339. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot link pub authro and contact.", []);
  1340. }
  1341. }
  1342. }
  1343. $rank++;
  1344. }
  1345. }
  1346. /**
  1347. * This function generates an array suitable for use with the
  1348. * tripal_pub_create_citation function for any publication
  1349. * already stored in the Chado tables.
  1350. *
  1351. * @param $pub_id
  1352. * The publication ID
  1353. * @param $skip_existing
  1354. * Set to TRUE to skip publications that already have a citation
  1355. * in the pubprop table. Set to FALSE to generate a citation
  1356. * regardless if the citation already exists.
  1357. *
  1358. * @return
  1359. * An array suitable for the trpial_pub_create_citation function. On
  1360. * failure returns FALSE.
  1361. *
  1362. * @ingroup tripal_pub
  1363. */
  1364. function tripal_pub_get_publication_array($pub_id, $skip_existing = TRUE) {
  1365. $options = ['return_array' => 1];
  1366. // ---------------------------------
  1367. // get the publication
  1368. // ---------------------------------
  1369. $values = ['pub_id' => $pub_id];
  1370. $pub = chado_generate_var('pub', $values);
  1371. // expand the title
  1372. $pub = chado_expand_var($pub, 'field', 'pub.title');
  1373. $pub = chado_expand_var($pub, 'field', 'pub.volumetitle');
  1374. $pub = chado_expand_var($pub, 'field', 'pub.uniquename');
  1375. $pub_array = [];
  1376. if (trim($pub->title)) {
  1377. $pub_array['Title'] = $pub->title;
  1378. }
  1379. if (trim($pub->volumetitle)) {
  1380. $pub_array['Volume Title'] = $pub->volumetitle;
  1381. }
  1382. if (trim($pub->volume)) {
  1383. $pub_array['Volume'] = $pub->volume;
  1384. }
  1385. if (trim($pub->series_name)) {
  1386. $pub_array['Series Name'] = $pub->series_name;
  1387. }
  1388. if (trim($pub->issue)) {
  1389. $pub_array['Issue'] = $pub->issue;
  1390. }
  1391. if (trim($pub->pyear)) {
  1392. $pub_array['Year'] = $pub->pyear;
  1393. }
  1394. if (trim($pub->pages)) {
  1395. $pub_array['Pages'] = $pub->pages;
  1396. }
  1397. if (trim($pub->miniref)) {
  1398. $pub_array['Mini Ref'] = $pub->miniref;
  1399. }
  1400. if (trim($pub->uniquename)) {
  1401. $pub_array['Uniquename'] = $pub->uniquename;
  1402. }
  1403. $pub_array['Publication Type'][] = $pub->type_id->name;
  1404. // ---------------------------------
  1405. // get the citation
  1406. // ---------------------------------
  1407. $values = [
  1408. 'pub_id' => $pub->pub_id,
  1409. 'type_id' => [
  1410. 'name' => 'Citation',
  1411. ],
  1412. ];
  1413. $citation = chado_generate_var('pubprop', $values);
  1414. if ($citation) {
  1415. $citation = chado_expand_var($citation, 'field', 'pubprop.value', $options);
  1416. if (count($citation) > 1) {
  1417. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Publication has multiple citations already: %pub_id",
  1418. ['%pub_id' => $pubid]);
  1419. return FALSE;
  1420. }
  1421. elseif (count($citation) == 1 and $skip_existing == TRUE) {
  1422. // skip this publication, it already has a citation
  1423. return FALSE;
  1424. }
  1425. }
  1426. // ---------------------------------
  1427. // get the publication types
  1428. // ---------------------------------
  1429. $values = [
  1430. 'pub_id' => $pub->pub_id,
  1431. 'type_id' => [
  1432. 'name' => 'Publication Type',
  1433. ],
  1434. ];
  1435. $ptypes = chado_generate_var('pubprop', $values, $options);
  1436. if ($ptypes) {
  1437. $ptypes = chado_expand_var($ptypes, 'field', 'pubprop.value', $options);
  1438. foreach ($ptypes as $ptype) {
  1439. $pub_array['Publication Type'][] = $ptype->value;
  1440. }
  1441. }
  1442. // ---------------------------------
  1443. // get the authors list
  1444. // ---------------------------------
  1445. $values = [
  1446. 'pub_id' => $pub->pub_id,
  1447. 'type_id' => [
  1448. 'name' => 'Authors',
  1449. ],
  1450. ];
  1451. $authors = chado_generate_var('pubprop', $values);
  1452. $authors = chado_expand_var($authors, 'field', 'pubprop.value', $options);
  1453. if (count($authors) > 1) {
  1454. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Publication has multiple author lists. It should have only one list: %pub_id",
  1455. ['%pub_id' => $pubid]);
  1456. return FALSE;
  1457. }
  1458. else {
  1459. if (trim($authors->value)) {
  1460. $pub_array['Authors'] = $authors->value;
  1461. }
  1462. // if there is no 'Author's property then try to retreive authors from the pubauthor table
  1463. else {
  1464. $sql = "
  1465. SELECT string_agg(surname || ' ' || givennames, ', ')
  1466. FROM {pubauthor}
  1467. WHERE pub_id = :pub_id
  1468. GROUP BY pub_id
  1469. ";
  1470. $au = chado_query($sql, [':pub_id' => $pub_id])->fetchField();
  1471. if ($au) {
  1472. $pub_array['Authors'] = $au;
  1473. }
  1474. }
  1475. }
  1476. //Get other props
  1477. $props = [
  1478. 'Journal Abbreviation',
  1479. 'Elocation',
  1480. 'Media Code',
  1481. 'Conference Name',
  1482. 'Keywords',
  1483. 'Series Name',
  1484. 'pISSN',
  1485. 'Publication Date',
  1486. 'Journal Code',
  1487. 'Journal Alias',
  1488. 'Journal Country',
  1489. 'Published Location',
  1490. 'Publication Model',
  1491. 'Language Abbr',
  1492. 'Alias',
  1493. 'Publication Dbxref',
  1494. 'Copyright',
  1495. 'Abstract',
  1496. 'Notes',
  1497. 'Citation',
  1498. 'Language',
  1499. 'URL',
  1500. 'eISSN',
  1501. 'DOI',
  1502. 'ISSN',
  1503. 'Publication Code',
  1504. 'Comments',
  1505. 'Publisher',
  1506. 'Media Alias',
  1507. 'Original Title',
  1508. ];
  1509. foreach ($props AS $prop) {
  1510. $sql =
  1511. "SELECT value FROM {pubprop}
  1512. WHERE type_id =
  1513. (SELECT cvterm_id
  1514. FROM {cvterm}
  1515. WHERE name = :cvtname AND cv_id =
  1516. (SELECT cv_id
  1517. FROM {cv}
  1518. WHERE name = 'tripal_pub'
  1519. )
  1520. )
  1521. AND pub_id = :pub_id
  1522. ";
  1523. $val = trim(chado_query($sql, [
  1524. ':cvtname' => $prop,
  1525. ':pub_id' => $pub->pub_id,
  1526. ])->fetchField());
  1527. if ($val) {
  1528. $pub_array[$prop] = $val;
  1529. }
  1530. }
  1531. return $pub_array;
  1532. }
  1533. /**
  1534. * This function is used to perfom a query using one of the supported databases
  1535. * and return the raw query results. This may be XML or some other format
  1536. * as provided by the database.
  1537. *
  1538. * @param $dbxref
  1539. * The unique database ID for the record to retrieve. This value must
  1540. * be of the format DB_NAME:ACCESSION where DB_NAME is the name of the
  1541. * database (e.g. PMID or AGL) and the ACCESSION is the unique identifier
  1542. * for the record in the database.
  1543. *
  1544. * @return
  1545. * Returns the publication array or FALSE if a problem occurs
  1546. *
  1547. * @ingroup tripal_pub
  1548. */
  1549. function tripal_get_remote_pub($dbxref) {
  1550. if (preg_match('/^(.*?):(.*?)$/', $dbxref, $matches)) {
  1551. $remote_db = $matches[1];
  1552. $accession = $matches[2];
  1553. // check that the database is supported
  1554. $supported_dbs = variable_get('tripal_pub_supported_dbs', ['PMID']);
  1555. if (!in_array($remote_db, $supported_dbs)) {
  1556. return FALSE;
  1557. }
  1558. $search = [
  1559. 'num_criteria' => 1,
  1560. 'remote_db' => $remote_db,
  1561. 'criteria' => [
  1562. '1' => [
  1563. 'search_terms' => "$remote_db:$accession",
  1564. 'scope' => 'id',
  1565. 'operation' => '',
  1566. 'is_phrase' => 0,
  1567. ],
  1568. ],
  1569. ];
  1570. $pubs = tripal_get_remote_pubs($remote_db, $search, 1, 0);
  1571. return $pubs['pubs'][0];
  1572. }
  1573. return FALSE;
  1574. }
  1575. /**
  1576. * Retrieves a list of publications as an associated array where
  1577. * keys correspond directly with Tripal Pub CV terms.
  1578. *
  1579. * @param remote_db
  1580. * The name of the remote publication database to query. These names should
  1581. * match the name of the databases in the Chado 'db' table. Currently
  1582. * supported databass include
  1583. * 'PMID': PubMed
  1584. *
  1585. * @param search_array
  1586. * An associate array containing the search criteria. The following key
  1587. * are expected
  1588. * 'remote_db': Specifies the name of the remote publication database
  1589. * 'num_criteria': Specifies the number of criteria present in the search
  1590. * array
  1591. * 'days': The number of days to include in the search starting
  1592. * from today
  1593. * 'criteria': An associate array containing the search critiera.
  1594. * There should be no less than 'num_criteria' elements in this array.
  1595. *
  1596. * The following keys are expected in the 'criteria' array
  1597. * 'search_terms': A list of terms to search on, separated by spaces.
  1598. * 'scope': The fields to search in the remote database. Valid
  1599. * values include: 'title', 'abstract', 'author' and 'any'
  1600. * 'operation': The logical operation to use for this criteria. Valid
  1601. * values include: 'AND', 'OR' and 'NOT'.
  1602. * @param $num_to_retrieve
  1603. * The number of records to retrieve. In cases with large numbers of
  1604. * records to retrieve, the remote database may limit the size of each
  1605. * retrieval.
  1606. * @param $page
  1607. * Optional. If this function is called where the
  1608. * page for the pager cannot be set using the $_GET variable, use this
  1609. * argument to specify the page to retrieve.
  1610. *
  1611. * @return
  1612. * Returns an array of pubs where each element is
  1613. * an associative array where the keys are Tripal Pub CV terms.
  1614. *
  1615. * @ingroup tripal_pub
  1616. */
  1617. function tripal_get_remote_pubs($remote_db, $search_array, $num_to_retrieve, $page = 0) {
  1618. // now call the callback function to get the results
  1619. $callback = "tripal_pub_remote_search_$remote_db";
  1620. $pubs = [
  1621. 'total_records' => 0,
  1622. 'search_str' => '',
  1623. 'pubs' => [],
  1624. ];
  1625. if (function_exists($callback)) {
  1626. $pubs = call_user_func($callback, $search_array, $num_to_retrieve, $page);
  1627. }
  1628. return $pubs;
  1629. }
  1630. /**
  1631. * The admin form for submitting job to create citations
  1632. *
  1633. * @param $form_state
  1634. *
  1635. * @ingroup tripal_pub
  1636. */
  1637. function tripal_pub_citation_form($form, &$form_state) {
  1638. $form['instructions'] = [
  1639. '#markup' => '<p>Use this form to unify publication citations. Citations are created automtically when
  1640. importing publications but citations are set by the user when publications are added manually.
  1641. Or publications added to the Chado database by tools other than the Tripal Publication Importer may
  1642. not have citations set. If you are certain that all necessary information for all publications is present (e.g.
  1643. authors, volume, issue, page numbers, etc.) but citations are not consistent, then you can
  1644. choose to update all citations for all publications using the form below. Alternatively, you
  1645. can update citations only for publication that do not already have one.</p>',
  1646. ];
  1647. $form['options'] = [
  1648. '#type' => 'radios',
  1649. '#options' => [
  1650. 'all' => 'Create citation for all publications. Replace the existing citation if it exists.',
  1651. 'new' => 'Create citation for publication only if it does not already have one.',
  1652. ],
  1653. '#default_value' => 'all',
  1654. ];
  1655. $form['submit'] = [
  1656. '#type' => 'submit',
  1657. '#value' => t('Submit'),
  1658. ];
  1659. return $form;
  1660. }
  1661. /**
  1662. * Submit form. Create Tripal job for citations
  1663. *
  1664. * @param $form_state
  1665. *
  1666. * @ingroup tripal_pub
  1667. */
  1668. function tripal_pub_citation_form_submit(&$form_state) {
  1669. $options [0] = $form_state['options']['#value'];
  1670. tripal_add_job("Create citations ($options[0])", 'tripal_pub', 'chado_pub_create_citations', $options, $user->uid);
  1671. }