tripal_stock.module 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. <?php
  2. /**
  3. * @file
  4. * Implements Tripal Stock Module hooks
  5. */
  6. /**
  7. * @defgroup tripal_stock Stock Module
  8. * @ingroup tripal_modules
  9. * @{
  10. * Provides functions for managing chado stocks including creating details pages for each stock
  11. *
  12. * The Tripal Stock Module provides functionality for adding, editing, deleting and accessing chado
  13. * stocks. The stock module was designed to store information about stock collections in a
  14. * laboratory. What is called a stock could also be called a strain or an accession. There is a lot
  15. * in common between a Drosophila stock and a Saccharomyces strain and an Arabidopsis line. They all
  16. * come from some taxon, have genotypes, physical locations in the lab, some conceivable
  17. * relationship with a publication, some conceivable relationship with a sequence feature (such as a
  18. * transgene), and could be described by some ontology term. For more information about the chado
  19. * Stock Module see the GMOD Wiki Page (http://gmod.org/wiki/Chado_Stock_Module)
  20. * @}
  21. */
  22. require_once("includes/tripal_stock.admin.inc");
  23. require_once("includes/tripal_stock.sync_stocks.inc");
  24. require_once("includes/other_module_api_functions.inc");
  25. require_once("includes/tripal_stock-secondary_tables.inc");
  26. require_once("includes/tripal_stock-properties.inc");
  27. require_once("includes/tripal_stock-relationships.inc");
  28. require_once("includes/tripal_stock-db_references.inc");
  29. require_once("api/tripal_stock.api.inc");
  30. /**
  31. * Implements hook_menu(): Adds menu items for the tripal_stock
  32. *
  33. * @return
  34. * Menu definitions for the tripal_stock
  35. *
  36. * @ingroup tripal_stock
  37. */
  38. function tripal_stock_menu() {
  39. $items = array();
  40. //Administrative settings menu-----------------
  41. $items['admin/tripal/tripal_stock'] = array(
  42. 'title' => 'Stocks',
  43. 'description' => 'Basic Description of Tripal Stock Module Functionality',
  44. 'page callback' => 'theme',
  45. 'page arguments' => array('tripal_stock_admin'),
  46. 'access arguments' => array('administer tripal stocks'),
  47. 'type' => MENU_NORMAL_ITEM
  48. );
  49. $items['admin/tripal/tripal_stock/configuration'] = array(
  50. 'title' => 'Configuration',
  51. 'description' => 'Settings for Chado Stocks',
  52. 'page callback' => 'drupal_get_form',
  53. 'page arguments' => array('tripal_stock_admin'),
  54. 'access arguments' => array('administer tripal stocks'),
  55. 'type' => MENU_NORMAL_ITEM
  56. );
  57. $items['admin/tripal/tripal_stock/sync'] = array(
  58. 'title' => ' Sync Stocks',
  59. 'description' => 'Sync stocks from Chado with Drupal',
  60. 'page callback' => 'drupal_get_form',
  61. 'page arguments' => array('tripal_stock_sync_form'),
  62. 'access arguments' => array('administer tripal stocks'),
  63. 'type' => MENU_NORMAL_ITEM,
  64. );
  65. // Adding Secondary Properties-----------------
  66. $items['node/%cs_node/properties'] = array(
  67. 'title' => 'Add Properties & Synonyms',
  68. 'description' => 'Settings for Chado Stocks',
  69. 'page callback' => 'tripal_stock_add_ALL_property_page',
  70. 'page arguments' => array(1),
  71. 'access arguments' => array('create chado_stock content'),
  72. 'type' => MENU_CALLBACK
  73. );
  74. $items['node/%cs_node/db_references'] = array(
  75. 'title' => 'Add Database References',
  76. 'description' => 'Settings for Chado Stocks',
  77. 'page callback' => 'tripal_stock_add_ALL_dbreferences_page',
  78. 'page arguments' => array(1),
  79. 'access arguments' => array('create chado_stock content'),
  80. 'type' => MENU_CALLBACK
  81. );
  82. $items['node/%cs_node/relationships'] = array(
  83. 'title' => 'Add Relationships',
  84. 'description' => 'Settings for Chado Stocks',
  85. 'page callback' => 'tripal_stock_add_ALL_relationships_page',
  86. 'page arguments' => array(1),
  87. 'access arguments' => array('create chado_stock content'),
  88. 'type' => MENU_CALLBACK
  89. );
  90. //Edit/Deleting Secondary Properties-------------
  91. $items['node/%cs_node/edit_properties'] = array(
  92. 'title' => 'Edit Properties',
  93. 'description' => 'Settings for Chado Stocks',
  94. 'page callback' => 'tripal_stock_edit_ALL_properties_page',
  95. 'page arguments' => array(1),
  96. 'access arguments' => array('edit chado_stock content'),
  97. 'type' => MENU_LOCAL_TASK,
  98. 'weight' => 8,
  99. );
  100. $items['node/%cs_node/edit_relationships'] = array(
  101. 'title' => 'Edit Relationships',
  102. 'description' => 'Settings for Chado Stocks',
  103. 'page callback' => 'tripal_stock_edit_ALL_relationships_page',
  104. 'page arguments' => array(1),
  105. 'access arguments' => array('edit chado_stock content'),
  106. 'type' => MENU_LOCAL_TASK,
  107. 'weight' => 9,
  108. );
  109. $items['node/%cs_node/edit_db_references'] = array(
  110. 'title' => 'Edit DB References',
  111. 'description' => 'Settings for Chado Stocks',
  112. 'page callback' => 'tripal_stock_edit_ALL_dbreferences_page',
  113. 'page arguments' => array(1),
  114. 'access arguments' => array('edit chado_stock content'),
  115. 'type' => MENU_LOCAL_TASK,
  116. 'weight' => 10,
  117. );
  118. return $items;
  119. }
  120. /**
  121. * Implements Menu wildcard_load hook
  122. *
  123. * Purpose: Allows the node ID of a chado stock to be dynamically
  124. * pulled from the path. The node is loaded from this node ID
  125. * and supplied to the page as an arguement. This is an example
  126. * of dynamic argument replacement using wildcards in the path.
  127. *
  128. * @param $nid
  129. * The node ID passed in from the path
  130. *
  131. * @return
  132. * The node object with the passed in nid
  133. *
  134. * @ingroup tripal_stock
  135. */
  136. function cs_node_load($nid) {
  137. if (is_numeric($nid)) {
  138. $node = node_load($nid);
  139. if ($node->type == 'chado_stock') {
  140. return $node;
  141. }
  142. }
  143. return FALSE;
  144. }
  145. /**
  146. * Implementation of hook_perm().
  147. *
  148. * Purpose: Set the permission types that the chado stock module uses
  149. *
  150. * @return
  151. * Listing of the possible permission catagories
  152. *
  153. * @ingroup tripal_stock
  154. */
  155. function tripal_stock_perm() {
  156. return array(
  157. 'access chado_stock content',
  158. 'create chado_stock content',
  159. 'edit chado_stock content',
  160. 'delete chado_stock content',
  161. 'administer tripal stocks',
  162. );
  163. }
  164. /**
  165. * Implement hook_access().
  166. *
  167. * This hook allows node modules to limit access to the node types they define.
  168. *
  169. * @param $op
  170. * The operation to be performed
  171. *
  172. * @param $node
  173. * The node on which the operation is to be performed, or, if it does not yet exist, the
  174. * type of node to be created
  175. *
  176. * @param $account
  177. * A user object representing the user for whom the operation is to be performed
  178. *
  179. * @return
  180. * If the permission for the specified operation is not set then return FALSE. If the
  181. * permission is set then return NULL as this allows other modules to disable
  182. * access. The only exception is when the $op == 'create'. We will always
  183. * return TRUE if the permission is set.
  184. *
  185. * @ingroup tripal_stock
  186. */
  187. function chado_stock_access($op, $node, $account) {
  188. if ($op == 'create') {
  189. if (!user_access('create chado_stock content', $account)) {
  190. return FALSE;
  191. }
  192. return TRUE;
  193. }
  194. if ($op == 'update') {
  195. if (!user_access('edit chado_stock content', $account)) {
  196. return FALSE;
  197. }
  198. }
  199. if ($op == 'delete') {
  200. if (!user_access('delete chado_stock content', $account)) {
  201. return FALSE;
  202. }
  203. }
  204. if ($op == 'view') {
  205. if (!user_access('access chado_stock content', $account)) {
  206. return FALSE;
  207. }
  208. }
  209. return NULL;
  210. }
  211. /**
  212. * Implements hook_views_api()
  213. *
  214. * Purpose: Essentially this hook tells drupal that there is views support for
  215. * for this module which then includes tripal_stock.views.inc where all the
  216. * views integration code is
  217. *
  218. * @return
  219. * An array with fields important for views integration
  220. *
  221. * @ingroup tripal_stock
  222. */
  223. function tripal_stock_views_api() {
  224. return array(
  225. 'api' => 2.0,
  226. );
  227. }
  228. /**
  229. * Implements hook_theme(): Register themeing functions for this module
  230. *
  231. * @return
  232. * An array of themeing functions to register
  233. *
  234. * @ingroup tripal_stock
  235. */
  236. function tripal_stock_theme() {
  237. return array(
  238. // Property edit forms--------------------------
  239. 'tripal_stock_edit_ALL_properties_form' => array(
  240. 'arguments' => array('form'),
  241. 'function' => 'theme_tripal_stock_edit_ALL_properties_form',
  242. ),
  243. 'tripal_stock_edit_ALL_db_references_form' => array(
  244. 'arguments' => array('form'),
  245. 'function' => 'theme_tripal_stock_edit_ALL_db_references_form',
  246. ),
  247. 'tripal_stock_edit_ALL_relationships_form' => array(
  248. 'arguments' => array('form'),
  249. 'function' => 'theme_tripal_stock_edit_ALL_relationships_form',
  250. ),
  251. // Block Templates------------------------------
  252. 'tripal_stock_base' => array(
  253. 'arguments' => array('node' => NULL),
  254. 'template' => 'tripal_stock_base',
  255. ),
  256. 'tripal_stock_properties' => array(
  257. 'arguments' => array('node' => NULL),
  258. 'template' => 'tripal_stock_properties',
  259. ),
  260. 'tripal_stock_references' => array(
  261. 'arguments' => array('node' => NULL),
  262. 'template' => 'tripal_stock_references',
  263. ),
  264. 'tripal_stock_relationships' => array(
  265. 'arguments' => array('node' => NULL),
  266. 'template' => 'tripal_stock_relationships',
  267. ),
  268. 'tripal_stock_synonyms' => array(
  269. 'arguments' => array('node' => NULL),
  270. 'template' => 'tripal_stock_synonyms',
  271. ),
  272. 'tripal_stock_collections' => array(
  273. 'arguments' => array('node' => NULL),
  274. 'template' => 'tripal_stock_collections',
  275. ),
  276. 'tripal_stock_collections' => array(
  277. 'arguments' => array('node' => NULL),
  278. 'template' => 'tripal_stock_collections',
  279. ),
  280. 'tripal_stock_phenotypes' => array(
  281. 'arguments' => array('node' => NULL),
  282. 'template' => 'tripal_stock_phenotypes',
  283. ),
  284. 'tripal_stock_locations' => array(
  285. 'arguments' => array('node' => NULL),
  286. 'template' => 'tripal_stock_locations',
  287. ),
  288. 'tripal_organism_stocks' => array(
  289. 'arguments' => array('node' => NULL),
  290. 'template' => 'tripal_organism_stocks',
  291. ),
  292. 'tripal_stock_admin' => array(
  293. 'template' => 'tripal_stock_admin',
  294. 'arguments' => array(NULL),
  295. 'path' => drupal_get_path('module', 'tripal_stock') . '/theme',
  296. ),
  297. );
  298. }
  299. /**
  300. * Implements hook_node_info(): registers a stock node type
  301. *
  302. * @return
  303. * An array describing various details of the node
  304. *
  305. * @ingroup tripal_stock
  306. */
  307. function tripal_stock_node_info() {
  308. return array(
  309. 'chado_stock' => array(
  310. 'name' => t('Stock'),
  311. 'module' => 'chado_stock',
  312. 'description' => t('A Chado Stock is a collection of material that can be sampled and have experiments performed on it.'),
  313. 'has_title' => TRUE,
  314. 'has_body' => FALSE,
  315. ),
  316. );
  317. }
  318. /**
  319. * Implements hook_load(): Prepares the chado_stock node
  320. *
  321. * @param $node
  322. * The basic node containing all variables common to all nodes
  323. *
  324. * @return
  325. * A stock node containing all the variables from the basic node and all stock specific variables
  326. *
  327. * @ingroup tripal_stock
  328. */
  329. function chado_stock_load($node) {
  330. // get the stock details from chado
  331. $stock_id = chado_get_id_for_node('stock', $node);
  332. // build the variable with all the stock details
  333. $values = array('stock_id' => $stock_id);
  334. $stock = tripal_core_generate_chado_var('stock', $values);
  335. // by default, the titles are saved using the unique constraint. We will
  336. // keep it the same, but remove the duplicate name if the unique name and name
  337. // are identical
  338. $title_type = variable_get('chado_stock_title', 'unique_constraint');
  339. if($title_type == 'unique_constraint') {
  340. if (strcmp($stock->name, $stock->uniquename)==0) {
  341. $node->title = $stock->name . " (" . $stock->type_id->name . ") " . $stock->organism_id->genus . " " . $stock->organism_id->species ;
  342. }
  343. // in previous version of Tripal, the stock title was simply the unique name.
  344. // so, we recreate the title just to be sure all of our stock pages are consistent
  345. else {
  346. $node->title = $stock->name . ", " . $stock->uniquename . " (" . $stock->type_id->name . ") " . $stock->organism_id->genus . " " . $stock->organism_id->species ;
  347. }
  348. }
  349. // set the title to be the stock name or uniquename as configured
  350. if($title_type == 'stock_name') {
  351. $node->title = $stock->name;
  352. }
  353. if($title_type == 'stock_unique_name') {
  354. $node->title = $stock->uniquename;
  355. }
  356. // add this to the node
  357. $additions = new stdClass();
  358. $additions->stock = $stock;
  359. return $additions;
  360. }
  361. /**
  362. * Implements hook_form(): Creates the main Add/Edit/Delete Form for chado stocks
  363. *
  364. * Parts to be added by this form
  365. * name,
  366. * uniquename,
  367. * description,
  368. * type => select from cvterm with key cvterm_id,
  369. * organism => select from available with key organism_id
  370. * main_db_reference => accession, version, description, db_name(select from dropdown)
  371. *
  372. * @param $node
  373. * An empty node object on insert OR the current stock node object on update
  374. * @param $form_state
  375. * The current state of the form
  376. *
  377. * @return
  378. * A description of the form to be rendered by drupal_get_form()
  379. *
  380. * @ingroup tripal_stock
  381. */
  382. function chado_stock_form($node, $form_state) {
  383. // Expand all fields needed
  384. $fields_needed = array('stock.uniquename', 'stock.name', 'stock.stock_id', 'stock.type_id', 'stock.organism_id', 'stock.description', 'stock.dbxref_id', 'dbxref.accession', 'dbxref.description', 'dbxref.db_id', 'db.db_id');
  385. foreach ($fields_needed as $field_name) {
  386. // Check to see if it's excluded and expand it if so
  387. if ($node->expandable_fields) {
  388. if (in_array($field_name, $node->expandable_fields)) {
  389. $node = tripal_core_expand_chado_vars($node, 'field', $field_name);
  390. }
  391. }
  392. }
  393. // This defines the path for the next step in a simulated multipart form
  394. // NOTE: The %node gets replaced with the nid in insert
  395. $form['next_step_path'] = array(
  396. '#type' => 'hidden',
  397. '#value' => 'node/%node/properties'
  398. );
  399. // If you don't want a multipart form set this to false
  400. // Will then do default redirect (to new node) on submit
  401. $form['simulate_multipart'] = array(
  402. '#type' => 'textfield',
  403. '#attributes' => array('style' => "display:none"),
  404. '#default_value' => TRUE
  405. );
  406. if (!isset($node->stock->uniquename)) {
  407. $form['progress'] = array(
  408. '#type' => 'item',
  409. '#value' => tripal_stock_add_chado_properties_progress('main')
  410. );
  411. }
  412. $form['names'] = array(
  413. '#type' => 'fieldset',
  414. '#title' => t('Stock Name')
  415. );
  416. $form['names']['sname'] = array(
  417. '#type' => 'textfield',
  418. '#title' => t('Name'),
  419. '#default_value' => $node->stock->name,
  420. '#required' => TRUE
  421. );
  422. $form['names']['uniquename'] = array(
  423. '#type' => 'textfield',
  424. '#title' => t('Unique Name'),
  425. '#default_value' => $node->stock->uniquename,
  426. '#required' => TRUE
  427. );
  428. $form['names']['stock_id'] = array(
  429. '#type' => 'hidden',
  430. '#value' => $node->stock->stock_id
  431. );
  432. $form['details'] = array(
  433. '#type' => 'fieldset',
  434. '#title' => t('Stock Details')
  435. );
  436. $type_options = tripal_cv_get_cvterm_options( variable_get('chado_stock_types_cv', 'NULL') );
  437. $type_options[0] = 'Select a Type';
  438. if ($node->nid == '') {
  439. $type_default = 0;
  440. }
  441. else {
  442. $type_default = $node->stock->type_id->cvterm_id;
  443. }
  444. $form['details']['type_id'] = array(
  445. '#type' => 'select',
  446. '#title' => t('Type of Stock'),
  447. '#options' => $type_options,
  448. '#default_value' => $type_default,
  449. '#required' => TRUE,
  450. );
  451. // get the list of organisms
  452. $sql = "SELECT * FROM {Organism} ORDER BY genus, species";
  453. $org_rset = chado_query($sql);
  454. $organisms = array();
  455. $organisms[''] = '';
  456. while ($organism = db_fetch_object($org_rset)) {
  457. $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
  458. }
  459. $form['details']['organism_id'] = array(
  460. '#type' => 'select',
  461. '#title' => t('Source Organism for stock'),
  462. '#default_value' => $node->stock->organism_id->organism_id,
  463. '#options' => $organisms,
  464. '#required' => TRUE
  465. );
  466. $form['details']['stock_description'] = array(
  467. '#type' => 'textarea',
  468. '#title' => t('Notes'),
  469. '#default_value' => $node->stock->description,
  470. '#description' => t('Briefly enter any notes on the above stock. This should not include phenotypes or genotypes.'),
  471. );
  472. $form['database_reference'] = array(
  473. '#type' => 'fieldset',
  474. '#title' => t('Stock Database Reference')
  475. );
  476. $form['database_reference']['accession'] = array(
  477. '#type' => 'textfield',
  478. '#title' => t('Accession'),
  479. '#default_value' => $node->stock->dbxref_id->accession
  480. );
  481. $form['database_reference']['db_description'] = array(
  482. '#type' => 'textarea',
  483. '#title' => t('Description of Database Reference'),
  484. '#default_value' => $node->stock->dbxref_id->description,
  485. '#description' => t('Optionally enter a description about the database accession.')
  486. );
  487. $db_options = tripal_db_get_db_options();
  488. $db_options[0] = 'Select a Database';
  489. if ($node->nid == '') {
  490. $db_default = 0; }
  491. else { $db_default = $node->stock->dbxref_id->db_id->db_id; }
  492. $form['database_reference']['database'] = array(
  493. '#type' => 'select',
  494. '#title' => t('Database'),
  495. '#options' => $db_options,
  496. '#default_value' => $db_default
  497. );
  498. return $form;
  499. }
  500. /**
  501. * Implements hook_validate(): Validate the input from the chado_stock node form
  502. *
  503. * @param $node
  504. * The current node including fields with the form element names and submitted values
  505. * @param $form
  506. * A description of the form to be rendered by drupal_get_form()
  507. *
  508. * @ingroup tripal_stock
  509. */
  510. function chado_stock_validate($node, &$form) {
  511. $int_in_chado_sql = "SELECT count(*) as count FROM {%s} WHERE %s=%d";
  512. $string_in_chado_sql = "SELECT count(*) as count FROM {%s} WHERE %s='%s'";
  513. // Validate Uniquename only if add
  514. if (empty($node->stock_id)) {
  515. $chado_row = db_fetch_object(chado_query("SELECT * FROM {stock} WHERE uniquename='" . $node->uniquename . "'"));
  516. if (!empty($chado_row->stock_id)) {
  517. $drupal_row = db_fetch_object(db_query("SELECT * FROM {chado_stock} WHERE stock_id=" . $chado_row->stock_id));
  518. if (!empty($drupal_row->nid)) {
  519. $link = l('node/' . $drupal_row->nid, $node->uniquename);
  520. form_set_error('uniquename', "There is already a stock with that uniquename $link. Please enter another uniquename.");
  521. }
  522. else {
  523. form_set_error('uniquename', "There is already a stock with that uniquename (although it's not sync'd with drupal). Please enter another uniquename.");
  524. }
  525. }
  526. }
  527. // Check Type of Stock is valid cvterm_id in chado ( $form['values']['details']['type_id'] )
  528. if ( $node->type_id == 0) {
  529. form_set_error('type_id', 'Please select a type of stock.');
  530. }
  531. else {
  532. $num_rows = db_fetch_object(chado_query($int_in_chado_sql, 'cvterm', 'cvterm_id', $node->type_id));
  533. if ( $num_rows->count != 1) {
  534. form_set_error('type_id', "The type you selected is not valid. Please choose another one. (CODE:$num_rows)"); }
  535. }
  536. // Check Source Organism is valid organism_id in chado ( $form['values']['details']['organism_id'] )
  537. if ( $node->organism_id == 0) {
  538. form_set_error('organism_id', 'Please select a source organism for this stock');
  539. }
  540. else {
  541. $num_rows = db_fetch_object(chado_query($int_in_chado_sql, 'organism', 'organism_id', $node->organism_id));
  542. if ( $num_rows->count != 1 ) {
  543. form_set_error('organism_id', "The organism you selected is not valid. Please choose another one. (CODE:$num_rows)"); }
  544. }
  545. // Check if Accession also database
  546. if ($node->accession != '') {
  547. if ($node->database == 0) {
  548. // there is an accession but no database selected
  549. form_set_error('database', 'You need to enter both a database and an accession for that database in order to add a database reference.');
  550. }
  551. }
  552. else {
  553. if ($node->database > 0) {
  554. // there is a database selected but no accession
  555. form_set_error('accession', 'You need to enter both a database and an accession for that database in order to add a database reference.');
  556. }
  557. }
  558. // Check database is valid db_id in chado ( $form['values']['database_reference']['database'] )
  559. if ( $node->database > 0) {
  560. $num_rows = db_fetch_object(chado_query($int_in_chado_sql, 'db', 'db_id', $node->database));
  561. if ($num_rows->count != 1) {
  562. form_set_error('database', 'The database you selected is not valid. Please choose another one.'); }
  563. }
  564. }
  565. /**
  566. * Implements hook_insert(): Inserts data from chado_stock_form() into drupal and chado
  567. *
  568. * @param $node
  569. * The current node including fields with the form element names and submitted values
  570. *
  571. * @return
  572. * TRUE if the node was successfully inserted into drupal/chado; FALSE otherwise
  573. *
  574. * @ingroup tripal_stock
  575. */
  576. function chado_stock_insert($node) {
  577. // If the chado stock exists (e.g. this is only a syncing operation)
  578. // then don't create but simply link to node
  579. if ($node->chado_stock_exists) {
  580. if (!empty($node->stock_id)) {
  581. db_query(
  582. "INSERT INTO {chado_stock} (nid, vid, stock_id) "
  583. ."VALUES (%d, %d, %d)",
  584. $node->nid,
  585. $node->vid,
  586. $node->stock_id
  587. );
  588. }
  589. return $node;
  590. }
  591. // before we can add the stock, we must add the dbxref if one has been
  592. // provided by the user.
  593. $dbxref_status = 0;
  594. if (!empty($node->accession) ) {
  595. if (!empty($node->database) ) {
  596. $values = array(
  597. 'db_id' => $node->database,
  598. 'accession' => $node->accession,
  599. );
  600. if (!tripal_core_chado_select('dbxref', array(dbxref_id), $values)) {
  601. $values['description'] = $node->db_description;
  602. $values['version'] = '1';
  603. $dbxref_status = tripal_core_chado_insert('dbxref', $values);
  604. if (!$dbxref_status) {
  605. drupal_set_message(t('Unable to add database reference to this stock.'), 'warning');
  606. watchdog('tripal_stock',
  607. 'Insert Stock: Unable to create dbxref where values:%values',
  608. array('%values' => print_r($values, TRUE)),
  609. WATCHDOG_WARNING
  610. );
  611. }
  612. }
  613. else {
  614. $dbxref_status = 1;
  615. }
  616. }
  617. }
  618. // create stock including the dbxref
  619. $stock = '';
  620. if ($dbxref_status) {
  621. $values = array(
  622. 'dbxref_id' => array(
  623. 'db_id' => $node->database,
  624. 'accession' => $node->accession
  625. ),
  626. 'organism_id' => $node->organism_id,
  627. 'name' => $node->sname,
  628. 'uniquename' => $node->uniquename,
  629. 'description' => $node->stock_description,
  630. 'type_id' => $node->type_id
  631. );
  632. $stock = tripal_core_chado_insert('stock', $values);
  633. }
  634. // create a stock without a dbxref
  635. else {
  636. $values = array(
  637. 'organism_id' => $node->organism_id,
  638. 'name' => $node->sname,
  639. 'uniquename' => $node->uniquename,
  640. 'description' => $node->stock_description,
  641. 'type_id' => $node->type_id
  642. );
  643. $stock = tripal_core_chado_insert('stock', $values);
  644. }
  645. // if the stock creation was succesful then add the URL and the entry in the
  646. // chado_stock table
  647. if (is_array($stock)) {
  648. // convert the stock into an object
  649. $stock = (object) $stock;
  650. // add the entry to the chado_stock table
  651. $sql = "INSERT INTO {chado_stock} (nid, vid, stock_id) VALUES (%d, %d, %d)";
  652. db_query($sql, $node->nid, $node->vid, $stock->stock_id);
  653. // Move on to next stage of Stock Creation based on next_stage_path field
  654. if ($node->simulate_multipart) {
  655. $next_stage_path = preg_replace('/%node/', $node->nid, $node->next_step_path);
  656. $_REQUEST['destination'] = $next_stage_path;
  657. }
  658. }
  659. else {
  660. drupal_set_message(t('Error during stock creation.'), 'error');
  661. watchdog('tripal_stock',
  662. 'Insert Stock: Unable to create stock where values:%values',
  663. array('%values' => print_r($values, TRUE)),
  664. WATCHDOG_WARNING
  665. );
  666. return FALSE;
  667. }
  668. }
  669. /**
  670. * Implements hook_update(): Handles Editing/Updating of main stock info
  671. *
  672. * NOTE: Currently just writes over all old data
  673. *
  674. * @param $node
  675. * The current node including fields with the form element names and submitted values
  676. *
  677. * @return
  678. * TRUE if the node was successfully updated in drupal/chado; FALSE otherwise
  679. *
  680. * @ingroup tripal_stock
  681. */
  682. function chado_stock_update($node) {
  683. if ($node->revision) {
  684. // there is no way to handle revisions in Chado but leave
  685. // this here just to make not we've addressed it.
  686. }
  687. //update dbxref
  688. if ($node->database) {
  689. if ($node->accession) {
  690. $dbxref_mode = '';
  691. $stock = tripal_core_chado_select(
  692. 'stock',
  693. array('dbxref_id', 'type_id'),
  694. array('stock_id' => $node->stock_id)
  695. );
  696. if ($stock[0]->dbxref_id) {
  697. $values = array(
  698. 'db_id' => $node->database,
  699. 'accession' => $node->accession,
  700. 'description' => $node->db_description
  701. );
  702. $dbxref_status = tripal_core_chado_update(
  703. 'dbxref',
  704. array('dbxref_id' => $stock[0]->dbxref_id),
  705. $values
  706. );
  707. $dbxref_mode = 'Update';
  708. }
  709. else {
  710. if ($stock[0]->type_id) {
  711. //create the dbxref
  712. //used the type_id as a control to check we have a stock but not a dbxref
  713. $values = array(
  714. 'db_id' => $node->database,
  715. 'accession' => $node->accession,
  716. 'description' => $node->db_description,
  717. 'version' => '1',
  718. );
  719. $dbxref_status = tripal_core_chado_insert(
  720. 'dbxref',
  721. $values
  722. );
  723. $dbxref_mode = 'Create';
  724. }
  725. else {
  726. drupal_set_message(t('Unable to find stock to Update'), 'error');
  727. watchdog(
  728. 'tripal_stock',
  729. 'Stock Update: Unable to find stock to update using values: %values',
  730. array('%values', print_r($values, TRUE)),
  731. WATCHDOG_ERROR
  732. );
  733. return FALSE;
  734. }
  735. }
  736. }
  737. }
  738. if (!$dbxref_status) {
  739. watchdog(
  740. 'tripal_stock',
  741. 'Stock Update: Unable to %mode main stock dbxref with values: %values',
  742. array('%values' => print_r($values, TRUE), '%mode' => $dbxref_mode),
  743. WATCHDOG_WARNING
  744. );
  745. }
  746. //can't change stock id which is all thats stored in drupal thus only update chado
  747. $update_values = array(
  748. 'organism_id' => $node->organism_id,
  749. 'name' => $node->sname,
  750. 'uniquename' => $node->uniquename,
  751. 'description' => $node->stock_description,
  752. 'type_id' => $node->type_id,
  753. );
  754. if ($dbxref_status) {
  755. $update_values['dbxref_id'] = array(
  756. 'db_id' => $node->database,
  757. 'accession' => $node->accession
  758. );
  759. }
  760. $status = tripal_core_chado_update('stock', array('stock_id' => $node->stock_id), $update_values);
  761. if (!$status) {
  762. drupal_set_message(t('Unable to update stock'), 'error');
  763. watchdog(
  764. 'tripal_stock',
  765. 'Stock Update: Unable to update stock using match values: %mvalues and update values: %uvalues',
  766. array('%mvalues' => print_r(array('stock_id' => $node->stock_id), TRUE), '%uvalues' => print_r($update_values, TRUE)),
  767. WATCHDOG_ERROR
  768. );
  769. }
  770. else {
  771. // set the URL for this stock page
  772. $values = array('stock_id' => $node->stock_id);
  773. $stock = tripal_core_chado_select('stock', array('*'), $values);
  774. }
  775. }
  776. /**
  777. * Implements hook_delete(): Handles deleting of chado_stocks
  778. *
  779. * NOTE: Currently deletes data -no undo or record-keeping functionality
  780. *
  781. * @param $node
  782. * The current node including fields with the form element names and submitted values
  783. *
  784. * @return
  785. * TRUE if the node was successfully deleted from drupal/chado; FALSE otherwise
  786. *
  787. * @ingroup tripal_stock
  788. */
  789. function chado_stock_delete($node) {
  790. // Set stock in chado: is_obsolete = TRUE
  791. chado_query(
  792. "DELETE FROM {stock} WHERE stock_id=%d",
  793. $node->stock->stock_id
  794. );
  795. //remove drupal node and all revisions
  796. db_query(
  797. "DELETE FROM {chado_stock} WHERE nid=%d",
  798. $node->nid
  799. );
  800. }
  801. /**
  802. * Purpose: Implement Blocks relating to stock content
  803. *
  804. * @param $op
  805. * What kind of information to retrieve about the block or blocks.
  806. * Possible values include list, configure, save, view.
  807. * @param $delta
  808. * Which block to return (not applicable if $op is 'list').
  809. * @param $edit
  810. * If $op is 'save', the submitted form data from the configuration form.
  811. *
  812. * @return
  813. * One of the following depending on $op: An array of block descriptions (list), the configuration
  814. * form (configure), nothing (save), an array defining subject and content for the block indexed
  815. * by $delta (view)
  816. *
  817. * @ingroup tripal_stock
  818. */
  819. function tripal_stock_block($op = 'list', $delta = 0, $edit=array()) {
  820. switch ($op) {
  821. case 'list':
  822. $blocks['base']['info'] = t('Tripal Stock Details');
  823. $blocks['base']['cache'] = BLOCK_NO_CACHE;
  824. $blocks['properties']['info'] = t('Tripal Stock Properties');
  825. $blocks['properties']['cache'] = BLOCK_NO_CACHE;
  826. $blocks['references']['info'] = t('Tripal Stock References');
  827. $blocks['references']['cache'] = BLOCK_NO_CACHE;
  828. $blocks['relationships_as_object']['info'] = t('Tripal Stock Relationships');
  829. $blocks['relationships_as_object']['cache'] = BLOCK_NO_CACHE;
  830. $blocks['synonyms']['info'] = t('Tripal Stock Synonyms');
  831. $blocks['synonyms']['cache'] = BLOCK_NO_CACHE;
  832. $blocks['collections']['info'] = t('Tripal Stock Collections');
  833. $blocks['collections']['cache'] = BLOCK_NO_CACHE;
  834. $blocks['phenotypes']['info'] = t('Tripal Stock Phenotypes');
  835. $blocks['phenotypes']['cache'] = BLOCK_NO_CACHE;
  836. $blocks['genotypes']['info'] = t('Tripal Stock Genotypes');
  837. $blocks['genotypes']['cache'] = BLOCK_NO_CACHE;
  838. $blocks['locations']['info'] = t('Tripal Stock Locations');
  839. $blocks['locations']['cache'] = BLOCK_NO_CACHE;
  840. $blocks['orgstocks']['info'] = t('Tripal Organism Stocks');
  841. $blocks['orgstocks']['cache'] = BLOCK_NO_CACHE;
  842. return $blocks;
  843. case 'view':
  844. if (user_access('access chado_stock content') and arg(0) == 'node' and is_numeric(arg(1))) {
  845. $nid = arg(1);
  846. $node = node_load($nid);
  847. $block = array();
  848. switch ($delta) {
  849. case 'base':
  850. $block['subject'] = t('Stock Details');
  851. $block['content'] = theme('tripal_stock_base', $node);
  852. break;
  853. case 'properties':
  854. $block['subject'] = t('Properties');
  855. $block['content'] = theme('tripal_stock_properties', $node);
  856. break;
  857. case 'references':
  858. $block['subject'] = t('References');
  859. $block['content'] = theme('tripal_stock_references', $node);
  860. break;
  861. case 'relationships':
  862. $block['subject'] = t('Relationships');
  863. $block['content'] = theme('tripal_stock_relationships', $node);
  864. break;
  865. case 'synonyms':
  866. $block['subject'] = t('Synonyms');
  867. $block['content'] = theme('tripal_stock_synonyms', $node);
  868. break;
  869. case 'collections':
  870. $block['subject'] = t('Stock Collections');
  871. $block['content'] = theme('tripal_stock_collections', $node);
  872. break;
  873. case 'phenotypes':
  874. $block['subject'] = t('Stock Phenotypes');
  875. $block['content'] = theme('tripal_stock_phenotypes', $node);
  876. break;
  877. case 'genotypes':
  878. $block['subject'] = t('Stock Genotypes');
  879. $block['content'] = theme('tripal_stock_genotypes', $node);
  880. break;
  881. case 'locations':
  882. $block['subject'] = t('Stock Locations');
  883. $block['content'] = theme('tripal_stock_locations', $node);
  884. break;
  885. case 'orgstocks':
  886. $block['subject'] = t('Organism Stocks');
  887. $block['content'] = theme('tripal_organism_stocks', $node);
  888. break;
  889. }
  890. return $block;
  891. }
  892. }
  893. }
  894. /**
  895. *
  896. *
  897. * @ingroup tripal_stock
  898. */
  899. function tripal_stock_preprocess_tripal_stock_relationships(&$variables) {
  900. // we want to provide a new variable that contains the matched stocks.
  901. $stock = $variables['node']->stock;
  902. // normally we would use tripal_core_expand_chado_vars to expand our
  903. // organism object and add in the relationships, however whan a large
  904. // number of relationships are present this significantly slows the
  905. // query, therefore we will manually perform the query
  906. $sql = "
  907. SELECT
  908. S.name, S.uniquename, S.stock_id, CS.nid,
  909. CVT.name as rel_type, CVTs.name as obj_type,
  910. SR.value
  911. FROM {stock_relationship} SR
  912. INNER JOIN {stock} S on SR.object_id = S.stock_id
  913. INNER JOIN {cvterm} CVT on SR.type_id = CVT.cvterm_id
  914. INNER JOIN {cvterm} CVTs on S.type_id = CVTs.cvterm_id
  915. LEFT JOIN public.chado_stock CS on S.stock_id = CS.stock_id
  916. WHERE SR.subject_id = %d
  917. ";
  918. $as_subject = chado_query($sql, $stock->stock_id);
  919. $sql = "
  920. SELECT
  921. S.name, S.uniquename, S.stock_id, CS.nid,
  922. CVT.name as rel_type, CVTs.name as sub_type,
  923. SR.value
  924. FROM {stock_relationship} SR
  925. INNER JOIN {stock} S on SR.subject_id = S.stock_id
  926. INNER JOIN {cvterm} CVT on SR.type_id = CVT.cvterm_id
  927. INNER JOIN {cvterm} CVTs on S.type_id = CVTs.cvterm_id
  928. LEFT JOIN public.chado_stock CS on S.stock_id = CS.stock_id
  929. WHERE SR.object_id = %d
  930. ";
  931. $as_object = chado_query($sql, $stock->stock_id);
  932. // combine both object and subject relationshisp into a single array
  933. $relationships = array();
  934. $relationships['object'] = array();
  935. $relationships['subject'] = array();
  936. // iterate through the object relationships
  937. while ($relationship = db_fetch_object($as_object)) {
  938. // get the relationship and child types
  939. $rel_type = t(preg_replace('/_/', " ", $relationship->rel_type));
  940. $sub_type = t(preg_replace('/_/', " ", $relationship->sub_type));
  941. if (!array_key_exists($rel_type, $relationships['object'])) {
  942. $relationships['object'][$rel_type] = array();
  943. }
  944. if (!array_key_exists($sub_type, $relationships['object'][$rel_type])) {
  945. $relationships['object'][$rel_type][$sub_type] = array();
  946. }
  947. $relationships['object'][$rel_type][$sub_type][] = $relationship;
  948. }
  949. // now add in the subject relationships
  950. while ($relationship = db_fetch_object($as_subject)) {
  951. // get the relationship and child types
  952. $rel_type = t(preg_replace('/_/', " ", $relationship->rel_type));
  953. $obj_type = t(preg_replace('/_/', " ", $relationship->obj_type));
  954. if (!array_key_exists($rel_type, $relationships['subject'])) {
  955. $relationships['subject'][$rel_type] = array();
  956. }
  957. if (!array_key_exists($obj_type, $relationships['subject'][$rel_type])) {
  958. $relationships['subject'][$rel_type][$obj_type] = array();
  959. }
  960. $relationships['subject'][$rel_type][$obj_type][] = $relationship;
  961. }
  962. $stock->all_relationships = $relationships;
  963. }
  964. /**
  965. * Implementation of hook_nodeapi().
  966. * Display stock information for associated organisms
  967. * This function also provides contents for indexing
  968. *
  969. * @ingroup tripal_stock
  970. */
  971. function tripal_stock_nodeapi(&$node, $op, $teaser, $page) {
  972. switch ($op) {
  973. // set the title to ensure it is always unique
  974. case 'presave':
  975. switch ($node->type) {
  976. case 'chado_stock':
  977. $values = array('organism_id' => $node->organism_id);
  978. $organism = tripal_core_chado_select('organism', array('genus','species'), $values);
  979. $values = array('cvterm_id' => $node->type_id);
  980. $cvterm = tripal_core_chado_select('cvterm', array('name'), $values);
  981. $node->title = $node->sname . ', ' . $node->uniquename . ' (' . $cvterm[0]->name . ') ' . $organism[0]->genus . ' ' . $organism[0]->species;
  982. break;
  983. }
  984. break;
  985. // set the URL path after inserting. We do it here because we do not
  986. // know the stock_id in the presave
  987. case 'insert':
  988. switch ($node->type) {
  989. case 'chado_stock':
  990. if (!$node->stock_id) {
  991. $sql = "SELECT * FROM {chado_stock} WHERE nid = %d";
  992. $chado_stock = db_fetch_object(db_query($sql, $node->nid));
  993. $node->stock_id = $chado_stock->stock_id;
  994. }
  995. // remove any previous alias
  996. db_query("DELETE FROM {url_alias} WHERE src = '%s'", "node/$node->nid");
  997. // set the URL for this stock page
  998. $url_alias = tripal_stock_get_stock_url($node);
  999. path_set_alias("node/$node->nid", $url_alias);
  1000. break;
  1001. }
  1002. break;
  1003. // set the URL path after inserting. We do it here because we do not
  1004. // know the stock_id in the presave
  1005. case 'update':
  1006. switch ($node->type) {
  1007. case 'chado_stock':
  1008. // remove any previous alias
  1009. db_query("DELETE FROM {url_alias} WHERE src = '%s'", "node/$node->nid");
  1010. // set the URL for this stock page
  1011. $url_alias = tripal_stock_get_stock_url($node);
  1012. path_set_alias("node/$node->nid", $url_alias);
  1013. break;
  1014. }
  1015. break;
  1016. // add items to other nodes, build index and search results
  1017. case 'view':
  1018. // add the stock to the organism/feature search indexing
  1019. if ($node->build_mode == NODE_BUILD_SEARCH_INDEX) {
  1020. }
  1021. elseif ($node->build_mode == NODE_BUILD_SEARCH_RESULT) {
  1022. }
  1023. else {
  1024. switch ($node->type) {
  1025. case 'chado_organism':
  1026. // Show stock if the organism/feature is not at teaser view
  1027. $node->content['tripal_organism_stocks'] = array(
  1028. '#value' => theme('tripal_organism_stocks', $node),
  1029. );
  1030. break;
  1031. }
  1032. }
  1033. break;
  1034. }
  1035. }