tripal_stock.chado_node.inc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. <?php
  2. /**
  3. * @file Stock Node Functionality
  4. */
  5. /**
  6. * Implements hook_node_info().
  7. * Registers a stock node type
  8. *
  9. * @return
  10. * An array describing various details of the node
  11. *
  12. * @ingroup tripal_legacy_stock
  13. */
  14. function tripal_stock_node_info() {
  15. return [
  16. 'chado_stock' => [
  17. 'name' => t('Stock (Tripal v2 legacy)'),
  18. 'base' => 'chado_stock',
  19. 'description' => t('A Chado Stock is a collection of material that can be sampled and have experiments performed on it.'),
  20. 'has_title' => TRUE,
  21. 'locked' => TRUE,
  22. 'chado_node_api' => [
  23. 'base_table' => 'stock',
  24. 'hook_prefix' => 'chado_stock',
  25. 'record_type_title' => [
  26. 'singular' => t('Stock'),
  27. 'plural' => t('Stocks'),
  28. ],
  29. 'sync_filters' => [
  30. 'type_id' => TRUE,
  31. 'organism_id' => TRUE,
  32. ],
  33. ],
  34. ],
  35. ];
  36. }
  37. /**
  38. * Implements hook_load().
  39. *
  40. * When a node is requested by the user this function is called to allow us
  41. * to add auxiliary data to the node object.
  42. *
  43. * @ingroup tripal_legacy_stock
  44. */
  45. function chado_stock_load($nodes) {
  46. foreach ($nodes as $nid => $node) {
  47. // find the stock and add in the details
  48. $stock_id = chado_get_id_from_nid('stock', $nid);
  49. // if the nid does not have a matching record then skip this node.
  50. // this can happen with orphaned nodes.
  51. if (!$stock_id) {
  52. continue;
  53. }
  54. // build the variable with all the stock details
  55. $values = ['stock_id' => $stock_id];
  56. $stock = chado_generate_var('stock', $values);
  57. $stock = chado_expand_var($stock, 'field', 'stock.uniquename');
  58. $stock = chado_expand_var($stock, 'field', 'stock.description');
  59. $nodes[$nid]->stock = $stock;
  60. // Now get the title
  61. $node->title = chado_get_node_title($node);
  62. }
  63. }
  64. /**
  65. * Implements hook_form().
  66. * Creates the main Add/Edit/Delete Form for chado stocks
  67. *
  68. * Parts to be added by this form
  69. * name,
  70. * uniquename,
  71. * description,
  72. * type => select from cvterm with key cvterm_id,
  73. * organism => select from available with key organism_id
  74. * main_db_reference => accession, version, description, db_name(select
  75. * from dropdown)
  76. *
  77. * @param $node
  78. * An empty node object on insert OR the current stock node object on update
  79. * @param $form_state
  80. * The current state of the form
  81. *
  82. * @return
  83. * A description of the form to be rendered by drupal_get_form()
  84. *
  85. * @ingroup tripal_legacy_stock
  86. */
  87. function chado_stock_form($node, $form_state) {
  88. /* I don't think we need this... commenting out but leaving just in case
  89. // If existing stock then expand all fields needed using the chado API
  90. if (isset($node->nid)) {
  91. $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');
  92. foreach ($fields_needed as $field_name) {
  93. // Check to see if it's excluded and expand it if so
  94. if (isset($node->expandable_fields)) {
  95. if (in_array($field_name, $node->expandable_fields)) {
  96. $node = chado_expand_var($node, 'field', $field_name);
  97. }
  98. }
  99. }
  100. }
  101. */
  102. //TODO: @lacey can you take a look at the above code?
  103. // Default values can come in the following ways:
  104. //
  105. // 1) as elements of the $node object. This occurs when editing an existing stock
  106. // 2) in the $form_state['values'] array which occurs on a failed validation or
  107. // ajax callbacks from non submit form elements
  108. // 3) in the $form_state['input'] array which occurs on ajax callbacks from submit
  109. // form elements and the form is being rebuilt
  110. //
  111. // set form field defaults
  112. $sname = '';
  113. $uniquename = '';
  114. $stock_id = 0;
  115. $type_id = 0;
  116. $organism_id = 0;
  117. $sdescription = '';
  118. $dbxref_accession = '';
  119. $dbxref_description = '';
  120. $dbxref_database = 0;
  121. // 1) if we are editing an existing node then the stock is already part of the node
  122. if (property_exists($node, 'stock')) {
  123. $sname = $node->stock->name;
  124. $uniquename = $node->stock->uniquename;
  125. $stock_id = $node->stock->stock_id;
  126. $type_id = $node->stock->type_id->cvterm_id;
  127. $organism_id = $node->stock->organism_id->organism_id;
  128. $sdescription = $node->stock->description;
  129. if (isset($node->stock->dbxref_id->db_id)) {
  130. $dbxref_accession = $node->stock->dbxref_id->accession;
  131. $dbxref_description = $node->stock->dbxref_id->description;
  132. $dbxref_database = $node->stock->dbxref_id->db_id->db_id;
  133. }
  134. }
  135. // 2) if we are re constructing the form from a failed validation or ajax callback
  136. // then use the $form_state['values'] values
  137. if (array_key_exists('values', $form_state) AND isset($form_state['values']['uniquename'])) {
  138. $sname = $form_state['values']['sname'];
  139. $uniquename = $form_state['values']['uniquename'];
  140. $stock_id = $form_state['values']['stock_id'];
  141. $type_id = $form_state['values']['type_id'];
  142. $organism_id = $form_state['values']['organism_id'];
  143. $sdescription = $form_state['values']['stock_description'];
  144. $dbxref_accession = $form_state['values']['accession'];
  145. $dbxref_description = $form_state['values']['db_description'];
  146. $dbxref_database = $form_state['values']['database'];
  147. }
  148. // 3) if we are re building the form from after submission (from ajax call) then
  149. // the values are in the $form_state['input'] array
  150. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  151. $sname = $form_state['input']['sname'];
  152. $uniquename = $form_state['input']['uniquename'];
  153. $stock_id = $form_state['input']['stock_id'];
  154. $type_id = $form_state['input']['type_id'];
  155. $organism_id = $form_state['input']['organism_id'];
  156. $sdescription = $form_state['input']['stock_description'];
  157. $dbxref_accession = $form_state['input']['accession'];
  158. $dbxref_description = $form_state['input']['db_description'];
  159. $dbxref_database = $form_state['input']['database'];
  160. }
  161. $form['sname'] = [
  162. '#type' => 'textfield',
  163. '#title' => t('Stock Name'),
  164. '#description' => t('Enter a human-readable name for this stock.'),
  165. '#default_value' => $sname,
  166. '#required' => TRUE,
  167. ];
  168. $form['uniquename'] = [
  169. '#type' => 'textfield',
  170. '#title' => t('Unique Name'),
  171. '#default_value' => $uniquename,
  172. '#description' => t('Enter a unique name for this stock. This name must be unique for the organism and stock type.'),
  173. '#required' => TRUE,
  174. ];
  175. if ($stock_id > 0) {
  176. $form['stock_id'] = [
  177. '#type' => 'hidden',
  178. '#value' => $stock_id,
  179. ];
  180. }
  181. // TODO: Should we make this a textfield with an autocomplete field like the
  182. // feature type_id field?.
  183. $st_cv = tripal_get_default_cv("stock", "type_id");
  184. $type_options = tripal_get_cvterm_default_select_options('stock', 'type_id', 'stock types');
  185. $type_options[0] = 'Select a Type';
  186. $st_message = tripal_set_message("To add additional items to the stock type drop down list,
  187. add a term to the " .
  188. l($st_cv->name . " controlled vocabulary",
  189. "admin/tripal/loaders/chado_vocabs/chado_cv/" . $st_cv->cv_id . "/cvterm/add",
  190. ['attributes' => ['target' => '_blank']]
  191. ),
  192. TRIPAL_INFO, ['return_html' => TRUE]
  193. );
  194. $form['type_id'] = [
  195. '#type' => 'select',
  196. '#title' => t('Type of Stock'),
  197. '#description' => t('Select the stock type.'),
  198. '#options' => $type_options,
  199. '#default_value' => $type_id,
  200. '#required' => TRUE,
  201. '#suffix' => $st_message,
  202. ];
  203. // get the list of organisms
  204. $sql = "SELECT * FROM {organism} ORDER BY genus, species";
  205. $org_rset = chado_query($sql);
  206. $organisms = [];
  207. $organisms[''] = '';
  208. while ($organism = $org_rset->fetchObject()) {
  209. $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
  210. }
  211. $form['organism_id'] = [
  212. '#type' => 'select',
  213. '#title' => t('Organism'),
  214. '#default_value' => $organism_id,
  215. '#description' => t('Choose the organism with which this stock is associated.'),
  216. '#options' => $organisms,
  217. '#required' => TRUE,
  218. ];
  219. $form['stock_description'] = [
  220. '#type' => 'text_format',
  221. '#title' => t('Notes'),
  222. '#default_value' => $sdescription,
  223. '#description' => t('Briefly enter any notes on the above stock. This should not include phenotypes or genotypes.'),
  224. ];
  225. $form['database_reference'] = [
  226. '#type' => 'fieldset',
  227. '#title' => t('Stock Database Reference'),
  228. '#description' => t('If this site is not the primary location for information
  229. about this stock, please provide the name of the database, the accession
  230. and an optional description using the fields below. If the database
  231. is not present in the list, then please ') .
  232. l(t('add the database '), 'admin/tripal/legacy/tripal_db/add', ['attributes' => ['target' => '_blank']]) .
  233. t('then refresh this page.'),
  234. ];
  235. $db_options = tripal_get_db_select_options();
  236. $form['database_reference']['database'] = [
  237. '#type' => 'select',
  238. '#title' => t('Database'),
  239. '#options' => $db_options,
  240. '#default_value' => $dbxref_database,
  241. '#description' => t('Select the remote database.'),
  242. ];
  243. $form['database_reference']['accession'] = [
  244. '#type' => 'textfield',
  245. '#title' => t('Accession'),
  246. '#default_value' => $dbxref_accession,
  247. '#description' => t('Please enter the accession in the remote database for this stock.'),
  248. ];
  249. $form['database_reference']['db_description'] = [
  250. '#type' => 'textarea',
  251. '#title' => t('Description of Database Reference'),
  252. '#default_value' => $dbxref_description,
  253. '#description' => t('Optionally enter a description about the database accession.'),
  254. ];
  255. // PROPERTIES FORM
  256. //---------------------------------------------
  257. $prop_cv = tripal_get_default_cv('stockprop', 'type_id');
  258. $cv_id = $prop_cv ? $prop_cv->cv_id : NULL;
  259. $details = [
  260. 'property_table' => 'stockprop',
  261. 'chado_id' => $stock_id,
  262. 'cv_id' => $cv_id,
  263. ];
  264. chado_add_node_form_properties($form, $form_state, $details);
  265. // ADDITIONAL DBXREFS FORM
  266. //---------------------------------------------
  267. $details = [
  268. 'linking_table' => 'stock_dbxref',
  269. 'base_foreign_key' => 'stock_id',
  270. 'base_key_value' => $stock_id,
  271. ];
  272. chado_add_node_form_dbxrefs($form, $form_state, $details);
  273. // RELATIONSHIPS FORM
  274. //---------------------------------------------
  275. $relationship_cv = tripal_get_default_cv('stock_relationship', 'type_id');
  276. $cv_id = $relationship_cv ? $relationship_cv->cv_id : NULL;
  277. $details = [
  278. 'relationship_table' => 'stock_relationship',
  279. 'base_table' => 'stock',
  280. 'base_foreign_key' => 'stock_id',
  281. 'base_key_value' => $stock_id,
  282. 'nodetype' => 'stock',
  283. 'cv_id' => $cv_id,
  284. ];
  285. chado_add_node_form_relationships($form, $form_state, $details);
  286. return $form;
  287. }
  288. /**
  289. * Implements hook_validate().
  290. * Validate the input from the chado_stock node form
  291. *
  292. * @param $node
  293. * The current node including fields with the form element names and
  294. * submitted values
  295. * @param $form
  296. * A description of the form to be rendered by drupal_get_form()
  297. *
  298. * @ingroup tripal_legacy_stock
  299. */
  300. function chado_stock_validate(&$node, $form, &$form_state) {
  301. // We only want to validate when the node is saved.
  302. // Since this validate can be called on AJAX and Deletion of the node
  303. // we need to make this check to ensure queries are not executed
  304. // without the proper values.
  305. if (property_exists($node, "op") and $node->op != 'Save') {
  306. return;
  307. }
  308. // we are syncing if we do not have a node ID but we do have a stock_id. We don't
  309. // need to validate during syncing so just skip it.
  310. if (!property_exists($node, 'nid') and property_exists($node, 'stock_id') and $node->stock_id != 0) {
  311. return;
  312. }
  313. // remove surrounding whitespace
  314. $node->uniquename = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
  315. $node->sname = property_exists($node, 'sname') ? trim($node->sname) : '';
  316. $node->accession = property_exists($node, 'accession') ? trim($node->accession) : '';
  317. $node->db_description = property_exists($node, 'db_description') ? trim($node->db_description) : '';
  318. $int_in_chado_sql = "SELECT count(*) as count FROM {:table} WHERE :column = :value";
  319. $string_in_chado_sql = "SELECT count(*) as count FROM {:table} WHERE :column = :value";
  320. // if this is an update, we want to make sure that a different stock for
  321. // the organism doesn't already have this uniquename. We don't want to give
  322. // two sequences the same uniquename
  323. if (property_exists($node, 'nid') and property_exists($node, 'stock_id')) {
  324. $sql = "
  325. SELECT *
  326. FROM {stock} S
  327. INNER JOIN {cvterm} CVT ON S.type_id = CVT.cvterm_id
  328. WHERE
  329. uniquename = :uname AND organism_id = :organism_id AND
  330. CVT.name = :cvtname AND NOT stock_id = :stock_id
  331. ";
  332. $result = chado_query($sql, [
  333. ':uname' => $node->uniquename,
  334. ':organism_id' => $node->organism_id,
  335. ':cvtname' => $node->type_id,
  336. ':stock_id' => $node->stock_id,
  337. ])->fetchObject();
  338. if ($result) {
  339. form_set_error('uniquename', t("Stock update cannot proceed. The stock name '$node->uniquename' is not unique for this organism. Please provide a unique name for this stock."));
  340. }
  341. }
  342. // if this is an insert then we just need to make sure this name doesn't
  343. // already exist for this organism if it does then we need to throw an error
  344. elseif (!empty($node->organism_id) AND !empty($node->type_id)) {
  345. $sql = "
  346. SELECT *
  347. FROM {stock} S
  348. INNER JOIN {cvterm} CVT ON S.type_id = CVT.cvterm_id
  349. WHERE uniquename = :uname AND organism_id = :organism_id AND CVT.name = :cvtname";
  350. $result = chado_query($sql, [
  351. ':uname' => $node->uniquename,
  352. ':organism_id' => $node->organism_id,
  353. ':cvtname' => $node->type_id,
  354. ])->fetchObject();
  355. if ($result) {
  356. form_set_error('uniquename', t("Stock insert cannot proceed. The stock name '$node->uniquename' already exists for this organism. Please provide a unique name for this stock."));
  357. }
  358. }
  359. // Check Type of Stock is valid cvterm_id in chado ( $form['values']['details']['type_id'] )
  360. if ($node->type_id == 0) {
  361. form_set_error('type_id', 'Please select a type of stock.');
  362. }
  363. else {
  364. $replace = [':table' => 'cvterm', ':column' => 'cvterm_id'];
  365. $new_sql = str_replace(array_keys($replace), $replace, $int_in_chado_sql);
  366. $num_rows = chado_query($new_sql, [':value' => $node->type_id])->fetchObject();
  367. if ($num_rows->count != 1) {
  368. form_set_error('type_id', "The type you selected is not valid. Please choose another one. (CODE:$num_rows)");
  369. }
  370. }
  371. // Check Source Organism is valid organism_id in chado ( $form['values']['details']['organism_id'] )
  372. if ($node->organism_id == 0) {
  373. form_set_error('organism_id', 'Please select a source organism for this stock');
  374. }
  375. else {
  376. $replace = [':table' => 'organism', ':column' => 'organism_id'];
  377. $new_sql = str_replace(array_keys($replace), $replace, $int_in_chado_sql);
  378. $num_rows = chado_query($new_sql, [':value' => $node->organism_id])->fetchObject();
  379. if ($num_rows->count != 1) {
  380. form_set_error('organism_id', "The organism you selected is not valid. Please choose another one. (CODE:$num_rows)");
  381. }
  382. }
  383. // Check if Accession also database
  384. if ($node->accession != '') {
  385. if ($node->database == 0) {
  386. // there is an accession but no database selected
  387. form_set_error('database', 'You need to enter both a database and an accession for that database in order to add a database reference.');
  388. }
  389. }
  390. else {
  391. if ($node->database > 0) {
  392. // there is a database selected but no accession
  393. form_set_error('accession', 'You need to enter both a database and an accession for that database in order to add a database reference.');
  394. }
  395. }
  396. // Check database is valid db_id in chado ( $form['values']['database_reference']['database'] )
  397. if ($node->database > 0) {
  398. $replace = [':table' => 'db', ':column' => 'db_id'];
  399. $new_sql = str_replace(array_keys($replace), $replace, $int_in_chado_sql);
  400. $num_rows = chado_query($new_sql, [':value' => $node->database])->fetchObject();
  401. if ($num_rows->count != 1) {
  402. form_set_error('database', 'The database you selected is not valid. Please choose another one.');
  403. }
  404. }
  405. }
  406. /**
  407. * Implements hook_insert().
  408. * Inserts data from chado_stock_form() into drupal and chado
  409. *
  410. * @param $node
  411. * The current node including fields with the form element names and
  412. * submitted values
  413. *
  414. * @return
  415. * TRUE if the node was successfully inserted into drupal/chado; FALSE
  416. * otherwise
  417. *
  418. * @ingroup tripal_legacy_stock
  419. */
  420. function chado_stock_insert($node) {
  421. $stock_id = '';
  422. // if there is an stock_id in the $node object then this must be a sync so
  423. // we can skip adding the stock to chado as it is already there, although
  424. // we do need to proceed with insertion into the chado/drupal linking table.
  425. if (!property_exists($node, 'stock_id')) {
  426. $node->uniquename = trim($node->uniquename);
  427. $node->sname = trim($node->sname);
  428. $node->accession = trim($node->accession);
  429. $node->stock_description = trim($node->stock_description['value']);
  430. // before we can add the stock, we must add the dbxref if one has been
  431. // provided by the user.
  432. $dbxref = NULL;
  433. if (!empty($node->accession) and !empty($node->database)) {
  434. $values = [
  435. 'db_id' => $node->database,
  436. 'accession' => $node->accession,
  437. ];
  438. if (!chado_select_record('dbxref', ['dbxref_id'], $values)) {
  439. $values['description'] = $node->db_description;
  440. $values['version'] = '1';
  441. $dbxref = chado_insert_record('dbxref', $values);
  442. if (!$dbxref) {
  443. drupal_set_message(t('Unable to add database reference to this stock.'), 'warning');
  444. tripal_report_error('tripal_stock', TRIPAL_WARNING,
  445. 'Insert Stock: Unable to create dbxref where values:%values',
  446. ['%values' => print_r($values, TRUE)]);
  447. }
  448. }
  449. }
  450. // create stock including the dbxref
  451. $stock = '';
  452. $values = [
  453. 'organism_id' => $node->organism_id,
  454. 'name' => $node->sname,
  455. 'uniquename' => $node->uniquename,
  456. 'description' => $node->stock_description,
  457. 'type_id' => $node->type_id,
  458. ];
  459. if ($dbxref) {
  460. $values['dbxref_id'] = [
  461. 'db_id' => $node->database,
  462. 'accession' => $node->accession,
  463. ];
  464. }
  465. $stock = chado_insert_record('stock', $values);
  466. if (!$stock) {
  467. drupal_set_message(t('Unable to add stock.'), 'warning');
  468. tripal_report_error('tripal_stock', TRIPAL_WARNING, 'Insert stock: Unable to create stock where values: %values',
  469. ['%values' => print_r($values, TRUE)]);
  470. return;
  471. }
  472. $stock_id = $stock['stock_id'];
  473. // Now add properties
  474. $details = [
  475. 'property_table' => 'stockprop',
  476. 'base_table' => 'stock',
  477. 'foreignkey_name' => 'stock_id',
  478. 'foreignkey_value' => $stock_id,
  479. ];
  480. chado_update_node_form_properties($node, $details);
  481. // Now add the additional references
  482. $details = [
  483. 'linking_table' => 'stock_dbxref',
  484. 'foreignkey_name' => 'stock_id',
  485. 'foreignkey_value' => $stock_id,
  486. ];
  487. chado_update_node_form_dbxrefs($node, $details);
  488. // Now add in relationships
  489. $details = [
  490. 'relationship_table' => 'stock_relationship',
  491. 'foreignkey_value' => $stock_id,
  492. ];
  493. chado_update_node_form_relationships($node, $details);
  494. }
  495. else {
  496. $stock_id = $node->stock_id;
  497. }
  498. // Make sure the entry for this stock doesn't already exist in the
  499. // chado_stock table if it doesn't exist then we want to add it.
  500. $check_org_id = chado_get_id_from_nid('stock', $node->nid);
  501. if (!$check_org_id) {
  502. $record = new stdClass();
  503. $record->nid = $node->nid;
  504. $record->vid = $node->vid;
  505. $record->stock_id = $stock_id;
  506. drupal_write_record('chado_stock', $record);
  507. }
  508. }
  509. /**
  510. * Implements hook_update().
  511. * Handles Editing/Updating of main stock info
  512. *
  513. * NOTE: Currently just writes over all old data
  514. *
  515. * @param $node
  516. * The current node including fields with the form element names and
  517. * submitted values
  518. *
  519. * @return
  520. * TRUE if the node was successfully updated in drupal/chado; FALSE otherwise
  521. *
  522. * @ingroup tripal_legacy_stock
  523. */
  524. function chado_stock_update($node) {
  525. $node->uniquename = trim($node->uniquename);
  526. $node->sname = trim($node->sname);
  527. $node->stock_description = trim($node->stock_description['value']);
  528. if ($node->revision) {
  529. // there is no way to handle revisions in Chado but leave
  530. // this here just to make not we've addressed it.
  531. }
  532. //update dbxref
  533. $dbxref_status = NULL;
  534. $dbxref_present = FALSE;
  535. if ($node->database) {
  536. $dbxref_present = TRUE;
  537. if ($node->accession) {
  538. $dbxref_mode = '';
  539. $stock = chado_select_record(
  540. 'stock',
  541. ['dbxref_id', 'type_id'],
  542. ['stock_id' => $node->stock_id]
  543. );
  544. if ($stock[0]->dbxref_id) {
  545. $values = [
  546. 'db_id' => $node->database,
  547. 'accession' => $node->accession,
  548. 'description' => $node->db_description,
  549. ];
  550. $dbxref_status = chado_update_record(
  551. 'dbxref',
  552. ['dbxref_id' => $stock[0]->dbxref_id],
  553. $values
  554. );
  555. $dbxref_mode = 'Update';
  556. }
  557. else {
  558. if ($stock[0]->type_id) {
  559. //create the dbxref
  560. //used the type_id as a control to check we have a stock but not a dbxref
  561. $values = [
  562. 'db_id' => $node->database,
  563. 'accession' => $node->accession,
  564. 'description' => $node->db_description,
  565. 'version' => '1',
  566. ];
  567. $dbxref_status = chado_insert_record(
  568. 'dbxref',
  569. $values
  570. );
  571. $dbxref_mode = 'Create';
  572. }
  573. else {
  574. drupal_set_message(t('Unable to find stock to Update'), 'error');
  575. tripal_report_error('tripal_stock', TRIPAL_ERROR,
  576. 'Stock Update: Unable to find stock to update using values: %values',
  577. ['%values', print_r($values, TRUE)]
  578. );
  579. return FALSE;
  580. }
  581. }
  582. }
  583. if (!$dbxref_status) {
  584. tripal_report_error('tripal_stock', TRIPAL_WARNING,
  585. 'Stock Update: Unable to %mode main stock dbxref with values: %values',
  586. ['%values' => print_r($values, TRUE), '%mode' => $dbxref_mode]);
  587. }
  588. }
  589. //can't change stock id which is all thats stored in drupal thus only update chado
  590. $update_values = [
  591. 'organism_id' => $node->organism_id,
  592. 'name' => $node->sname,
  593. 'uniquename' => $node->uniquename,
  594. 'description' => $node->stock_description,
  595. 'type_id' => $node->type_id,
  596. ];
  597. if ($dbxref_present) {
  598. if ($dbxref_status) {
  599. $update_values['dbxref_id'] = [
  600. 'db_id' => $node->database,
  601. 'accession' => $node->accession,
  602. ];
  603. }
  604. }
  605. $status = chado_update_record('stock', ['stock_id' => $node->stock_id], $update_values);
  606. if (!$status) {
  607. drupal_set_message(t('Unable to update stock'), 'error');
  608. tripal_report_error('tripal_stock', TRIPAL_ERROR,
  609. 'Stock Update: Unable to update stock using match values: %mvalues and update values: %uvalues',
  610. [
  611. '%mvalues' => print_r(['stock_id' => $node->stock_id], TRUE),
  612. '%uvalues' => print_r($update_values, TRUE),
  613. ]
  614. );
  615. }
  616. else {
  617. // set the URL for this stock page
  618. $values = ['stock_id' => $node->stock_id];
  619. $stock = chado_select_record('stock', ['*'], $values);
  620. }
  621. // now update the properties
  622. if ($node->stock_id > 0) {
  623. $details = [
  624. 'property_table' => 'stockprop',
  625. 'base_table' => 'stock',
  626. 'foreignkey_name' => 'stock_id',
  627. 'foreignkey_value' => $node->stock_id,
  628. ];
  629. chado_update_node_form_properties($node, $details);
  630. }
  631. // now update the additional dbxrefs
  632. if ($node->stock_id > 0) {
  633. $details = [
  634. 'linking_table' => 'stock_dbxref',
  635. 'foreignkey_name' => 'stock_id',
  636. 'foreignkey_value' => $node->stock_id,
  637. ];
  638. chado_update_node_form_dbxrefs($node, $details);
  639. }
  640. // now update relationships
  641. if ($node->stock_id > 0) {
  642. $details = [
  643. 'relationship_table' => 'stock_relationship',
  644. 'foreignkey_value' => $node->stock_id,
  645. ];
  646. chado_update_node_form_relationships($node, $details);
  647. }
  648. }
  649. /**
  650. * Implements hook_delete().
  651. * Handles deleting of chado_stocks
  652. *
  653. * NOTE: Currently deletes data -no undo or record-keeping functionality
  654. *
  655. * @param $node
  656. * The current node including fields with the form element names and
  657. * submitted values
  658. *
  659. * @return
  660. * TRUE if the node was successfully deleted from drupal/chado; FALSE
  661. * otherwise
  662. *
  663. * @ingroup tripal_legacy_stock
  664. */
  665. function chado_stock_delete($node) {
  666. // Set stock in chado: is_obsolete = TRUE
  667. chado_query("DELETE FROM {stock} WHERE stock_id = :stock_id", [':stock_id' => $node->stock->stock_id]);
  668. //remove drupal node and all revisions
  669. db_query("DELETE FROM {chado_stock} WHERE nid = :nid", [':nid' => $node->nid]);
  670. }
  671. /**
  672. * Used by Tripal Chado Node API during sync'ing of nodes
  673. *
  674. * @ingroup tripal_legacy_stock
  675. */
  676. function chado_stock_chado_node_sync_create_new_node($new_node, $record) {
  677. $new_node->organism_id = $record->organism_id;
  678. $new_node->sname = $record->name;
  679. $new_node->uniquename = $record->uniquename;
  680. $new_node->type_id = $record->type_id;
  681. return $new_node;
  682. }
  683. /**
  684. * Implements hook_node_presave(). Acts on all content types.
  685. *
  686. * @ingroup tripal_legacy_stock
  687. */
  688. function tripal_stock_node_presave($node) {
  689. switch ($node->type) {
  690. // This step is for setting the title for the Drupal node. This title
  691. // is permanent and thus is created to be unique. Title changes provided
  692. // by tokens are generated on the fly dynamically, but the node title
  693. // seen in the content listing needs to be set here. Do not call
  694. // the chado_get_node_title() function here to set the title as the node
  695. // object isn't properly filled out and the function will fail.
  696. case 'chado_stock':
  697. // For a form submission the fields are part of the node object
  698. // but for a sync the fields are in an object of the node.
  699. $organism_id = NULL;
  700. $sname = '';
  701. $uniquename = '';
  702. $type = '';
  703. if (property_exists($node, 'organism_id')) {
  704. $organism_id = $node->organism_id;
  705. $sname = $node->sname;
  706. $uniquename = $node->uniquename;
  707. $type_id = $node->type_id;
  708. $values = ['cvterm_id' => $node->type_id];
  709. $cvterm = chado_select_record('cvterm', ['name'], $values);
  710. $type = $cvterm[0]->name;
  711. }
  712. else {
  713. if (property_exists($node, 'stock')) {
  714. $organism_id = $node->stock->organism_id;
  715. $sname = $node->stock->name;
  716. $uniquename = $node->stock->uniquename;
  717. $type = $node->stock->type_id->name;
  718. }
  719. }
  720. $values = ['organism_id' => $organism_id];
  721. $organism = chado_select_record('organism', [
  722. 'genus',
  723. 'species',
  724. ], $values);
  725. $node->title = "$sname, $uniquename ($type) " . $organism[0]->genus . ' ' . $organism[0]->species;
  726. break;
  727. }
  728. }
  729. /**
  730. * Implements hook_node_view(). Acts on all content types.
  731. *
  732. * @ingroup tripal_legacy_stock
  733. */
  734. function tripal_stock_node_view($node, $view_mode, $langcode) {
  735. switch ($node->type) {
  736. case 'chado_stock':
  737. if ($view_mode == 'full') {
  738. $node->content['tripal_stock_base'] = [
  739. '#theme' => 'tripal_stock_base',
  740. '#node' => $node,
  741. '#tripal_toc_id' => 'base',
  742. '#tripal_toc_title' => 'Overview',
  743. '#weight' => -100,
  744. ];
  745. $node->content['tripal_stock_collections'] = [
  746. '#theme' => 'tripal_stock_collections',
  747. '#node' => $node,
  748. '#tripal_toc_id' => 'collections',
  749. '#tripal_toc_title' => 'Stock Collections',
  750. ];
  751. $node->content['tripal_stock_properties'] = [
  752. '#theme' => 'tripal_stock_properties',
  753. '#node' => $node,
  754. '#tripal_toc_id' => 'properties',
  755. '#tripal_toc_title' => 'Properties',
  756. ];
  757. $node->content['tripal_stock_references'] = [
  758. '#theme' => 'tripal_stock_references',
  759. '#node' => $node,
  760. '#tripal_toc_id' => 'references',
  761. '#tripal_toc_title' => 'Cross References',
  762. ];
  763. $node->content['tripal_stock_relationships'] = [
  764. '#theme' => 'tripal_stock_relationships',
  765. '#node' => $node,
  766. '#tripal_toc_id' => 'relationships',
  767. '#tripal_toc_title' => 'Relationships',
  768. ];
  769. $node->content['tripal_stock_synonyms'] = [
  770. '#theme' => 'tripal_stock_synonyms',
  771. '#node' => $node,
  772. '#tripal_toc_id' => 'synonyms',
  773. '#tripal_toc_title' => 'Synonyms',
  774. ];
  775. $node->content['tripal_stock_publications'] = [
  776. '#theme' => 'tripal_stock_publications',
  777. '#node' => $node,
  778. '#tripal_toc_id' => 'publications',
  779. '#tripal_toc_title' => 'Publications',
  780. ];
  781. }
  782. if ($view_mode == 'teaser') {
  783. $node->content['tripal_stock_teaser'] = [
  784. '#theme' => 'tripal_stock_teaser',
  785. '#node' => $node,
  786. ];
  787. }
  788. break;
  789. case 'chado_organism':
  790. if ($view_mode == 'full') {
  791. $node->content['tripal_organism_stocks'] = [
  792. '#theme' => 'tripal_organism_stocks',
  793. '#node' => $node,
  794. '#tripal_toc_id' => 'stocks',
  795. '#tripal_toc_title' => 'Stocks',
  796. ];
  797. }
  798. break;
  799. }
  800. }
  801. /**
  802. * Implements hook_node_insert().
  803. * Acts on all content types.
  804. *
  805. * @ingroup tripal_legacy_stock
  806. */
  807. function tripal_stock_node_insert($node) {
  808. // set the URL path after inserting. We do it here because we do not
  809. // know the stock_id in the presave
  810. switch ($node->type) {
  811. case 'chado_stock':
  812. // We still don't have a fully loaded node object in this hook. Therefore,
  813. // we need to simulate one so that the right values are available for
  814. // the URL to be determined.
  815. $stock_id = chado_get_id_from_nid('stock', $node->nid);
  816. $stock = chado_generate_var('stock', ['stock_id' => $stock_id]);
  817. $stock = chado_expand_var($stock, 'field', 'stock.uniquename');
  818. $stock = chado_expand_var($stock, 'field', 'stock.description');
  819. $node->stock = $stock;
  820. // Set the Title.
  821. $node->title = chado_get_node_title($node);
  822. // Now use the API to set the path.
  823. chado_set_node_url($node);
  824. break;
  825. }
  826. }
  827. /**
  828. * Implements hook_node_update().
  829. * Acts on all content types.
  830. *
  831. * @ingroup tripal_legacy_stock
  832. */
  833. function tripal_stock_node_update($node) {
  834. // add items to other nodes, build index and search results
  835. switch ($node->type) {
  836. case 'chado_stock':
  837. // Set the Title.
  838. $node->title = chado_get_node_title($node);
  839. // Now use the API to set the path.
  840. chado_set_node_url($node);
  841. break;
  842. }
  843. }
  844. /**
  845. * Implements [content_type]_chado_node_default_title_format().
  846. *
  847. * Defines a default title format for the Chado Node API to set the titles on
  848. * Chado Stock nodes based on chado fields.
  849. */
  850. function chado_stock_chado_node_default_title_format() {
  851. return '[stock.name], [stock.uniquename] ([stock.type_id>cvterm.name]) [stock.organism_id>organism.genus] [stock.organism_id>organism.species]';
  852. }
  853. /**
  854. * Implements hook_chado_node_default_url_format().
  855. *
  856. * Designates a default URL format for stock nodes.
  857. */
  858. function chado_stock_chado_node_default_url_format() {
  859. return '/stock/[stock.organism_id>organism.genus]/[stock.organism_id>organism.species]/[stock.type_id>cvterm.name]/[stock.uniquename]';
  860. }
  861. /**
  862. * Implement hook_node_access().
  863. *
  864. * This hook allows node modules to limit access to the node types they define.
  865. *
  866. * @param $node
  867. * The node on which the operation is to be performed, or, if it does not yet
  868. * exist, the type of node to be created
  869. *
  870. * @param $op
  871. * The operation to be performed
  872. *
  873. * @param $account
  874. * A user object representing the user for whom the operation is to be
  875. * performed
  876. *
  877. * @return
  878. * If the permission for the specified operation is not set then return FALSE.
  879. * If the permission is set then return NULL as this allows other modules to
  880. * disable access. The only exception is when the $op == 'create'. We will
  881. * always return TRUE if the permission is set.
  882. *
  883. * @ingroup tripal_legacy_stock
  884. */
  885. function tripal_stock_node_access($node, $op, $account) {
  886. $node_type = $node;
  887. if (is_object($node)) {
  888. $node_type = $node->type;
  889. }
  890. if ($node_type == 'chado_stock') {
  891. if ($op == 'create') {
  892. if (!user_access('create chado_stock content', $account)) {
  893. return NODE_ACCESS_DENY;
  894. }
  895. return NODE_ACCESS_ALLOW;
  896. }
  897. if ($op == 'update') {
  898. if (!user_access('edit chado_stock content', $account)) {
  899. return NODE_ACCESS_DENY;
  900. }
  901. }
  902. if ($op == 'delete') {
  903. if (!user_access('delete chado_stock content', $account)) {
  904. return NODE_ACCESS_DENY;
  905. }
  906. }
  907. if ($op == 'view') {
  908. if (!user_access('access chado_stock content', $account)) {
  909. return NODE_ACCESS_DENY;
  910. }
  911. }
  912. return NODE_ACCESS_IGNORE;
  913. }
  914. }