tripal_feature.admin.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. /**
  3. * @file
  4. * Administration of features
  5. */
  6. /**
  7. * Launchpad for feature administration.
  8. *
  9. * @ingroup tripal_feature
  10. */
  11. function tripal_feature_admin_feature_view() {
  12. $output = '';
  13. // set the breadcrumb
  14. $breadcrumb = array();
  15. $breadcrumb[] = l('Home', '<front>');
  16. $breadcrumb[] = l('Administration', 'admin');
  17. $breadcrumb[] = l('Tripal', 'admin/tripal');
  18. $breadcrumb[] = l('Chado', 'admin/tripal/chado');
  19. $breadcrumb[] = l('Features', 'admin/tripal/chado/tripal_feature');
  20. drupal_set_breadcrumb($breadcrumb);
  21. // Add the view
  22. $view = views_embed_view('tripal_feature_admin_features','default');
  23. if (isset($view)) {
  24. $output .= $view;
  25. }
  26. else {
  27. $output .= '<p>The Feature module uses primarily views to provide an '
  28. . 'administrative interface. Currently one or more views needed for this '
  29. . 'administrative interface are disabled. <strong>Click each of the following links to '
  30. . 'enable the pertinent views</strong>:</p>';
  31. $output .= '<ul>';
  32. $output .= '<li>'.l('Features View', 'admin/tripal/chado/tripal_feature/views/features/enable').'</li>';
  33. $output .= '</ul>';
  34. }
  35. // Add a summary chart.
  36. //-----------------------------------
  37. // We are using the organism_feature_count materialized view as the source for our data.
  38. // Thus grab all the records from this materialized view.
  39. $organism_feature_count = chado_select_record(
  40. 'organism_feature_count',
  41. array('*'),
  42. array(),
  43. array('order_by' => array('genus' => 'ASC', 'species' => 'ASC', 'feature_type' => 'ASC', 'num_features' => 'DESC'))
  44. );
  45. // Initialize variables.
  46. $chart = array();
  47. $type_names = array();
  48. $organism_names = array();
  49. // Process each row of the materialzied view into the chart array.
  50. // Note: it's first keyed by type since each type will be a bar. Each type will have
  51. // a "bars" array with the start (y0) and end (y1) height on the bar for a given
  52. // organism. Finally we keep a record of the names of the types & organisms
  53. // for axis' and legend generation respectively.
  54. foreach ($organism_feature_count as $row) {
  55. // Build up the easy details for the current row's type. These will be overridden
  56. // multiple times but that's more efficient than checking each time.
  57. $chart[$row->cvterm_id]['cvterm_id'] = $row->cvterm_id;
  58. $chart[$row->cvterm_id]['name'] = $row->feature_type;
  59. // Save the name of the type and organism into their respective arrays
  60. // for generation of axis' and legends for the chart.
  61. $type_names[$row->cvterm_id] = $row->feature_type;
  62. $organism_names[$row->organism_id] = $row->genus . ' ' . $row->species;
  63. // Save information about the current organism. This isn't actually used by the
  64. // chart but can be used to debug the bar generation to follow.
  65. $chart[$row->cvterm_id]['organisms'][] = array(
  66. 'name' => $row->genus . ' ' . $row->species,
  67. 'value' => (int) $row->num_features
  68. );
  69. // Now to build the bar array with the start (y0) and end (y1) height on the
  70. // bar for a given organism.
  71. // NOTE: we cannot assume the types are all in order so store y0 & y1 in the
  72. // $chart[type] array.
  73. // If y0 has not yet been set for this type then we're starting with the first
  74. // chunk (organism) on the bar.
  75. if (!isset($chart[$row->cvterm_id]['y0'])) {
  76. $chart[$row->cvterm_id]['y0'] = 0;
  77. $chart[$row->cvterm_id]['y1'] = $row->num_features;
  78. }
  79. // Otherwise, add the next chunk (organism) on top of the pre-existing bar.
  80. else {
  81. $chart[$row->cvterm_id]['y0'] = $chart[$row->cvterm_id]['y1'];
  82. $chart[$row->cvterm_id]['y1'] = $chart[$row->cvterm_id]['y0'] + $row->num_features;
  83. }
  84. // Now save the bar chunk we just determined.
  85. $chart[$row->cvterm_id]['bars'][] = array(
  86. 'name' => $row->genus . ' ' . $row->species,
  87. 'y0' => $chart[$row->cvterm_id]['y0'],
  88. 'y1' => $chart[$row->cvterm_id]['y1'],
  89. );
  90. // We also need to keep track of the total number of features for a single bar (Type).
  91. $chart[$row->cvterm_id]['total_features'] = $chart[$row->cvterm_id]['y1'];
  92. }
  93. // Sort based on the total number of features.
  94. // NOTE: This changes the keys so it's no longer the organism/type_id.
  95. usort($chart, 'tripal_feature_admin_summary_sort');
  96. sort($type_names);
  97. sort($organism_names);
  98. // We also need to add information about the materialized views
  99. // so that admin can update it and know how recent the data is.
  100. $mview = db_query('
  101. SELECT mview_id, name, last_update
  102. FROM tripal_mviews
  103. WHERE mv_table=:mv_table',
  104. array(':mv_table' => 'organism_feature_count')
  105. )->fetchObject();
  106. // Save everything we just determined as a Drupal JS settings so that we have access to
  107. // it in our js script.
  108. drupal_add_js(array('tripalFeature' => array('admin' => array(
  109. 'summary' => $chart,
  110. 'types' => $type_names,
  111. 'organisms' => $organism_names,
  112. 'mviewUrl' => url('admin/tripal/schema/mviews/update/' . $mview->mview_id),
  113. 'mviewUable' => $mview->name,
  114. 'mviewLastUpdate' => format_date($mview->last_update),
  115. ))), 'setting');
  116. // Finally add all the javascript and css needed to render the chart.
  117. tripal_add_d3js();
  118. drupal_add_css(drupal_get_path('module','tripal_feature') . '/theme/css/tripal_feature.css');
  119. drupal_add_js(drupal_get_path('module','tripal_feature') . '/theme/js/tripalFeature.adminChart.js');
  120. return $output;
  121. }
  122. /**
  123. * Feature Settings page
  124. *
  125. * @ingroup tripal_feature
  126. */
  127. function tripal_feature_admin() {
  128. // FEATURE PAGE TITLES
  129. // Using the Chado Node: Title & Path API
  130. $details = array(
  131. 'module' => 'tripal_feature',
  132. 'content_type' => 'chado_feature',
  133. // An array of options to use under "Page Titles"
  134. // the key should be the token and the value should be the human-readable option
  135. 'options' => array(
  136. '[feature.name]' => 'Feature Name Only',
  137. '[feature.uniquename]' => 'Feature Unique Name Only',
  138. // there should always be one options matching the unique constraint.
  139. '[feature.name], [feature.uniquename] ([feature.type_id>cvterm.name]) [feature.organism_id>organism.genus] [feature.organism_id>organism.species]' => 'Unique Contraint: Includes the name, uniquename, type and scientific name'
  140. ),
  141. // the token indicating the unique constraint in the options array
  142. 'unique_option' => '[feature.name], [feature.uniquename] ([feature.type_id>cvterm.name]) [feature.organism_id>organism.genus] [feature.organism_id>organism.species]'
  143. );
  144. // This call adds the configuration form to your current form
  145. // This sub-form handles it's own validation & submit
  146. chado_add_admin_form_set_title($form, $form_state, $details);
  147. // FEATURE NODE URL
  148. // Using the Chado Node: Title & Path API
  149. $details = array(
  150. 'module' => 'tripal_feature',
  151. 'content_type' => 'chado_feature',
  152. // An array of options to use under "Page URL"
  153. // the key should be the token and the value should be the human-readable option
  154. 'options' => array(
  155. '/feature/[feature.feature_id]' => 'Feature ID',
  156. // there should always be one options matching the unique constraint.
  157. '/feature/[feature.organism_id>organism.genus]/[feature.organism_id>organism.species]/[feature.type_id>cvterm.name]/[feature.uniquename]' => 'Unique Contraint: Includes the name, uniquename, type and scientific name'
  158. )
  159. );
  160. // This call adds the configuration form to your current form
  161. // This sub-form handles it's own validation & submit
  162. chado_add_admin_form_set_url($form, $form_state, $details);
  163. // FEATURE BROWSER
  164. $form['browser'] = array(
  165. '#type' => 'fieldset',
  166. '#title' => t('Feature Browser'),
  167. '#collapsible' => TRUE,
  168. '#collapsed' => TRUE,
  169. );
  170. $form['browser']['browser_desc'] = array(
  171. '#markup' => t('A feature browser can be added to an organism page to allow users to quickly ' .
  172. 'access a feature. This will most likely not be the ideal mechanism for accessing feature ' .
  173. 'information, especially for large sites, but it will alow users exploring the site (such ' .
  174. 'as students) to better understand the data types available on the site.'),
  175. );
  176. $form['browser']['feature_types'] = array(
  177. '#title' => t('Feature Types'),
  178. '#type' => 'textarea',
  179. '#description' => t("Enter the Sequence Ontology (SO) terms for the feature types that " .
  180. "will be shown in the feature browser."),
  181. '#default_value' => variable_get('chado_browser_feature_types', 'gene mRNA'),
  182. );
  183. $form['browser']['set_browse_button'] = array(
  184. '#type' => 'submit',
  185. '#value' => t('Set Browser'),
  186. '#weight' => 2,
  187. );
  188. // FEATURE SUMMARY REPORT
  189. $form['summary'] = array(
  190. '#type' => 'fieldset',
  191. '#title' => t('Feature Summary Report'),
  192. '#collapsible' => TRUE,
  193. '#collapsed' => TRUE,
  194. );
  195. $form['summary']['feature_mapping'] = array(
  196. '#title' => 'Map feature types',
  197. '#description' => t('You may specify which Sequence Ontology (SO) terms to show in the ' .
  198. 'feature summary report by listing them in the following text area. Enter one per line. ' .
  199. 'If left blank, all SO terms for all features will be shown in the report. Only those terms ' .
  200. 'listed below will be shown in the report. Terms will appear in the report in the same order listed. To rename a ' .
  201. 'SO term to be more human readable form, use an \'=\' sign after the SO term (e.g. \'polypeptide = Protein\')'),
  202. '#type' => 'textarea',
  203. '#rows' => 15,
  204. '#default_value' => variable_get('tripal_feature_summary_report_mapping', ''),
  205. );
  206. $form['summary']['set_summary_button'] = array(
  207. '#type' => 'submit',
  208. '#value' => t('Set Summary'),
  209. '#weight' => 2,
  210. );
  211. return system_settings_form($form);
  212. }
  213. /**
  214. * Validate the feature settings forms
  215. *
  216. * @ingroup tripal_feature
  217. */
  218. function tripal_feature_admin_validate($form, &$form_state) {
  219. global $user; // we need access to the user info
  220. $job_args = array();
  221. variable_set('chado_browser_feature_types', $form_state['values']['feature_types']);
  222. switch ($form_state['values']['op']) {
  223. case t('Set Summary') :
  224. variable_set('tripal_feature_summary_report_mapping', $form_state['values']['feature_mapping']);
  225. break;
  226. }
  227. }
  228. /**
  229. * USort function for the admin summary chart.
  230. * Not meant to be called directly.
  231. */
  232. function tripal_feature_admin_summary_sort($a, $b) {
  233. if ($a['total_features'] == $b['total_features']) return 0;
  234. return $b['total_features'] - $a['total_features'];
  235. }