tripal_analysis.form.inc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. <?php
  2. /**
  3. * When editing or creating a new node of type 'chado_analysis' we need
  4. * a form. This function creates the form that will be used for this.
  5. *
  6. * @ingroup tripal_analysis
  7. */
  8. function chado_analysis_form($node, &$form_state) {
  9. $form = array();
  10. // Default values can come in the following ways:
  11. //
  12. // 1) as elements of the $node object. This occurs when editing an existing analysis
  13. // 2) in the $form_state['values'] array which occurs on a failed validation or
  14. // ajax callbacks from non submit form elements
  15. // 3) in the $form_state['input'[ array which occurs on ajax callbacks from submit
  16. // form elements and the form is being rebuilt
  17. //
  18. // set form field defaults
  19. $analysis_id = null;
  20. $analysisname = '';
  21. $program = '';
  22. $programversion = '';
  23. $algorithm = '';
  24. $sourcename = '';
  25. $sourceversion = '';
  26. $sourceuri = '';
  27. $timeexecuted = '';
  28. $description = '';
  29. $d_removed = array(); // lists removed properties
  30. $num_new = 0; // the number of new rows
  31. // if we are editing an existing node then the analysis is already part of the node
  32. if (property_exists($node, 'analysis')) {
  33. $analysis = $node->analysis;
  34. $analysis = tripal_core_expand_chado_vars($analysis, 'field', 'analysis.description');
  35. $analysis_id = $analysis->analysis_id;
  36. // get form defaults
  37. $analysisname = $analysis->analysisname;
  38. $program = $analysis->program;
  39. $programversion = $analysis->programversion;
  40. $algorithm = $analysis->algorithm;
  41. $sourcename = $analysis->sourcename;
  42. $sourceversion = $analysis->sourceversion;
  43. $sourceuri = $analysis->sourceuri;
  44. $timeexecuted = $analysis->timeexecuted;
  45. $description = $analysis->description;
  46. // set the organism_id in the form
  47. $form['analysis_id'] = array(
  48. '#type' => 'value',
  49. '#value' => $analysis->analysis_id,
  50. );
  51. }
  52. // if we are re constructing the form from a failed validation or ajax callback
  53. // then use the $form_state['values'] values
  54. if (array_key_exists('values', $form_state)) {
  55. $analysisname = $form_state['values']['analysisname'];
  56. $program = $form_state['values']['program'];
  57. $programversion = $form_state['values']['programversion'];
  58. $algorithm = $form_state['values']['algorithm'];
  59. $sourcename = $form_state['values']['sourcename'];
  60. $sourceversion = $form_state['values']['sourceversion'];
  61. $sourceuri = $form_state['values']['sourceuri'];
  62. $timeexecuted = $form_state['values']['timeexecuted'];
  63. $description = $form_state['values']['description'];
  64. $d_removed = $form_state['values']['removed'];
  65. $num_new = $form_state['values']['num_new'] ? $form_state['values']['num_new'] : 0;
  66. }
  67. // if we are re building the form from after submission (from ajax call) then
  68. // the values are in the $form_state['input'] array
  69. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  70. $analysisname = $form_state['input']['analysisname'];
  71. $program = $form_state['input']['program'];
  72. $programversion = $form_state['input']['programversion'];
  73. $algorithm = $form_state['input']['algorithm'];
  74. $sourcename = $form_state['input']['sourcename'];
  75. $sourceversion = $form_state['input']['sourceversion'];
  76. $sourceuri = $form_state['input']['sourceuri'];
  77. $timeexecuted = $form_state['input']['timeexecuted'];
  78. $description = $form_state['input']['description'];
  79. $d_removed = $form_state['input']['removed'];
  80. $num_new = $form_state['input']['num_new'] ? $form_state['input']['num_new'] : 0;
  81. }
  82. $form['title']= array(
  83. '#type' => 'value',
  84. '#default_value' => $node->title,
  85. );
  86. $form['analysisname']= array(
  87. '#type' => 'textfield',
  88. '#title' => t('Analysis Name'),
  89. '#required' => TRUE,
  90. '#default_value' => $analysisname,
  91. '#description' => t("This should be a brief name that
  92. describes the analysis succintly. This name will helps the user find analyses."),
  93. );
  94. $form['program']= array(
  95. '#type' => 'textfield',
  96. '#title' => t('Program'),
  97. '#required' => TRUE,
  98. '#default_value' => $program,
  99. '#description' => t("Program name, e.g. blastx, blastp, sim4, genscan."),
  100. );
  101. $form['programversion']= array(
  102. '#type' => 'textfield',
  103. '#title' => t('Program Version'),
  104. '#required' => TRUE,
  105. '#default_value' => $programversion,
  106. '#description' => t("Version description, e.g. TBLASTX 2.0MP-WashU [09-Nov-2000]. Enter 'n/a' if no version is available."),
  107. );
  108. $form['algorithm']= array(
  109. '#type' => 'textfield',
  110. '#title' => t('Algorithm'),
  111. '#required' => FALSE,
  112. '#default_value' => $algorithm,
  113. '#description' => t("Algorithm name, e.g. blast."),
  114. );
  115. $form['sourcename']= array(
  116. '#type' => 'textfield',
  117. '#title' => t('Source Name'),
  118. '#required' => TRUE,
  119. '#default_value' => $sourcename,
  120. '#description' => t('The name of the source data. This could be a file name, data set name or a
  121. small description for how the data was collected. For long descriptions use the description field below'),
  122. );
  123. $form['sourceversion']= array(
  124. '#type' => 'textfield',
  125. '#title' => t('Source Version'),
  126. '#required' => FALSE,
  127. '#default_value' => $sourceversion,
  128. '#description' => t('If the source dataset has a version, include it here'),
  129. );
  130. $form['sourceuri']= array(
  131. '#type' => 'textfield',
  132. '#title' => t('Source URI'),
  133. '#required' => FALSE,
  134. '#default_value' => $sourceuri,
  135. '#description' => t("This is a permanent URL or URI for the source of the analysis.
  136. Someone could recreate the analysis directly by going to this URI and
  137. fetching the source data (e.g. the blast database, or the training model)."),
  138. );
  139. // Get time saved in chado
  140. $default_time = $timeexecuted;
  141. $year = preg_replace("/^(\d+)-\d+-\d+ .*/", "$1", $default_time);
  142. $month = preg_replace("/^\d+-0?(\d+)-\d+ .*/", "$1", $default_time);
  143. $day = preg_replace("/^\d+-\d+-0?(\d+) .*/", "$1", $default_time);
  144. // If the time is not set, use current time
  145. if (!$default_time) {
  146. $default_time = REQUEST_TIME;
  147. $year = format_date($default_time, 'custom', 'Y');
  148. $month = format_date($default_time, 'custom', 'n');
  149. $day = format_date($default_time, 'custom', 'j');
  150. }
  151. $form['timeexecuted']= array(
  152. '#type' => 'date',
  153. '#title' => t('Time Executed'),
  154. '#required' => TRUE,
  155. '#default_value' => array(
  156. 'year' => $year,
  157. 'month' => $month,
  158. 'day' => $day,
  159. ),
  160. );
  161. $form['description']= array(
  162. '#type' => 'textarea',
  163. '#rows' => 15,
  164. '#title' => t('Materials & Methods (Description and/or Program Settings)'),
  165. '#required' => FALSE,
  166. '#default_value' => $description,
  167. '#description' => t('Please provide all necessary information to allow
  168. someone to recreate the analysis, including materials and methods
  169. for collection of the source data and performing the analysis'),
  170. );
  171. $form['properties'] = array(
  172. '#type' => 'fieldset',
  173. '#title' => t('Analysis Details'),
  174. '#description' => t('You may add additional properties by
  175. selecting a property type from the dropdown and adding text. You may add
  176. as many properties as desired by clicking the plus button on the right. To
  177. remove a property, click the minus button. If a property is not available
  178. you may add it by ' . l('adding the term', 'admin/tripal/tripal_cv/cvterm/add') . '
  179. to the <b>analysis_property</b> vocabulary within the <b>tripal</b> database'),
  180. );
  181. $form['properties']['table'] = array(
  182. '#type' => 'markup',
  183. '#value' => '',
  184. '#prefix' => '<div id="tripal-analysis-edit-properties-table">',
  185. '#suffix' => '</div>',
  186. );
  187. // get the analysis properties
  188. $properties_select = array();
  189. $properties_select[] = 'Select a Property';
  190. $properties_list = array();
  191. $sql = "
  192. SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
  193. FROM {cvterm} CVT
  194. INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
  195. WHERE
  196. CV.name = 'analysis_property' AND
  197. NOT CVT.is_obsolete = 1
  198. ORDER BY CVT.name ASC
  199. ";
  200. $prop_types = chado_query($sql);
  201. while ($prop = $prop_types->fetchObject()) {
  202. $properties_select[$prop->cvterm_id] = $prop->name;
  203. $properties_list[$prop->cvterm_id] = $prop;
  204. }
  205. // this array keeps track of all properties we have and allows the functions
  206. // below to select the next rank if a property is dupliated
  207. $ranks = array();
  208. // add in the properties from the Chado analysisprop table (only pertains to existing analyses)
  209. if ($analysis_id) {
  210. chado_analysis_node_form_add_analysisprop_table_props($form, $form_state, $analysis_id, $ranks, $d_removed);
  211. }
  212. // add in any new properties that have been added by the user through an AHAH callback
  213. chado_analysis_node_form_add_new_props($form, $form_state, $ranks, $d_removed);
  214. // add an empty row of field to allow for addition of a new property
  215. chado_analysis_node_form_add_new_empty_props($form, $form_state, $properties_select);
  216. $form['#theme'] = 'chado_analysis_form';
  217. return $form;
  218. }
  219. /**
  220. * This function is responsible for adding a blank row to the properties table for
  221. * adding a new property.
  222. */
  223. function chado_analysis_node_form_add_new_empty_props(&$form, &$form_state, $properties_select) {
  224. // get the field defaults either from $form_state['values'] or $form_state['input']
  225. $description = '';
  226. $text = '';
  227. $id = 0;
  228. if (array_key_exists('values', $form_state)) {
  229. $id = $form_state['values']['new_id'];
  230. $text = $form_state['values']['new_value'];
  231. }
  232. // if we have a property ID then get it's definition to display to the user
  233. if($id) {
  234. $values = array('cvterm_id' => $id);
  235. $cvterm = tripal_core_chado_select('cvterm', array('definition'), $values);
  236. if ($cvterm[0]->definition) {
  237. $description = $cvterm[0]->definition;
  238. }
  239. }
  240. $rows = 1;
  241. // add one more blank set of property fields
  242. $form['properties']['table']['new']["new_id"] = array(
  243. '#type' => 'select',
  244. '#options' => $properties_select,
  245. '#value' => $id,
  246. '#ajax' => array(
  247. 'callback' => "tripal_analysis_property_get_description",
  248. 'wrapper' => 'tripal-analysis-new_value',
  249. 'effect' => 'fade',
  250. 'method' => 'replace',
  251. ),
  252. );
  253. $form['properties']['table']['new']["new_value"] = array(
  254. '#type' => 'textarea',
  255. '#value' => $text,
  256. '#cols' => 50,
  257. '#rows' => $rows,
  258. '#prefix' => '<div id="tripal-analysis-new_value">',
  259. '#description' => $description,
  260. '#suffix' => '</div>',
  261. );
  262. $form['properties']['table']['new']["add"] = array(
  263. '#type' => 'button',
  264. '#value' => t('Add'),
  265. '#name' => 'add',
  266. '#ajax' => array(
  267. 'callback' => "tripal_analysis_property_ajax_update",
  268. 'wrapper' => 'tripal-analysis-edit-properties-table',
  269. 'effect' => 'fade',
  270. 'method' => 'replace',
  271. 'prevent' => 'click'
  272. ),
  273. // When this button is clicked, the form will be validated and submitted.
  274. // Therefore, we set custom submit and validate functions to override the
  275. // default form submit. In the validate function we set the form_state
  276. // to rebuild the form so the submit function never actually gets called,
  277. // but we need it or Drupal will run the default validate anyway.
  278. // we also set #limit_validation_errors to empty so fields that
  279. // are required that don't have values won't generate warnings.
  280. '#submit' => array('chado_anslysis_node_form_props_button_submit'),
  281. '#validate' => array('chado_anslysis_node_form_props_button_validate'),
  282. '#limit_validation_errors' => array(array('new_id')),
  283. );
  284. }
  285. /**
  286. * This function is used to rebuild the form if an ajax call is made vai a button.
  287. * The button causes the form to be submitted. We don't want this so we override
  288. * the validate and submit routines on the form button. Therefore, this function
  289. * only needs to tell Drupal to rebuild the form
  290. */
  291. function chado_anslysis_node_form_props_button_validate($form, &$form_state){
  292. if (array_key_exists('triggering_element', $form_state) and
  293. $form_state['triggering_element']['#name'] == 'add' and
  294. $form_state['input']['new_id'] == 0 ){
  295. form_set_error('new_id', "Please specify a property type");
  296. return;
  297. }
  298. $form_state['rebuild'] = TRUE;
  299. }
  300. /**
  301. * This function is just a dummy to override the default form submit on ajax calls for buttons
  302. */
  303. function chado_anslysis_node_form_props_button_submit($form, &$form_state){
  304. // do nothing
  305. }
  306. /**
  307. * This adds
  308. */
  309. function chado_analysis_node_form_add_new_props(&$form, &$form_state, &$ranks, &$d_removed) {
  310. // set some default values
  311. $j = 0;
  312. $num_properties = 0;
  313. $values = array();
  314. if (array_key_exists('values', $form_state)) {
  315. $values = $form_state['values'];
  316. }
  317. if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
  318. $values = $form_state['input'];
  319. }
  320. // first, add in all of the new properties that were added previously via this form
  321. foreach ($values as $element_name => $value) {
  322. if (preg_match('/new_value-(\d+)-(\d+)/', $element_name, $matches)) {
  323. $new_id = $matches[1];
  324. $rank = $matches[2];
  325. // skip any properties that the user requested to delete through a previous
  326. // ajax callback or through the current ajax callback
  327. if (array_key_exists("$new_id-$rank", $d_removed)) {
  328. continue;
  329. }
  330. if (array_key_exists('triggering_element', $form_state) and
  331. $form_state['triggering_element']['#name'] == 'remove-' . $new_id . '-' . $rank) {
  332. $d_removed["$new_id-$rank"] = 1;
  333. continue;
  334. }
  335. // get this new_id information
  336. $args = array('cvterm_id' => $new_id);
  337. $cvterm = tripal_core_chado_select('cvterm', array('name', 'definition'), $args);
  338. // add it to the $ranks array
  339. $ranks[$new_id][$rank]['name'] = $cvterm[0]->name;
  340. $ranks[$new_id][$rank]['id'] = $new_id;
  341. $ranks[$new_id][$rank]['value'] = $value;
  342. $ranks[$new_id][$rank]['definition'] = $cvterm[0]->definition;
  343. $num_properties++;
  344. // determine how many rows we need in the textarea
  345. $rows = 1;
  346. // add the new fields
  347. $form['properties']['table']['new'][$new_id][$rank]["new_id-$new_id-$rank"] = array(
  348. '#markup' => $cvterm[0]->name
  349. );
  350. $form['properties']['table']['new'][$new_id][$rank]["new_value-$new_id-$rank"] = array(
  351. '#type' => 'textarea',
  352. '#default_value' => $value,
  353. '#cols' => 50,
  354. '#rows' => $rows,
  355. '#description' => $cvterm[0]->definition,
  356. );
  357. $form['properties']['table']['new'][$new_id][$rank]["remove-$new_id-$rank"] = array(
  358. '#type' => 'button',
  359. '#value' => t('Remove'),
  360. '#name' => "remove-$new_id-$rank",
  361. '#ajax' => array(
  362. 'callback' => "tripal_analysis_property_ajax_update",
  363. 'wrapper' => 'tripal-analysis-edit-properties-table',
  364. 'effect' => 'fade',
  365. 'event' => 'mousedown',
  366. 'method' => 'replace',
  367. 'prevent' => 'click'
  368. ),
  369. // When this button is clicked, the form will be validated and submitted.
  370. // Therefore, we set custom submit and validate functions to override the
  371. // default form submit. In the validate function we set the form_state
  372. // to rebuild the form so the submit function never actually gets called,
  373. // but we need it or Drupal will run the default validate anyway.
  374. // we also set #limit_validation_errors to empty so fields that
  375. // are required that don't have values won't generate warnings.
  376. '#submit' => array('chado_anslysis_node_form_props_button_submit'),
  377. '#validate' => array('chado_anslysis_node_form_props_button_validate'),
  378. '#limit_validation_errors' => array(),
  379. );
  380. }
  381. }
  382. // second add in any new properties added during this callback
  383. if (array_key_exists('triggering_element', $form_state) and
  384. $form_state['triggering_element']['#name'] == 'add' and
  385. $form_state['input']['new_id'] != 0) {
  386. $new_id = $form_state['input']['new_id'];
  387. $new_value = $form_state['input']['new_value'];
  388. // get the rank by counting the number of entries
  389. $rank = count($ranks[$new_id]);
  390. // get this new_id information
  391. $cvterm = tripal_core_chado_select('cvterm', array('name', 'definition'), array('cvterm_id' => $new_id));
  392. // add it to the $ranks array
  393. $ranks[$new_id][$rank]['name'] = $cvterm[0]->name;
  394. $ranks[$new_id][$rank]['id'] = $new_id;
  395. $ranks[$new_id][$rank]['value'] = $value;
  396. $ranks[$new_id][$rank]['definition'] = $cvterm[0]->definition;
  397. $num_properties++;
  398. // determine how many rows we need in the textarea
  399. $rows = 1;
  400. // add the new fields
  401. $form['properties']['table']['new'][$new_id][$rank]["new_id-$new_id-$rank"] = array(
  402. '#markup' => $cvterm[0]->name
  403. );
  404. $form['properties']['table']['new'][$new_id][$rank]["new_value-$new_id-$rank"] = array(
  405. '#type' => 'textarea',
  406. '#default_value' => $new_value,
  407. '#cols' => 50,
  408. '#rows' => $rows,
  409. '#description' => $cvterm[0]->definition,
  410. );
  411. $form['properties']['table']['new'][$new_id][$rank]["remove-$new_id-$rank"] = array(
  412. '#type' => 'button',
  413. '#value' => t('Remove'),
  414. '#name' => "remove-$new_id-$rank",
  415. '#ajax' => array(
  416. 'callback' => "tripal_analysis_property_ajax_update",
  417. 'wrapper' => 'tripal-analysis-edit-properties-table',
  418. 'effect' => 'fade',
  419. 'event' => 'mousedown',
  420. 'method' => 'replace',
  421. 'prevent' => 'click'
  422. ),
  423. // When this button is clicked, the form will be validated and submitted.
  424. // Therefore, we set custom submit and validate functions to override the
  425. // default form submit. In the validate function we set the form_state
  426. // to rebuild the form so the submit function never actually gets called,
  427. // but we need it or Drupal will run the default validate anyway.
  428. // we also set #limit_validation_errors to empty so fields that
  429. // are required that don't have values won't generate warnings.
  430. '#submit' => array('chado_anslysis_node_form_props_button_submit'),
  431. '#validate' => array('chado_anslysis_node_form_props_button_validate'),
  432. '#limit_validation_errors' => array(),
  433. );
  434. }
  435. return $num_properties;
  436. }
  437. /*
  438. *
  439. */
  440. function chado_analysis_node_form_add_analysisprop_table_props(&$form, $form_state, $analysis_id, &$ranks, &$d_removed) {
  441. // get the properties for this analysis
  442. $num_properties = 0;
  443. if (!$analysis_id) {
  444. return $num_properties;
  445. }
  446. $sql = "
  447. SELECT CVT.cvterm_id, CVT.name, CVT.definition, PP.value, PP.rank
  448. FROM {analysisprop} PP
  449. INNER JOIN {cvterm} CVT on CVT.cvterm_id = PP.type_id
  450. INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
  451. WHERE PP.analysis_id = :analysis_id and CV.name = 'analysis_property'
  452. ORDER BY CVT.name, PP.rank
  453. ";
  454. $analysis_props = chado_query($sql, array(':analysis_id' => $analysis_id));
  455. while ($prop = $analysis_props->fetchObject()) {
  456. $type_id = $prop->cvterm_id;
  457. $rank = count($ranks[$type_id]);
  458. // skip any properties that the user requested to delete through a previous
  459. // AHAH callback or through the current AHAH callback
  460. if (array_key_exists("$type_id-$rank", $d_removed)) {
  461. continue;
  462. }
  463. if (array_key_exists('triggering_element', $form_state) and
  464. $form_state['triggering_element']['#name'] == 'remove-' . $type_id . '-' . $rank) {
  465. $d_removed["$type_id-$rank"] = 1;
  466. continue;
  467. }
  468. $ranks[$type_id][$rank]['name'] = $prop->name;
  469. $ranks[$type_id][$rank]['id'] = $type_id;
  470. $ranks[$type_id][$rank]['value'] = $prop->value;
  471. $ranks[$type_id][$rank]['definition'] = $prop->definition;
  472. $num_properties++;
  473. $form['properties']['table'][$type_id][$rank]["prop_id-$type_id-$rank"] = array(
  474. '#type' => 'item',
  475. '#value' => $prop->name,
  476. );
  477. $form['properties']['table'][$type_id][$rank]["prop_value-$type_id-$rank"] = array(
  478. '#type' => 'textarea',
  479. '#default_value' => $prop->value,
  480. '#cols' => 50,
  481. '#rows' => $rows,
  482. '#description' => $prop->definition,
  483. );
  484. $form['properties']['table'][$type_id][$rank]["remove-$type_id-$rank"] = array(
  485. '#type' => 'button',
  486. '#value' => t('Remove'),
  487. '#name' => "remove-$type_id-$rank",
  488. '#ajax' => array(
  489. 'callback' => "tripal_analysis_property_ajax_update",
  490. 'wrapper' => 'tripal-analysis-edit-properties-table',
  491. 'effect' => 'fade',
  492. 'event' => 'mousedown',
  493. 'method' => 'replace',
  494. 'prevent' => 'click'
  495. ),
  496. // When this button is clicked, the form will be validated and submitted.
  497. // Therefore, we set custom submit and validate functions to override the
  498. // default form submit. In the validate function we set the form_state
  499. // to rebuild the form so the submit function never actually gets called,
  500. // but we need it or Drupal will run the default validate anyway.
  501. // we also set #limit_validation_errors to empty so fields that
  502. // are required that don't have values won't generate warnings.
  503. '#submit' => array('chado_anslysis_node_form_props_button_submit'),
  504. '#validate' => array('chado_anslysis_node_form_props_button_validate'),
  505. '#limit_validation_errors' => array(),
  506. );
  507. }
  508. return $num_properties;
  509. }
  510. /**
  511. * Validates the user input before creating an analysis node
  512. *
  513. * @ingroup tripal_analysis
  514. */
  515. function chado_analysis_validate($node, &$form) {
  516. // use the analysis parent to validate the node
  517. tripal_analysis_validate($node, $form);
  518. }
  519. /**
  520. * This validation is being used for three activities:
  521. * CASE A: Update a node that exists in both drupal and chado
  522. * CASE B: Synchronizing a node from chado to drupal
  523. * CASE C: Inserting a new node that exists in niether drupal nor chado
  524. *
  525. * @ingroup tripal_analysis
  526. */
  527. function tripal_analysis_validate($node, $form, &$form_state) {
  528. $node->analysisname = trim($node->analysisname);
  529. $node->description = trim($node->description);
  530. $node->program = trim($node->program);
  531. $node->programversion = trim($node->programversion);
  532. $node->algorithm = trim($node->algorithm);
  533. $node->sourcename = trim($node->sourcename);
  534. $node->sourceversion = trim($node->sourceversion);
  535. $node->sourceuri = trim($node->sourceuri);
  536. // Only nodes being updated will have an nid already
  537. if (!is_null($node->nid)) {
  538. // CASE A: We are validating a form for updating an existing node
  539. // get the existing node
  540. $values = array('analysis_id' => $node->analysis_id);
  541. $result = tripal_core_chado_select('analysis', array('*'), $values);
  542. $analysis = $result[0];
  543. // if the name has changed make sure it doesn't conflict with an existing name
  544. if ($analysis->name != $node->analysisname) {
  545. $values = array('name' => $node->analysisname);
  546. $result = tripal_core_chado_select('analysis', array('analysis_id'), $values);
  547. if ($result and count($result) > 0) {
  548. form_set_error('analysisname', 'Cannot update the analysis with this analysis name. An analysis with this name already exists.');
  549. return;
  550. }
  551. }
  552. // if the unique constraint has changed check to make sure it doesn't conflict with an
  553. // existing record
  554. if ($analysis->program != $node->program or $analysis->programversion != $node->programversion or
  555. $analysis->sourcename != $node->sourcename) {
  556. $values = array(
  557. 'program' => $node->program,
  558. 'programversion' => $node->programversion,
  559. 'sourcename' => $node->sourcename,
  560. );
  561. $result = tripal_core_chado_select('analysis', array('analysis_id'), $values);
  562. if ($result and count($result) > 0) {
  563. if ($analysis->program != $node->program) {
  564. $field = 'program';
  565. }
  566. if ($analysis->programversion != $node->programversion) {
  567. $field = 'programversion';
  568. }
  569. if ($analysis->sourcename != $node->sourcename) {
  570. $field = 'sourcename';
  571. }
  572. form_set_error($field, 'Cannot update the analysis with this program,
  573. program version and source name. An analysis with these values already exists.');
  574. return;
  575. }
  576. }
  577. }
  578. else {
  579. // To differentiate if we are syncing or creating a new analysis altogther, see if an
  580. // analysis_id already exists
  581. if ($node->analysis_id and $node->analysis_id != 0) {
  582. // CASE B: Synchronizing a node from chado to drupal
  583. // we don't need to do anything.
  584. }
  585. else {
  586. // CASE C: We are validating a form for inserting a new node
  587. // The unique constraint for the chado analysis table is: program, programversion, sourcename
  588. $values = array(
  589. 'program' => $node->program,
  590. 'programversion' => $node->programversion,
  591. 'sourcename' => $node->sourcename,
  592. );
  593. $analysis = tripal_core_chado_select('analysis', array('analysis_id'), $values);
  594. if ($analysis and count($analysis) > 0) {
  595. form_set_error('program', 'Cannot add the analysis with this program,
  596. program version and source name. An analysis with these values already exists.');
  597. return;
  598. }
  599. // make sure we have a unique analysis name. This is not a requirement
  600. // for the analysis table but we use the analysis name for the Drupal node
  601. // title, so it should be unique
  602. $values = array('name' => $node->analysisname);
  603. $result = tripal_core_chado_select('analysis', array('analysis_id'), $values);
  604. if ($result and count($result) > 0) {
  605. form_set_error('analysisname', 'Cannot add the analysis with this analysis name. An analysis with this name already exists.');
  606. return;
  607. }
  608. }
  609. }
  610. }
  611. /*
  612. *
  613. */
  614. function tripal_analysis_theme_node_form_properties($form) {
  615. $rows = array();
  616. if (array_key_exists('properties', $form)) {
  617. // first add in the properties derived from the analysisprop table
  618. // the array tree for these properties looks like this:
  619. // $form['properties']['table'][$type_id][$rank]["prop_id-$type_id-$rank"]
  620. foreach ($form['properties']['table'] as $type_id => $elements) {
  621. // there are other fields in the properties array so we only
  622. // want the numeric ones those are our type_id
  623. if (is_numeric($type_id)) {
  624. foreach ($elements as $rank => $element) {
  625. if (is_numeric($rank)) {
  626. $rows[] = array(
  627. drupal_render($element["prop_id-$type_id-$rank"]),
  628. drupal_render($element["prop_value-$type_id-$rank"]),
  629. drupal_render($element["remove-$type_id-$rank"]),
  630. );
  631. }
  632. }
  633. }
  634. }
  635. // second, add in any new properties added by the user through AHAH callbacks
  636. // the array tree for these properties looks like this:
  637. // $form['properties']['table']['new'][$type_id][$rank]["new_id-$new_id-$rank"]
  638. foreach ($form['properties']['table']['new'] as $type_id => $elements) {
  639. if (is_numeric($type_id)) {
  640. foreach ($elements as $rank => $element) {
  641. if (is_numeric($rank)) {
  642. $rows[] = array(
  643. drupal_render($element["new_id-$type_id-$rank"]),
  644. drupal_render($element["new_value-$type_id-$rank"]),
  645. drupal_render($element["remove-$type_id-$rank"]),
  646. );
  647. }
  648. }
  649. }
  650. }
  651. // finally add in a set of blank field for adding a new property
  652. $rows[] = array(
  653. drupal_render($form['properties']['table']['new']['new_id']),
  654. array(
  655. 'data' => drupal_render($form['properties']['table']['new']['new_value']),
  656. 'width' => '60%',
  657. ),
  658. drupal_render($form['properties']['table']['new']['add']),
  659. );
  660. }
  661. $headers = array('Property Type', 'Value', 'Actions');
  662. $table = array(
  663. 'header' => $headers,
  664. 'rows' => $rows,
  665. 'attributes' => array(),
  666. 'sticky' => TRUE,
  667. 'caption' => '',
  668. 'colgroups' => array(),
  669. 'empty' => '',
  670. );
  671. return theme_table($table);
  672. }
  673. /**
  674. * Form AJAX callback for adding a blank property row
  675. *
  676. * We only want to return the properties as that's all we'll replace with this callback
  677. */
  678. function tripal_analysis_property_ajax_update($form, $form_state) {
  679. $properties_html = tripal_analysis_theme_node_form_properties($form);
  680. $form['properties']['table'] = array(
  681. '#markup' => $properties_html,
  682. '#prefix' => '<div id="tripal-analysis-edit-properties-table">',
  683. '#suffix' => '</div>',
  684. );
  685. return $form['properties']['table'];
  686. }
  687. /**
  688. * Form AJAX callback for updating a property description. This
  689. * function only gets called when the property drop down is changed
  690. * on the bottom (empty) row of properties
  691. */
  692. function tripal_analysis_property_get_description($form, $form_state) {
  693. return $form['properties']['table']['new']["new_value"];
  694. }
  695. /**
  696. * We need to theme the analysis form so that the properties fields look good
  697. */
  698. function theme_chado_analysis_form($variables) {
  699. $form = $variables['form'];
  700. $properties_table = tripal_analysis_theme_node_form_properties($form);
  701. $markup = $properties_table;
  702. $form['properties']['table'] = array(
  703. '#markup' => $markup,
  704. '#prefix' => '<div id="tripal-analysis-edit-properties-table">',
  705. '#suffix' => '</div>',
  706. );
  707. $form['buttons']['#weight'] = 50;
  708. return drupal_render_children($form);
  709. }