tripal_pub.api.inc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) to manage chado publications
  5. */
  6. /**
  7. * @defgroup tripal_pub_api Publication Module API
  8. * @ingroup tripal_api
  9. * @{
  10. * Provides an application programming interface (API) to manage chado publications
  11. *
  12. * @stephen add documentation here for how to add a new importer.
  13. *
  14. * @}
  15. */
  16. /**
  17. * Retrieves a list of publications as an associated array where
  18. * keys correspond directly with Tripal Pub CV terms.
  19. *
  20. * @param remote_db
  21. * The name of the remote publication database to query. These names should
  22. * match the name of the databases in the Chado 'db' table. Currently
  23. * supported databass include
  24. * 'PMID': PubMed
  25. *
  26. * @param search_array
  27. * An associate array containing the search criteria. The following key
  28. * are expected
  29. * 'remote_db': Specifies the name of the remote publication database
  30. * 'num_criteria': Specifies the number of criteria present in the search array
  31. * 'days': The number of days to include in the search starting from today
  32. * 'criteria': An associate array containing the search critiera. There should
  33. * be no less than 'num_criteria' elements in this array.
  34. *
  35. * The following keys are expected in the 'criteria' array
  36. * 'search_terms': A list of terms to search on, separated by spaces.
  37. * 'scope': The fields to search in the remote database. Valid values
  38. * include: 'title', 'abstract', 'author' and 'any'
  39. * 'operation': The logical operation to use for this criteria. Valid
  40. * values include: 'AND', 'OR' and 'NOT'.
  41. * @param $num_to_retrieve
  42. * The number of records to retrieve. In cases with large numbers of
  43. * records to retrieve, the remote database may limit the size of each
  44. * retrieval.
  45. * @param $page
  46. * Optional. If this function is called where the
  47. * page for the pager cannot be set using the $_GET variable, use this
  48. * argument to specify the page to retrieve.
  49. *
  50. * @return
  51. * Returns an array of pubs where each element is
  52. * an associative array where the keys are Tripal Pub CV terms.
  53. *
  54. * @ingroup tripal_pub_api
  55. */
  56. function pub_search_remote($remote_db, $search_array, $num_to_retrieve, $page = 0) {
  57. // now call the callback function to get the results
  58. $callback = "tripal_pub_remote_search_$remote_db";
  59. $pubs = array(
  60. 'total_records' => 0,
  61. 'search_str' => '',
  62. 'pubs' => array(),
  63. );
  64. if (function_exists($callback)) {
  65. $pubs = call_user_func($callback, $search_array, $num_to_retrieve, $page);
  66. }
  67. return $pubs;
  68. }
  69. /**
  70. * Builds the SQL statement need to search Chado for the publications
  71. * that match the user supplied criteria. Tpyically, this function is
  72. * called by the search form generated by the tripal_pub_search_form() function
  73. * but this function is included in the API for calling by anyone.
  74. *
  75. * @param $search_array
  76. * An array of search criteria provided by the user. The search array is
  77. * an associative array with the following keys:
  78. * 'num_criteria': an integer indicating the number of search criteria supplied
  79. * 'from_year': filters records by a start year
  80. * 'to_year': filters records by an end year
  81. * 'criteria': an array of criteria. Each criteria is an associative
  82. * array with the following keys:
  83. * 'search_terms': The text used for searching
  84. * 'scope': The cvterm_id of the property used for filtering
  85. * 'mode': The operation (e.g. AND, OR or NOT)
  86. * @param $offset
  87. * The offset for paging records. The first record returned will be
  88. * at the offset indicated here, and the next $limit number of records
  89. * will be returned.
  90. *
  91. * @param $limit
  92. * The number of records to retrieve
  93. *
  94. * @param total_records
  95. * A value passed by reference. This value will get set to the total
  96. * number of matching records
  97. *
  98. * @return
  99. * a PDO database object of the query results.
  100. *
  101. * @ingroup tripal_pub
  102. */
  103. function pub_search($search_array, $offset, $limit, &$total_records) {
  104. // build the SQL based on the criteria provided by the user
  105. $select = "SELECT DISTINCT P.*, CP.nid ";
  106. $from = "FROM {pub} P
  107. LEFT JOIN public.chado_pub CP on P.pub_id = CP.pub_id
  108. INNER JOIN {cvterm} CVT on CVT.cvterm_id = P.type_id
  109. ";
  110. $where = "WHERE (NOT P.title = 'null') "; // always exclude the dummy pub
  111. $order = "ORDER BY P.pyear DESC, P.title ASC";
  112. $args = array(); // arguments for where clause
  113. $join = 0;
  114. $num_criteria = $search_array['num_criteria'];
  115. $from_year = $search_array['from_year'];
  116. $to_year = $search_array['to_year'];
  117. for ($i = 1; $i <= $num_criteria; $i++) {
  118. $value = $search_array['criteria'][$i]['search_terms'];
  119. $type_id = $search_array['criteria'][$i]['scope'];
  120. $mode = $search_array['criteria'][$i]['mode'];
  121. $op = $search_array['criteria'][$i]['operation'];
  122. // skip criteria with no values
  123. if(!$value) {
  124. continue;
  125. }
  126. // to prevent SQL injection make sure our operator is
  127. // what we expect
  128. if ($op and $op != "AND" and $op != "OR" and $op != 'NOT') {
  129. $op = 'AND';
  130. }
  131. if ($op == 'NOT') {
  132. $op = 'AND NOT';
  133. }
  134. if (!$op) {
  135. $op = 'AND';
  136. }
  137. // get the scope type
  138. $values = array('cvterm_id' => $type_id);
  139. $cvterm = chado_select_record('cvterm', array('name'), $values);
  140. $type_name = '';
  141. if (count($cvterm) > 0) {
  142. $type_name = $cvterm[0]->name;
  143. }
  144. if ($type_name == 'Title') {
  145. $where .= " $op (lower(P.title) LIKE lower(:crit$i)) ";
  146. $args[":crit$i"] = '%' . $value . '%';
  147. }
  148. elseif ($type_name == 'Year') {
  149. $where .= " $op (lower(P.pyear) = lower(:crit$i)) ";
  150. $args[":crit$i"] = '%' . $value . '%';
  151. }
  152. elseif ($type_name == 'Volume') {
  153. $where .= " $op (lower(P.volume) = lower(:crit$i)) ";
  154. $args[":crit$i"] = '%' . $value . '%';
  155. }
  156. elseif ($type_name == 'Issue') {
  157. $where .= " $op (lower(P.issue) = lower(:crit$i)) ";
  158. $args[":crit$i"] = '%' . $value . '%';
  159. }
  160. elseif ($type_name == 'Journal Name') {
  161. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
  162. $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Journal Article') OR
  163. (lower(PP$i.value) = lower(:crit$i))) ";
  164. $args[":crit$i"] = $type_id;
  165. }
  166. elseif ($type_name == 'Conference Name') {
  167. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
  168. $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Conference Proceedings') OR
  169. (lower(PP$i.value) = lower(:crit$i))) ";
  170. $args[":crit$i"] = $type_id;
  171. }
  172. elseif ($type_name == 'Publication Type') {
  173. $where .= " $op (lower(CVT.name) = lower(:crit$i))";
  174. $args[":crit$i"] = $value;
  175. }
  176. elseif ($type_id == 0) { //'Any Field'
  177. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id ";
  178. $where .= " $op (lower(PP$i.value) LIKE lower(:crit$i) OR
  179. lower(P.title) LIKE lower(:crit$i) OR
  180. lower(P.volumetitle) LIKE lower(:crit$i) OR
  181. lower(P.publisher) LIKE lower(:crit$i) OR
  182. lower(P.uniquename) LIKE lower(:crit$i) OR
  183. lower(P.pubplace) LIKE lower(:crit$i) OR
  184. lower(P.miniref) LIKE lower(:crit$i) OR
  185. lower(P.series_name) LIKE lower(:crit$i)) ";
  186. $args[":crit$i"] = '%' . $value . '%';
  187. }
  188. // for all other properties
  189. else {
  190. $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :type_id$i ";
  191. $where .= " $op (lower(PP$i.value) LIKE lower(:crit$i)) ";
  192. $args[":crit$i"] = '%' . $value . '%';
  193. $args[":type_id$i"] = $type_id;
  194. }
  195. }
  196. if($from_year and $to_year) {
  197. $where .= " AND (P.pyear ~ '....' AND to_number(P.pyear,'9999') >= :from$i AND to_number(P.pyear,'9999') <= :to$i) ";
  198. $args[":from$i"] = $from_year;
  199. $args[":to$i"] = $to_year;
  200. }
  201. $sql = "$select $from $where $order LIMIT " . (int) $limit . ' OFFSET ' . (int) $offset;
  202. $count = "SELECT count(*) FROM ($select $from $where $order) as t1";
  203. // first get the total number of matches
  204. $total_records = chado_query($count, $args)->fetchField();
  205. $results = chado_query($sql, $args);
  206. return $results;
  207. }
  208. /**
  209. * This function is used to perfom a query using one of the supported databases
  210. * and return the raw query results. This may be XML or some other format
  211. * as provided by the database.
  212. *
  213. * @param $dbxref
  214. * The unique database ID for the record to retrieve. This value must
  215. * be of the format DB_NAME:ACCESSION where DB_NAME is the name of the
  216. * database (e.g. PMID or AGL) and the ACCESSION is the unique identifier
  217. * for the record in the database.
  218. *
  219. * @return
  220. * Returns the raw output wrapped in an HTML textarea element or an
  221. * error message indicating if the database type is unsupported or the
  222. * dbxref is invalid
  223. *
  224. * @ingroup tripal_pub_api
  225. */
  226. function tripal_get_remote_pub_record($dbxref) {
  227. if(preg_match('/^(.*?):(.*?)$/', $dbxref, $matches)) {
  228. $remote_db = $matches[1];
  229. $accession = $matches[2];
  230. // check that the database is supported
  231. $supported_dbs = variable_get('tripal_pub_supported_dbs', array());
  232. if(!in_array($remote_db, $supported_dbs)) {
  233. return "Unsupported database: $dbxref";
  234. }
  235. $search = array(
  236. 'num_criteria' => 1,
  237. 'remote_db' => $remote_db,
  238. 'criteria' => array(
  239. '1' => array(
  240. 'search_terms' => "$remote_db:$accession",
  241. 'scope' => 'id',
  242. 'operation' => '',
  243. 'is_phrase' => 0,
  244. ),
  245. ),
  246. );
  247. $pubs = pub_search_remote($remote_db, $search, 1, 0);
  248. return $pubs[0]['raw'];
  249. }
  250. return 'Invalid DB xref';
  251. }
  252. /**
  253. * Updates publication records with the most recent data in the remote
  254. * database.
  255. *
  256. * @param $do_contact
  257. * Set to TRUE if authors should automatically have a contact record added
  258. * to Chado. Contacts are added using the name provided by the remote
  259. * database.
  260. * @param $dbxref
  261. * The unique database ID for the record to update. This value must
  262. * be of the format DB_NAME:ACCESSION where DB_NAME is the name of the
  263. * database (e.g. PMID or AGL) and the ACCESSION is the unique identifier
  264. * for the record in the database.
  265. * @param $db
  266. * The name of the remote database to update. If this value is provided and
  267. * no dbxref then all of the publications currently in the Chado database
  268. * for this remote database will be updated.
  269. *
  270. * @ingroup tripal_pub_api
  271. */
  272. function tripal_pub_update_publications($do_contact = FALSE, $dbxref = NULL, $db = NULL) {
  273. print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
  274. "If the load fails or is terminated prematurely then the entire set of \n" .
  275. "insertions/updates is rolled back and will not be found in the database\n\n";
  276. $transaction = db_transaction();
  277. try {
  278. // get a list of all publications by their Dbxrefs that have supported databases
  279. $sql = "
  280. SELECT DB.name as db_name, DBX.accession
  281. FROM pub P
  282. INNER JOIN pub_dbxref PDBX ON P.pub_id = PDBX.pub_id
  283. INNER JOIN dbxref DBX ON DBX.dbxref_id = PDBX.dbxref_id
  284. INNER JOIN db DB ON DB.db_id = DBX.db_id
  285. ";
  286. $args = array();
  287. if ($dbxref and preg_match('/^(.*?):(.*?)$/', $dbxref, $matches)) {
  288. $dbname = $matches[1];
  289. $accession = $matches[2];
  290. $sql .= "WHERE DBX.accession = :accession and DB.name = :dbname ";
  291. $args[':accession'] = $accession;
  292. $args[':dbname'] = $dbname;
  293. }
  294. elseif ($db) {
  295. $sql .= " WHERE DB.name = :dbname ";
  296. $args[':dbname'] = $db;
  297. }
  298. $sql .= "ORDER BY DB.name, P.pub_id";
  299. $results = chado_query($sql, $args);
  300. $num_to_retrieve = 100;
  301. $i = 0; // count the number of IDs. When we hit $num_to_retrieve we'll do the query
  302. $curr_db = ''; // keeps track of the current current database
  303. $ids = array(); // the list of IDs for the database
  304. $search = array(); // the search array passed to the search function
  305. // iterate through the pub IDs
  306. while ($pub = $results->fetchObject()) {
  307. $accession = $pub->accession;
  308. $remote_db = $pub->db_name;
  309. // here we need to only update publications for databases we support
  310. $supported_dbs = variable_get('tripal_pub_supported_dbs', array());
  311. if(!in_array($remote_db, $supported_dbs)) {
  312. continue;
  313. }
  314. $search = array(
  315. 'num_criteria' => 1,
  316. 'remote_db' => $remote_db,
  317. 'criteria' => array(
  318. '1' => array(
  319. 'search_terms' => "$remote_db:$accession",
  320. 'scope' => 'id',
  321. 'operation' => '',
  322. 'is_phrase' => 0,
  323. ),
  324. ),
  325. );
  326. $pubs = pub_search_remote($remote_db, $search, 1, 0);
  327. tripal_pub_add_publications($pubs, $do_contact, TRUE);
  328. $i++;
  329. }
  330. // sync the newly added publications with Drupal
  331. print "Syncing publications with Drupal...\n";
  332. tripal_pub_sync_pubs();
  333. // if the caller wants to create contacts then we should sync them
  334. if ($do_contact) {
  335. print "Syncing contacts with Drupal...\n";
  336. tripal_contact_sync_contacts();
  337. }
  338. }
  339. catch (Exception $e) {
  340. print "\n"; // make sure we start errors on new line
  341. watchdog_exception('T_pub_import', $e);
  342. $transaction->rollback();
  343. print "FAILED: Rolling back database changes...\n";
  344. return;
  345. }
  346. print "Done.\n";
  347. }
  348. /**
  349. * Imports all publications for a given publication import setup.
  350. *
  351. * @param $import_id
  352. * The ID of the import setup to use
  353. * @param $job_id
  354. * The jobs management job_id for the job if this function is run as a job.
  355. *
  356. * @ingroup tripal_pub_api
  357. */
  358. function tripal_pub_import_publications_by_import_id($import_id, $job_id = NULL) {
  359. print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
  360. "If the load fails or is terminated prematurely then the entire set of \n" .
  361. "insertions/updates is rolled back and will not be found in the database\n\n";
  362. // start the transaction
  363. $transaction = db_transaction();
  364. try {
  365. $page = 0;
  366. $do_contact = FALSE;
  367. $num_to_retrieve = 100;
  368. // get all of the loaders
  369. $args = array(':import_id' => $import_id);
  370. $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :import_id ";
  371. $import = db_query($sql, $args)->fetchObject();
  372. print "Importing: " . $import->name . "\n";
  373. $criteria = unserialize($import->criteria);
  374. $remote_db = $criteria['remote_db'];
  375. $total_pubs = 0;
  376. do {
  377. // retrieve the pubs for this page. We'll retreive 100 at a time
  378. $results = pub_search_remote($remote_db, $criteria, $num_to_retrieve, $page);
  379. $pubs = $results['pubs'];
  380. $num_pubs = $rseults['total_records'];
  381. $total_pubs += $num_pubs;
  382. tripal_pub_add_publications($pubs, $import->do_contact);
  383. $page++;
  384. }
  385. // continue looping until we have a $pubs array that does not have
  386. // our requested numer of records. This means we've hit the end
  387. while (count($pubs) == $num_to_retrieve);
  388. // sync the newly added publications with Drupal. If the user
  389. // requested a report then we don't want to print any syncing information
  390. // so pass 'FALSE' to the sync call
  391. print "Syncing publications with Drupal...\n";
  392. tripal_pub_sync_pubs();
  393. // if any of the importers wanted to create contacts from the authors then sync them
  394. if($import->do_contact) {
  395. print "Syncing contacts with Drupal...\n";
  396. tripal_contact_sync_contacts();
  397. }
  398. tripal_set_job_progress($job_id, '100');
  399. }
  400. catch (Exception $e) {
  401. print "\n"; // make sure we start errors on new line
  402. watchdog_exception('T_pub_import', $e);
  403. $transaction->rollback();
  404. print "FAILED: Rolling back database changes...\n";
  405. return;
  406. }
  407. print "Done.\n";
  408. }
  409. /**
  410. * Imports all publications for all active import setups.
  411. *
  412. * @param $report_email
  413. * A list of email address, separated by commas, that should be notified
  414. * once importing has completed
  415. * @param $do_update
  416. * If set to TRUE then publications that already exist in the Chado database
  417. * will be updated, whereas if FALSE only new publications will be added
  418. *
  419. * @ingroup tripal_pub_api
  420. */
  421. function tripal_pub_import_publications($report_email = FALSE, $do_update = FALSE) {
  422. $num_to_retrieve = 100;
  423. $page = 0;
  424. print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
  425. "If the load fails or is terminated prematurely then the entire set of \n" .
  426. "insertions/updates is rolled back and will not be found in the database\n\n";
  427. // start the transaction
  428. $transaction = db_transaction();
  429. try {
  430. // get all of the loaders
  431. $args = array();
  432. $sql = "SELECT * FROM {tripal_pub_import} WHERE disabled = 0 ";
  433. $results = db_query($sql, $args);
  434. $do_contact = FALSE;
  435. $reports = array();
  436. foreach ($results as $import) {
  437. $page = 0;
  438. print "Importing: " . $import->name . "\n";
  439. // keep track if any of the importers want to create contacts from authors
  440. if ($import->do_contact == 1) {
  441. $do_contact = TRUE;
  442. }
  443. $criteria = unserialize($import->criteria);
  444. $remote_db = $criteria['remote_db'];
  445. do {
  446. // retrieve the pubs for this page. We'll retreive 100 at a time
  447. $results = pub_search_remote($remote_db, $criteria, $num_to_retrieve, $page);
  448. $pubs = $results['pubs'];
  449. $reports[$import->name] = tripal_pub_add_publications($pubs, $import->do_contact, $do_update);
  450. $page++;
  451. }
  452. // continue looping until we have a $pubs array that does not have
  453. // our requested numer of records. This means we've hit the end
  454. while (count($pubs) == $num_to_retrieve);
  455. }
  456. // sync the newly added publications with Drupal. If the user
  457. // requested a report then we don't want to print any syncing information
  458. // so pass 'FALSE' to the sync call
  459. print "Syncing publications with Drupal...\n";
  460. tripal_pub_sync_pubs();
  461. // iterate through each of the reports and generate a final report with HTML links
  462. $HTML_report = '';
  463. if ($report_email) {
  464. $HTML_report .= "<html>";
  465. global $base_url;
  466. foreach ($reports as $importer => $report) {
  467. $total = count($report['inserted']);
  468. $HTML_report .= "<b>$total new publications from importer: $importer</b><br><ol>\n";
  469. foreach ($report['inserted'] as $pub) {
  470. $item = $pub['Title'];
  471. if (array_key_exists('pub_id', $pub)) {
  472. $item = l($pub['Title'], "$base_url/pub/" . $pub['pub_id']);
  473. }
  474. $HTML_report .= "<li>$item</li>\n";
  475. }
  476. $HTML_report .= "</ol>\n";
  477. }
  478. $HTML_report .= "</html>";
  479. $site_email = variable_get('site_mail', '');
  480. $params = array(
  481. 'message' => $HTML_report
  482. );
  483. drupal_mail('tripal_pub', 'import_report', $report_email, language_default(), $params, $site_email, TRUE);
  484. }
  485. // if any of the importers wanted to create contacts from the authors then sync them
  486. if($do_contact) {
  487. print "Syncing contacts with Drupal...\n";
  488. tripal_contact_sync_contacts();
  489. }
  490. }
  491. catch (Exception $e) {
  492. print "\n"; // make sure we start errors on new line
  493. watchdog_exception('T_pub_import', $e);
  494. $transaction->rollback();
  495. print "FAILED: Rolling back database changes...\n";
  496. return;
  497. }
  498. print "Done.\n";
  499. }
  500. /**
  501. * Imports a singe publication specified by a remote database cross reference.
  502. *
  503. * @param $pub_dbxref
  504. * The unique database ID for the record to update. This value must
  505. * be of the format DB_NAME:ACCESSION where DB_NAME is the name of the
  506. * database (e.g. PMID or AGL) and the ACCESSION is the unique identifier
  507. * for the record in the database.
  508. * @param $do_contact
  509. * Set to TRUE if authors should automatically have a contact record added
  510. * to Chado.
  511. * @param $do_update
  512. * If set to TRUE then the publication will be updated if it already exists
  513. * in the database.
  514. *
  515. * @ingroup tripal_pub_api
  516. */
  517. function tripal_pub_import_by_dbxref($pub_dbxref, $do_contact = FALSE, $do_update) {
  518. $num_to_retrieve = 1;
  519. $pager_id = 0;
  520. $page = 0;
  521. $num_pubs = 0;
  522. print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
  523. "If the load fails or is terminated prematurely then the entire set of \n" .
  524. "insertions/updates is rolled back and will not be found in the database\n\n";
  525. $transaction = db_transaction();
  526. try {
  527. if(preg_match('/^(.*?):(.*?)$/', $pub_dbxref, $matches)) {
  528. $dbname = $matches[1];
  529. $accession = $matches[2];
  530. $criteria = array(
  531. 'num_criteria' => 1,
  532. 'remote_db' => $dbname,
  533. 'criteria' => array(
  534. '1' => array(
  535. 'search_terms' => "$dbname:$accession",
  536. 'scope' => 'id',
  537. 'operation' => '',
  538. 'is_phrase' => 0,
  539. ),
  540. ),
  541. );
  542. $remote_db = $criteria['remote_db'];
  543. $results = pub_search_remote($remote_db, $criteria, $num_to_retrieve, $page);
  544. $pubs = $results['pubs'];
  545. $search_str = $results['search_str'];
  546. $total_records = $results['total_records'];
  547. $pub_id = tripal_pub_add_publications($pubs, $do_contact, $do_update);
  548. }
  549. // sync the newly added publications with Drupal
  550. print "Syncing publications with Drupal...\n";
  551. tripal_pub_sync_pubs();
  552. // if any of the importers wanted to create contacts from the authors then sync them
  553. if($do_contact) {
  554. print "Syncing contacts with Drupal...\n";
  555. tripal_contact_sync_contacts();
  556. }
  557. }
  558. catch (Exception $e) {
  559. print "\n"; // make sure we start errors on new line
  560. watchdog_exception('T_pub_import', $e);
  561. $transaction->rollback();
  562. print "FAILED: Rolling back database changes...\n";
  563. return;
  564. }
  565. print "Done.\n";
  566. }
  567. /**
  568. * Adds publications that have been retrieved from a remote database and
  569. * consolidated into an array of details.
  570. *
  571. * @param $pubs
  572. * An array containing a list of publications to add to Chado. The
  573. * array contains a set of details for the publication.
  574. * @param $do_contact
  575. * Set to TRUE if authors should automatically have a contact record added
  576. * to Chado.
  577. * @param $update
  578. * If set to TRUE then publications that already exist in the Chado database
  579. * will be updated, whereas if FALSE only new publications will be added
  580. *
  581. * @return
  582. * Returns an array containing the number of publications that were
  583. * inserted, updated, skipped and which had an error during import.
  584. *
  585. * @ingroup tripal_pub_api
  586. */
  587. function tripal_pub_add_publications($pubs, $do_contact, $update = FALSE) {
  588. $report = array();
  589. $report['error'] = 0;
  590. $report['inserted'] = array();
  591. $report['skipped'] = array();
  592. $total_pubs = count($pubs);
  593. // iterate through the publications and add each one
  594. $i = 1;
  595. foreach ($pubs as $pub) {
  596. $memory = number_format(memory_get_usage()) . " bytes";
  597. print "Processing $i of $total_pubs. Memory usage: $memory.\r";
  598. // add the publication to Chado
  599. $action = '';
  600. $pub_id = tripal_pub_add_publication($pub, $action, $do_contact, $update);
  601. if ($pub_id){
  602. // add the publication cross reference (e.g. to PubMed)
  603. if ($pub_id and $pub['Publication Dbxref']) {
  604. $pub_dbxref = tripal_pub_add_pub_dbxref($pub_id, $pub['Publication Dbxref']);
  605. }
  606. $pub['pub_id'] = $pub_id;
  607. }
  608. switch ($action) {
  609. case 'error':
  610. $report['error']++;
  611. break;
  612. case 'inserted':
  613. $report['inserted'][] = $pub;
  614. break;
  615. case 'updated':
  616. $report['updated'][] = $pub;
  617. break;
  618. case 'skipped':
  619. $report['skipped'][] = $pub;
  620. break;
  621. }
  622. $i++;
  623. }
  624. print "\n";
  625. return $report;
  626. }
  627. /**
  628. * Returns the list of publications that are assigned the database
  629. * cross-reference provided
  630. *
  631. * @param $pub_dbxref
  632. * The database cross reference accession. It should be in the form
  633. * DB:ACCESSION, where DB is the database name and ACCESSION is the
  634. * unique publication identifier (e.g. PMID:4382934)
  635. *
  636. * @return
  637. * Returns an array of all the publications that have the provided
  638. * cross reference. If no publications match, then an empty array
  639. * is returned.
  640. *
  641. * @ingroup tripal_pub_api
  642. */
  643. function tripal_pub_get_pubs_by_dbxref($pub_dbxref) {
  644. $return = array();
  645. if(preg_match('/^(.*?):(.*?)$/', $pub_dbxref, $matches)) {
  646. $dbname = $matches[1];
  647. $accession = $matches[2];
  648. $values = array(
  649. 'dbxref_id' => array (
  650. 'accession' => $accession,
  651. 'db_id' => array(
  652. 'name' => $dbname
  653. ),
  654. ),
  655. );
  656. $options = array('statement_name' => 'sel_pubdbxref_db');
  657. $results = chado_select_record('pub_dbxref', array('pub_id'), $values, $options);
  658. foreach ($results as $index => $pub) {
  659. $return[] = $pub->pub_id;
  660. }
  661. }
  662. return $return;
  663. }
  664. /**
  665. * Returns the list of publications that match a given title, type and year
  666. *
  667. * @param title
  668. * The title of the publication to look for
  669. * @param type
  670. * Optional. The publication type. The value of this field should come from
  671. * the Tripal Pub vocabulary. This should be the type name (e.g. cvterm.name)
  672. * @param pyear
  673. * Optional. The year the publication was published.
  674. * @param series_name
  675. * Optional. The name of the series (e.g. Journal name)
  676. *
  677. * @return
  678. * Returns an array of all the publications that have the provided
  679. * cross reference. If no publications match, then an empty array
  680. * is returned.
  681. *
  682. * @ingroup tripal_pub_api
  683. */
  684. function tripal_pub_get_pubs_by_title_type_pyear_series($title, $type = NULL, $pyear = NULL, $series_name = NULL) {
  685. $return = array();
  686. // build the values array for the query.
  687. $values = array(
  688. 'title' => $title,
  689. );
  690. $stmnt_suffix = 'ti';
  691. if ($type) {
  692. $values['type_id'] = array(
  693. 'name' => $type,
  694. 'cv_id' => array(
  695. 'name' => 'tripal_pub'
  696. )
  697. );
  698. $stmnt_suffix .= 'ty';
  699. }
  700. if ($pyear) {
  701. $values['pyear'] = $pyear;
  702. $stmnt_suffix .= 'py';
  703. }
  704. if ($series_name) {
  705. $values['series_name'] = strtolower($series_name);
  706. $stmnt_suffix .= 'se';
  707. }
  708. $options = array(
  709. 'statement_name' => 'sel_pub_' . $stmnt_suffix,
  710. 'case_insensitive_columns' => array('title', 'series_name'),
  711. );
  712. $results = chado_select_record('pub', array('pub_id'), $values, $options);
  713. // iterate through any matches and pull out the pub_id
  714. foreach ($results as $index => $pub) {
  715. $return[] = $pub->pub_id;
  716. }
  717. return $return;
  718. }
  719. /**
  720. * Returns the list of publications that match a given title, type and year
  721. *
  722. * @param title
  723. * The title of the publication to look for
  724. * @param type
  725. * Optional. The publication type. The value of this field should come from
  726. * the Tripal Pub vocabulary. This should be the type name (e.g. cvterm.name)
  727. * @param year
  728. * Optional. The year the publication was published.
  729. * @param series_name
  730. * Optional. The name of the series (e.g. Journal name)
  731. *
  732. * @return
  733. * Returns an array of all the publications that have the provided
  734. * cross reference. If no publications match, then an empty array
  735. * is returned.
  736. *
  737. * @ingroup tripal_pub_api
  738. */
  739. function tripal_pub_get_pub_by_uniquename($name) {
  740. $return = array();
  741. // build the values array for the query.
  742. $values = array(
  743. 'uniquename' => $name,
  744. );
  745. $options = array(
  746. 'statement_name' => 'sel_pub_un',
  747. 'case_insensitive_columns' => array('uniquename'),
  748. );
  749. $results = chado_select_record('pub', array('pub_id'), $values, $options);
  750. // iterate through any matches and pull out the pub_id
  751. foreach ($results as $index => $pub) {
  752. $return[] = $pub->pub_id;
  753. }
  754. return $return;
  755. }
  756. /**
  757. * Adds a new publication to the Chado, along with all properties and
  758. * database cross-references. If the publication does not already exist
  759. * in Chado then it is added. If it does exist nothing is done. If
  760. * the $update parameter is TRUE then the publication is updated if it exists.
  761. *
  762. * @param $pub_details
  763. * An associative array containing all of the details about the publication.
  764. * @param $action
  765. * This variable will get set to a text value indicating the action that was
  766. * performed. The values include 'skipped', 'inserted', 'updated' or 'error'.
  767. * @param $do_contact
  768. * Optional. Set to TRUE if a contact entry should be added to the Chado contact table
  769. * for authors of the publication.
  770. * @param $update_if_exists
  771. * Optional. If the publication already exists then this function will return
  772. * without adding a new publication. However, set this value to TRUE to force
  773. * the function to pudate the publication using the $pub_details that are provided.
  774. *
  775. * @return
  776. * If the publication already exists, is inserted or updated then the publication
  777. * ID is returned, otherwise FALSE is returned. If the publication already exists
  778. * and $update_if_exists is not TRUE then the $action variable is set to 'skipped'.
  779. * If the publication already exists and $update_if_exists is TRUE and if the update
  780. * was successful then $action is set to 'updated'. Otherwise on successful insert
  781. * the $action variable is set to 'inserted'. If the function failes then the
  782. * $action variable is set to 'error'
  783. *
  784. * @ingroup tripal_pub_api
  785. */
  786. function tripal_pub_add_publication($pub_details, &$action, $do_contact = FALSE, $update_if_exists = FALSE) {
  787. $pub_id = 0;
  788. if (!is_array($pub_details)) {
  789. return FALSE;
  790. }
  791. // first try to find the publication using the accession number. It will have
  792. // one if the pub has already been loaded for the publication database
  793. if (array_key_exists('Publication Dbxref', $pub_details)) {
  794. $results = tripal_pub_get_pubs_by_dbxref($pub_details['Publication Dbxref']);
  795. if(count($results) == 1) {
  796. $pub_id = $results[0];
  797. if ($pub_id and !$update_if_exists) {
  798. //tripal_core_report_error('tripal_pub', TRIPAL_WARNING, "A publication with this Dbxref already exists... Skipping: %dbxref",
  799. //array('%dbxref' => $pub_details['Publication Dbxref']));
  800. $action = 'skipped';
  801. return $pub_id;
  802. }
  803. }
  804. elseif (count($results) > 1) {
  805. tripal_report_error('tripal_pub', TRIPAL_ERROR, "There are two publications with this accession: %db:%accession. Cannot determine which to update.",
  806. array('%db' => $dbname, '%accession' => $accession));
  807. $action = 'error';
  808. return FALSE;
  809. }
  810. }
  811. // if we couldn't find a publication by the accession (which means it doesn't
  812. // yet exist or it has been added using a different publication database) then
  813. // try to find it using the title and publication year.
  814. if (!$pub_id and array_key_exists('Title', $pub_details)) {
  815. $results = tripal_pub_get_pubs_by_title_type_pyear_series($pub_details['Title'], NULL, $pub_details['Year']);
  816. if (count($results) == 1) {
  817. $pub_id = $results[0];
  818. if ($pub_id and !$update_if_exists) {
  819. tripal_report_error('tripal_pub', TRIPAL_WARNING, "The publication with the same title, type and year already exists. Skipping. ".
  820. " Title: '%title'. Type: '%type'. Year: '%year'",
  821. array('%title' => $pub_details['Title'], '%type' => $pub_details['Publication Type'], '%year' => $pub_details['Year']));
  822. $action = 'skipped';
  823. return $pub_id;
  824. }
  825. }
  826. elseif (count($results) > 1) {
  827. tripal_report_error('tripal_pub', TRIPAL_ERROR, "The publication with the same title, type and year is present multiple times. Cannot ".
  828. "determine which to use. Title: '%title'. Type: '%type'. Year: '%year'",
  829. array('%title' => $pub_details['Title'], '%type' => $pub_details['Publication Type'], '%year' => $pub_details['Year']));
  830. $action = 'error';
  831. return FALSE;
  832. }
  833. }
  834. // get the publication type (use the first publication type, any others will get stored as properties)
  835. if (array_key_exists('Publication Type', $pub_details)) {
  836. if(is_array($pub_details['Publication Type'])) {
  837. $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'][0], NULL, 'tripal_pub');
  838. }
  839. else {
  840. $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'], NULL, 'tripal_pub');
  841. }
  842. }
  843. else {
  844. tripal_report_error('tripal_pub', TRIPAL_ERROR, "The Publication Type is a required property but is missing", array());
  845. $action = 'error';
  846. return FALSE;
  847. }
  848. if (!$pub_type) {
  849. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot find publication type: '%type'",
  850. array('%type' => $pub_details['Publication Type'][0]));
  851. $action = 'error';
  852. return FALSE;
  853. }
  854. // build the values array for inserting or updating
  855. $values = array(
  856. 'title' => $pub_details['Title'],
  857. 'volume' => $pub_details['Volume'],
  858. 'series_name' => substr($pub_details['Journal Name'], 0, 255),
  859. 'issue' => $pub_details['Issue'],
  860. 'pyear' => $pub_details['Year'],
  861. 'pages' => $pub_details['Pages'],
  862. 'uniquename' => $pub_details['Citation'],
  863. 'type_id' => $pub_type->cvterm_id,
  864. );
  865. // if there is no pub_id then we need to do an insert.
  866. if (!$pub_id) {
  867. $options = array('statement_name' => 'ins_pub_tivoseispypaunty');
  868. $pub = chado_insert_record('pub', $values, $options);
  869. if (!$pub) {
  870. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot insert the publication with title: %title",
  871. array('%title' => $pub_details['Title']));
  872. $action = 'error';
  873. return FALSE;
  874. }
  875. $pub_id = $pub['pub_id'];
  876. $action = 'inserted';
  877. }
  878. // if there is a pub_id and we've been told to update, then do the update
  879. if ($pub_id and $update_if_exists) {
  880. $match = array('pub_id' => $pub_id);
  881. $options = array('statement_name' => 'up_pub_tivoseispypaunty');
  882. $success = chado_update_record('pub', $match, $values, $options);
  883. if (!$success) {
  884. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot update the publication with title: %title",
  885. array('%title' => $pub_details['Title']));
  886. $action = 'error';
  887. return FALSE;
  888. }
  889. $action = 'updated';
  890. }
  891. // before we add any new properties we need to remove those that are there if this
  892. // is an update. The only thing we don't want to remove are the 'Publication Dbxref'
  893. if ($update_if_exists) {
  894. $sql = "
  895. DELETE FROM {pubprop}
  896. WHERE
  897. pub_id = :pub_id AND
  898. NOT type_id in (
  899. SELECT cvterm_id
  900. FROM {cvterm}
  901. WHERE name = 'Publication Dbxref'
  902. )
  903. ";
  904. chado_query($sql, array(':pub_id' => $pub_id));
  905. }
  906. // iterate through the properties and add them
  907. foreach ($pub_details as $key => $value) {
  908. // the pub_details may have the raw search data (e.g. in XML from PubMed. We'll irgnore this for now
  909. if($key == 'raw') {
  910. continue;
  911. }
  912. // get the cvterm by name or synonym
  913. $cvterm = tripal_cv_get_cvterm_by_name($key, NULL, 'tripal_pub');
  914. if (!$cvterm) {
  915. $cvterm = tripal_cv_get_cvterm_by_synonym($key, NULL, 'tripal_pub');
  916. }
  917. if (!$cvterm) {
  918. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot find term: '%prop'. Skipping.", array('%prop' => $key));
  919. continue;
  920. }
  921. // skip details that won't be stored as properties
  922. if ($key == 'Author List') {
  923. tripal_pub_add_authors($pub_id, $value, $do_contact);
  924. continue;
  925. }
  926. if ($key == 'Title' or $key == 'Volume' or $key == 'Journal Name' or $key == 'Issue' or
  927. $key == 'Year' or $key == 'Pages') {
  928. continue;
  929. }
  930. $success = 0;
  931. if (is_array($value)) {
  932. foreach ($value as $subkey => $subvalue) {
  933. // if the key is an integer then this array is a simple list and
  934. // we will insert using the primary key. Otheriwse, use the new key
  935. if(is_int($subkey)) {
  936. $success = chado_insert_property('pub', $pub_id, $key, 'tripal_pub', $subvalue, FALSE);
  937. }
  938. else {
  939. $success = chado_insert_property('pub', $pub_id, $subkey, 'tripal_pub', $subvalue, FALSE);
  940. }
  941. }
  942. }
  943. else {
  944. $success = chado_insert_property('pub', $pub_id, $key, 'tripal_pub', $value, TRUE);
  945. }
  946. if (!$success) {
  947. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot add property '%prop' to publication. Skipping.",
  948. array('%prop' => $key));
  949. continue;
  950. }
  951. }
  952. return $pub_id;
  953. }
  954. /**
  955. * Add one or more authors to a publication
  956. *
  957. * @param $pub_id
  958. * The publication ID of the pub in Chado.
  959. * @param $authors
  960. * An array of authors. Each author should have a set of keys/value pairs
  961. * describing the author.
  962. * @param $do_contact
  963. * Optional. Set to TRUE if a contact entry should be added to the Chado contact table
  964. * for authors of the publication.
  965. * @ingroup tripal_pub_api
  966. */
  967. function tripal_pub_add_authors($pub_id, $authors, $do_contact) {
  968. $rank = 0;
  969. // first remove any of the existing pubauthor entires
  970. $sql = "DELETE FROM {pubauthor} WHERE pub_id = :pub_id";
  971. chado_query($sql, array(':pub_id' => $pub_id));
  972. // iterate through the authors and add them to the pubauthors and contact
  973. // tables of chado, then link them through the custom pubauthors_contact table
  974. foreach ($authors as $author) {
  975. // skip invalid author entires
  976. if ($author['valid'] == 'N') {
  977. continue;
  978. }
  979. // remove the 'valid' property as we don't have a CV term for it
  980. unset($author['valid']);
  981. // construct the contact.name field using the author information
  982. $name = '';
  983. $type = 'Person';
  984. if ($author['Given Name']) {
  985. $name .= $author['Given Name'];
  986. }
  987. if ($author['Surname']) {
  988. $name .= ' ' . $author['Surname'];
  989. }
  990. if ($author['Suffix']) {
  991. $name .= ' ' . $author['Suffix'];
  992. }
  993. if ($author['Collective']) {
  994. $name = $author['Collective'];
  995. $type = 'Collective';
  996. }
  997. $name = trim($name);
  998. // add an entry to the pubauthors table
  999. $values = array(
  1000. 'pub_id' => $pub_id,
  1001. 'rank' => $rank,
  1002. 'surname' => $author['Surname'] ? substr($author['Surname'], 0, 100) : substr($author['Collective'], 0, 100),
  1003. 'givennames' => $author['Given Name'],
  1004. 'suffix' => $author['Suffix'],
  1005. );
  1006. $options = array('statement_name' => 'ins_pubauthor_idrasugisu');
  1007. $pubauthor = chado_insert_record('pubauthor', $values, $options);
  1008. // if the user wants us to create a contact for each author then do it.
  1009. if ($do_contact) {
  1010. // Add the contact
  1011. $contact = tripal_contact_add_contact($name, '', $type, $author);
  1012. // if we have succesfully added the contact and the pubauthor entries then we want to
  1013. // link them together
  1014. if ($contact and $pubauthor) {
  1015. // link the pubauthor entry to the contact
  1016. $values = array(
  1017. 'pubauthor_id' => $pubauthor['pubauthor_id'],
  1018. 'contact_id' => $contact['contact_id'],
  1019. );
  1020. $options = array('statement_name' => 'ins_pubauthorcontact_puco');
  1021. $pubauthor_contact = chado_insert_record('pubauthor_contact', $values, $options);
  1022. if (!$pubauthor_contact) {
  1023. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot link pub authro and contact.", array());
  1024. }
  1025. }
  1026. }
  1027. $rank++;
  1028. }
  1029. }
  1030. /**
  1031. * Retrieve properties of a given type for a given pub
  1032. *
  1033. * @param $pub_id
  1034. * The pub_id of the properties you would like to retrieve
  1035. * @param $property
  1036. * The cvterm name of the properties to retrieve
  1037. *
  1038. * @return
  1039. * An pub chado variable with the specified properties expanded
  1040. *
  1041. * @ingroup tripal_pub_api
  1042. */
  1043. function tripal_pub_get_property($pub_id, $property) {
  1044. return chado_get_property('pub', $pub_id, $property, 'tripal_pub');
  1045. }
  1046. /**
  1047. * Insert a given property
  1048. *
  1049. * @param $pub_id
  1050. * The pub_id of the property to insert
  1051. * @param $property
  1052. * The cvterm name of the property to insert
  1053. * @param $value
  1054. * The value of the property to insert
  1055. * @param $update_if_present
  1056. * A boolean indicated whether to update the record if it's already present
  1057. *
  1058. * @return
  1059. * True of success, False otherwise
  1060. *
  1061. * @ingroup tripal_pub_api
  1062. */
  1063. function tripal_pub_insert_property($pub_id, $property, $value, $update_if_present = 0) {
  1064. return chado_insert_property('pub', $pub_id, $property, 'tripal_pub', $value, $update_if_present);
  1065. }
  1066. /**
  1067. * Update a given property
  1068. *
  1069. * @param $pub_id
  1070. * The pub_id of the property to update
  1071. * @param $property
  1072. * The cvterm name of the property to update
  1073. * @param $value
  1074. * The value of the property to update
  1075. * @param $insert_if_missing
  1076. * A boolean indicated whether to insert the record if it's absent
  1077. *
  1078. * Note: The property will be identified using the unique combination of the $pub_id and $property
  1079. * and then it will be updated with the supplied value
  1080. *
  1081. * @return
  1082. * True of success, False otherwise
  1083. *
  1084. * @ingroup tripal_pub_api
  1085. */
  1086. function tripal_pub_update_property($pub_id, $property, $value, $insert_if_missing = 0) {
  1087. return chado_update_property('pub', $pub_id, $property, 'tripal_pub', $value, $insert_if_missing);
  1088. }
  1089. /**
  1090. * Delete a given property
  1091. *
  1092. * @param $pub_id
  1093. * The pub_id of the property to delete
  1094. * @param $property
  1095. * The cvterm name of the property to delete
  1096. *
  1097. * Note: The property will be identified using the unique combination of the $pub_id and $property
  1098. * and then it will be deleted
  1099. *
  1100. * @return
  1101. * True of success, False otherwise
  1102. *
  1103. * @ingroup tripal_pub_api
  1104. */
  1105. function tripal_pub_delete_property($pub_id, $property) {
  1106. return chado_delete_property('pub', $pub_id, $property, 'tripal_pub');
  1107. }
  1108. /**
  1109. * This function generates an array suitable for use with the
  1110. * tripal_pub_create_citation function for any publication
  1111. * already stored in the Chado tables.
  1112. *
  1113. * @param $pub_id
  1114. * The publication ID
  1115. * @param $skip_existing
  1116. * Set to TRUE to skip publications that already have a citation
  1117. * in the pubprop table. Set to FALSE to generate a citation
  1118. * regardless if the citation already exists.
  1119. *
  1120. * @return
  1121. * An array suitable for the trpial_pub_create_citation function. On
  1122. * failure returns FALSE.
  1123. *
  1124. * @ingroup tripal_pub_api
  1125. */
  1126. function tripal_pub_get_publication_array($pub_id, $skip_existing = TRUE) {
  1127. $options = array('return_array' => 1);
  1128. // ---------------------------------
  1129. // get the publication
  1130. // ---------------------------------
  1131. $values = array('pub_id' => $pub_id);
  1132. $pub = chado_generate_var('pub', $values);
  1133. // expand the title
  1134. $pub = chado_expand_var($pub, 'field', 'pub.title');
  1135. $pub = chado_expand_var($pub, 'field', 'pub.volumetitle');
  1136. $pub = chado_expand_var($pub, 'field', 'pub.uniquename');
  1137. $pub_array = array();
  1138. if (trim($pub->title)) {
  1139. $pub_array['Title'] = $pub->title;
  1140. }
  1141. if (trim($pub->volumetitle)) {
  1142. $pub_array['Volume Title'] = $pub->volumetitle;
  1143. }
  1144. if (trim($pub->volume)) {
  1145. $pub_array['Volume'] = $pub->volume;
  1146. }
  1147. if (trim($pub->series_name)) {
  1148. $pub_array['Series Name'] = $pub->series_name;
  1149. }
  1150. if (trim($pub->issue)) {
  1151. $pub_array['Issue'] = $pub->issue;
  1152. }
  1153. if (trim($pub->pyear)) {
  1154. $pub_array['Year'] = $pub->pyear;
  1155. }
  1156. if (trim($pub->pages)) {
  1157. $pub_array['Pages'] = $pub->pages;
  1158. }
  1159. if (trim($pub->miniref)) {
  1160. $pub_array['Mini Ref'] = $pub->miniref;
  1161. }
  1162. if (trim($pub->uniquename)) {
  1163. $pub_array['Uniquename'] = $pub->uniquename;
  1164. }
  1165. $pub_array['Publication Type'][] = $pub->type_id->name;
  1166. // ---------------------------------
  1167. // get the citation
  1168. // ---------------------------------
  1169. $values = array(
  1170. 'pub_id' => $pub->pub_id,
  1171. 'type_id' => array(
  1172. 'name' => 'Citation',
  1173. ),
  1174. );
  1175. $citation = chado_generate_var('pubprop', $values);
  1176. if ($citation) {
  1177. $citation = chado_expand_var($citation, 'field', 'pubprop.value', $options);
  1178. if (count($citation) > 1) {
  1179. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Publication has multiple citations already: %pub_id",
  1180. array('%pub_id' => $pubid));
  1181. return FALSE;
  1182. }
  1183. elseif (count($citation) == 1 and $skip_existing == TRUE) {
  1184. // skip this publication, it already has a citation
  1185. return FALSE;
  1186. }
  1187. }
  1188. // ---------------------------------
  1189. // get the publication types
  1190. // ---------------------------------
  1191. $values = array(
  1192. 'pub_id' => $pub->pub_id,
  1193. 'type_id' => array(
  1194. 'name' => 'Publication Type',
  1195. ),
  1196. );
  1197. $ptypes = chado_generate_var('pubprop', $values, $options);
  1198. if ($ptypes) {
  1199. $ptypes = chado_expand_var($ptypes, 'field', 'pubprop.value', $options);
  1200. foreach ($ptypes as $ptype) {
  1201. $pub_array['Publication Type'][] = $ptype->value;
  1202. }
  1203. }
  1204. // ---------------------------------
  1205. // get the authors list
  1206. // ---------------------------------
  1207. $values = array(
  1208. 'pub_id' => $pub->pub_id,
  1209. 'type_id' => array(
  1210. 'name' => 'Authors',
  1211. ),
  1212. );
  1213. $authors = chado_generate_var('pubprop', $values);
  1214. $authors = chado_expand_var($authors, 'field', 'pubprop.value', $options);
  1215. if (count($authors) > 1) {
  1216. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Publication has multiple author lists. It should have only one list: %pub_id",
  1217. array('%pub_id' => $pubid));
  1218. return FALSE;
  1219. }
  1220. else if (trim($authors->value)) {
  1221. $pub_array['Authors'] = $authors->value;
  1222. }
  1223. // if there is no 'Author's property then try to retreive authors from the pubauthor table
  1224. else {
  1225. $sql = "
  1226. SELECT string_agg(surname || ' ' || givennames, ', ')
  1227. FROM {pubauthor}
  1228. WHERE pub_id = :pub_id
  1229. GROUP BY pub_id
  1230. ";
  1231. $au = chado_query($sql, array(':pub_id' => $pub_id))->fetchField();
  1232. if ($au) {
  1233. $pub_array['Authors'] = $au;
  1234. }
  1235. }
  1236. //Get other props
  1237. $props = array(
  1238. 'Journal Abbreviation',
  1239. 'Elocation',
  1240. 'Media Code',
  1241. 'Conference Name',
  1242. 'Keywords',
  1243. 'Series Name',
  1244. 'pISSN',
  1245. 'Publication Date',
  1246. 'Journal Code',
  1247. 'Journal Alias',
  1248. 'Journal Country',
  1249. 'Published Location',
  1250. 'Publication Model',
  1251. 'Language Abbr',
  1252. 'Alias',
  1253. 'Publication Dbxref',
  1254. 'Copyright',
  1255. 'Abstract',
  1256. 'Notes',
  1257. 'Citation',
  1258. 'Language',
  1259. 'URL',
  1260. 'eISSN',
  1261. 'DOI',
  1262. 'ISSN',
  1263. 'Publication Code',
  1264. 'Comments',
  1265. 'Publisher',
  1266. 'Media Alias',
  1267. 'Original Title');
  1268. foreach ($props AS $prop) {
  1269. $sql =
  1270. "SELECT value FROM {pubprop}
  1271. WHERE type_id =
  1272. (SELECT cvterm_id
  1273. FROM {cvterm}
  1274. WHERE name = :cvtname AND cv_id =
  1275. (SELECT cv_id
  1276. FROM {cv}
  1277. WHERE name = 'tripal_pub'
  1278. )
  1279. )
  1280. AND pub_id = :pub_id
  1281. ";
  1282. $val = trim(chado_query($sql, array(':cvtname' => $prop, ':pub_id' => $pub->pub_id))->fetchField());
  1283. if ($val) {
  1284. $pub_array[$prop] =$val;
  1285. }
  1286. }
  1287. return $pub_array;
  1288. }
  1289. /**
  1290. * This function generates citations for publications. It requires
  1291. * an array structure with keys being the terms in the Tripal
  1292. * publication ontology. This function is intended to be used
  1293. * for any function that needs to generate a citation.
  1294. *
  1295. * @param $pub
  1296. * An array structure containing publication details where the keys
  1297. * are the publication ontology term names and values are the
  1298. * corresponding details. The pub array can contain the following
  1299. * keys with corresponding values:
  1300. * - Publication Type: an array of publication types. a publication can have more than one type
  1301. * - Authors: a string containing all of the authors of a publication
  1302. * - Journal Name: a string containing the journal name
  1303. * - Journal Abbreviation: a string containing the journal name abbreviation
  1304. * - Series Name: a string containing the series (e.g. conference proceedings) name
  1305. * - Series Abbreviation: a string containing the series name abbreviation
  1306. * - Volume: the serives volume number
  1307. * - Issue: the series issue number
  1308. * - Pages: the page numbers for the publication
  1309. * - Publication Date: A date in the format "Year Month Day"
  1310. *
  1311. * @return
  1312. * A text string containing the citation
  1313. *
  1314. * @ingroup tripal_pub_api
  1315. */
  1316. function tripal_pub_create_citation($pub) {
  1317. $citation = '';
  1318. $pub_type = '';
  1319. // An article may have more than one publication type. For example,
  1320. // a publication type can be 'Journal Article' but also a 'Clinical Trial'.
  1321. // Therefore, we need to select the type that makes most sense for
  1322. // construction of the citation. Here we'll iterate through them all
  1323. // and select the one that matches best.
  1324. if(is_array($pub['Publication Type'])) {
  1325. foreach ($pub['Publication Type'] as $ptype) {
  1326. if ($ptype == 'Journal Article' ) {
  1327. $pub_type = $ptype;
  1328. break;
  1329. }
  1330. else if ($ptype == 'Conference Proceedings'){
  1331. $pub_type = $ptype;
  1332. break;
  1333. }
  1334. else if ($ptype == 'Book') {
  1335. $pub_type = $ptype;
  1336. break;
  1337. }
  1338. else if ($ptype == 'Letter') {
  1339. $pub_type = $ptype;
  1340. break;
  1341. }
  1342. else if ($ptype == 'Book Chapter') {
  1343. $pub_type = $ptype;
  1344. break;
  1345. }
  1346. else if ($ptype == "Research Support, Non-U.S. Gov't") {
  1347. $pub_type = $ptype;
  1348. // we don't break because if the article is also a Journal Article
  1349. // we prefer that type
  1350. }
  1351. }
  1352. if (!$pub_type) {
  1353. tripal_report_error('tripal_pub', TRIPAL_ERROR, "Cannot generate citation for publication type: %types",
  1354. array('%types' => print_r($pub['Publication Type'], TRUE)));
  1355. return FALSE;
  1356. }
  1357. }
  1358. else {
  1359. $pub_type = $pub['Publication Type'];
  1360. }
  1361. //----------------------
  1362. // Journal Article
  1363. //----------------------
  1364. if ($pub_type == 'Journal Article') {
  1365. $citation = $pub['Authors'] . '. ' . $pub['Title'] . '. ';
  1366. if (array_key_exists('Journal Name', $pub)) {
  1367. $citation .= $pub['Journal Name'] . '. ';
  1368. }
  1369. elseif (array_key_exists('Journal Abbreviation', $pub)) {
  1370. $citation .= $pub['Journal Abbreviation'] . '. ';
  1371. }
  1372. elseif (array_key_exists('Series Name', $pub)) {
  1373. $citation .= $pub['Series Name'] . '. ';
  1374. }
  1375. elseif (array_key_exists('Series Abbreviation', $pub)) {
  1376. $citation .= $pub['Series Abbreviation'] . '. ';
  1377. }
  1378. if (array_key_exists('Publication Date', $pub)) {
  1379. $citation .= $pub['Publication Date'];
  1380. }
  1381. elseif (array_key_exists('Year', $pub)) {
  1382. $citation .= $pub['Year'];
  1383. }
  1384. if (array_key_exists('Volume', $pub) or array_key_exists('Issue', $pub) or array_key_exists('Pages',$pub)) {
  1385. $citation .= '; ';
  1386. }
  1387. if (array_key_exists('Volume', $pub)) {
  1388. $citation .= $pub['Volume'];
  1389. }
  1390. if (array_key_exists('Issue', $pub)) {
  1391. $citation .= '(' . $pub['Issue'] . ')';
  1392. }
  1393. if (array_key_exists('Pages', $pub)) {
  1394. if (array_key_exists('Volume', $pub)) {
  1395. $citation .= ':';
  1396. }
  1397. $citation .= $pub['Pages'];
  1398. }
  1399. $citation .= '.';
  1400. }
  1401. //----------------------
  1402. // Research Support, Non-U.S. Gov't
  1403. //----------------------
  1404. elseif ($pub_type == "Research Support, Non-U.S. Gov't") {
  1405. $citation = $pub['Authors'] . '. ' . $pub['Title'] . '. ';
  1406. if (array_key_exists('Journal Name', $pub)) {
  1407. $citation .= $pub['Journal Name'] . '. ';
  1408. }
  1409. if (array_key_exists('Publication Date', $pub)) {
  1410. $citation .= $pub['Publication Date'];
  1411. }
  1412. elseif (array_key_exists('Year', $pub)) {
  1413. $citation .= $pub['Year'];
  1414. }
  1415. $citation .= '.';
  1416. }
  1417. //----------------------
  1418. // Letter
  1419. //----------------------
  1420. elseif ($pub_type == 'Letter') {
  1421. $citation = $pub['Authors'] . '. ' . $pub['Title'] . '. ';
  1422. if (array_key_exists('Journal Name', $pub)) {
  1423. $citation .= $pub['Journal Name'] . '. ';
  1424. }
  1425. elseif (array_key_exists('Journal Abbreviation', $pub)) {
  1426. $citation .= $pub['Journal Abbreviation'] . '. ';
  1427. }
  1428. elseif (array_key_exists('Series Name', $pub)) {
  1429. $citation .= $pub['Series Name'] . '. ';
  1430. }
  1431. elseif (array_key_exists('Series Abbreviation', $pub)) {
  1432. $citation .= $pub['Series Abbreviation'] . '. ';
  1433. }
  1434. if (array_key_exists('Publication Date', $pub)) {
  1435. $citation .= $pub['Publication Date'];
  1436. }
  1437. elseif (array_key_exists('Year', $pub)) {
  1438. $citation .= $pub['Year'];
  1439. }
  1440. if (array_key_exists('Volume', $pub) or array_key_exists('Issue', $pub) or array_key_exists('Pages',$pub)) {
  1441. $citation .= '; ';
  1442. }
  1443. if (array_key_exists('Volume', $pub)) {
  1444. $citation .= $pub['Volume'];
  1445. }
  1446. if (array_key_exists('Issue', $pub)) {
  1447. $citation .= '(' . $pub['Issue'] . ')';
  1448. }
  1449. if (array_key_exists('Pages', $pub)) {
  1450. if (array_key_exists('Volume', $pub)) {
  1451. $citation .= ':';
  1452. }
  1453. $citation .= $pub['Pages'];
  1454. }
  1455. $citation .= '.';
  1456. }
  1457. //----------------------
  1458. // Book
  1459. //----------------------
  1460. elseif ($pub_type == 'Book') {
  1461. }
  1462. //----------------------
  1463. // Book Chapter
  1464. //----------------------
  1465. elseif ($pub_type == 'Book Chapter') {
  1466. }
  1467. //----------------------
  1468. // Conference Proceedings
  1469. //----------------------
  1470. elseif ($pub_type == 'Conference Proceedings') {
  1471. $citation = $pub['Authors'] . '. ' . $pub['Title'] . '. ';
  1472. if (array_key_exists('Conference Name', $pub)) {
  1473. $citation .= $pub['Conference Name'] . '. ';
  1474. }
  1475. elseif (array_key_exists('Series Name', $pub)) {
  1476. $citation .= $pub['Series Name'] . '. ';
  1477. }
  1478. elseif (array_key_exists('Series Abbreviation', $pub)) {
  1479. $citation .= $pub['Series Abbreviation'] . '. ';
  1480. }
  1481. if (array_key_exists('Publication Date', $pub)) {
  1482. $citation .= $pub['Publication Date'];
  1483. }
  1484. elseif (array_key_exists('Year', $pub)) {
  1485. $citation .= $pub['Year'];
  1486. }
  1487. if (array_key_exists('Volume', $pub) or array_key_exists('Issue', $pub) or array_key_exists('Pages',$pub)) {
  1488. $citation .= '; ';
  1489. }
  1490. if (array_key_exists('Volume', $pub)) {
  1491. $citation .= $pub['Volume'];
  1492. }
  1493. if (array_key_exists('Issue', $pub)) {
  1494. $citation .= '(' . $pub['Issue'] . ')';
  1495. }
  1496. if (array_key_exists('Pages', $pub)) {
  1497. if (array_key_exists('Volume', $pub)) {
  1498. $citation .= ':';
  1499. }
  1500. $citation .= $pub['Pages'];
  1501. }
  1502. $citation .= '.';
  1503. }
  1504. return $citation;
  1505. }