tripal_entities.admin.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <?php
  2. /**
  3. * Provide a data listing for tripal entites (ie: biological data).
  4. *
  5. * This function is a callback in a menu item which is set in the
  6. * TripalEntityUIController class.
  7. */
  8. function tripal_entities_content_view() {
  9. // Retrieve our data listing form and render it.
  10. $form = drupal_get_form('tripal_entities_content_overview_form');
  11. $output = drupal_render($form);
  12. // Set the breadcrumb.
  13. $breadcrumb = array();
  14. $breadcrumb[] = l('Home', '<front>');
  15. $breadcrumb[] = l('Administration', 'admin');
  16. drupal_set_breadcrumb($breadcrumb);
  17. return $output;
  18. }
  19. /**
  20. * Display a listing of Tripal entities.
  21. *
  22. * @TODO Filters and bulk operations needed to be added to this form.
  23. *
  24. * @param array $form
  25. * @param array $form_state
  26. * @return
  27. * A form array describing this listing to the Form API.
  28. */
  29. function tripal_entities_content_overview_form($form, &$form_state) {
  30. // Set the title to be informative (defaults to content for some reason).
  31. drupal_set_title('Biological Data');
  32. // Retrieve a pages list of all tripal entitles (ie: biological data).
  33. // This will return the 25 most recently created entities.
  34. $entities = db_select('tripal_entity', 'td')
  35. ->fields('td')
  36. ->orderBy('created', 'DESC')//ORDER BY created
  37. ->range(0,25)
  38. ->execute();
  39. $headers = array('Title', 'Vocabulary', 'Term', 'Author', 'Status', 'Updated', 'Operations');
  40. $rows = array();
  41. // For each entity retrieved add a row to the data listing.
  42. while ($entity = $entities->fetchObject()) {
  43. // Retrieve details about the term this entity is based on.
  44. $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $entity->cvterm_id));
  45. // Retrieve details about the user who created this data.
  46. $author = user_load($entity->uid);
  47. // Add information to the table.
  48. $rows[] = array(
  49. l($entity->title, 'bio-data/' . $entity->id),
  50. $cvterm->cv_id->name . ' (' . $cvterm->dbxref_id->db_id->name . ')',
  51. $cvterm->name,
  52. l($author->name, 'user/' . $entity->uid),
  53. $entity->status == 1 ? 'published' : 'unpublished',
  54. format_date($entity->changed, 'short'),
  55. l('edit', 'bio-data/' . $entity->id . '/edit') . '&nbsp;&nbsp;' .
  56. l('delete', 'bio-data/' . $entity->id . '/delete')
  57. );
  58. }
  59. // If there are no entites created yet then add a message to the table to
  60. // provide guidance to administrators.
  61. if (empty($rows)) {
  62. $rows[] = array(
  63. array(
  64. 'data' => t('No biological data available.'),
  65. 'colspan' => 7
  66. )
  67. );
  68. }
  69. // Render the data listing.
  70. $table_vars = array(
  71. 'header' => $headers,
  72. 'rows' => $rows,
  73. 'attributes' => array(),
  74. 'sticky' => TRUE,
  75. 'caption' => '',
  76. 'colgroups' => array(),
  77. 'empty' => '',
  78. );
  79. $form['results'] = array(
  80. '#type' => 'markup',
  81. '#markup' => theme('table', $table_vars),
  82. );
  83. return $form;
  84. }
  85. /**
  86. * Form for creating tripal data types.
  87. *
  88. * This form is available on the menu at Admin >> Structure >> Biological Data
  89. * Types
  90. *
  91. * @param array $form
  92. * @param array $form_state
  93. *
  94. * @return
  95. * An array describing this form to the Form API.
  96. */
  97. function tripal_entities_admin_add_type_form($form, &$form_state) {
  98. $term_name = '';
  99. $num_terms = 0;
  100. $cv_id = '';
  101. // Set defaults using the form state.
  102. if (array_key_exists('input', $form_state)) {
  103. if (array_key_exists('term_name', $form_state['input'])) {
  104. $term_name = $form_state['input']['term_name'];
  105. }
  106. if (array_key_exists('cv_id', $form_state['input'])) {
  107. $cv_id = $form_state['input']['cv_id'];
  108. }
  109. // If a term and cv_id are provided then we can look for the term using
  110. // both and we should find a unique term. If only ther term is provided
  111. // we can still look for a unique term but there must only be one.
  112. if ($term_name and !$cv_id) {
  113. $match = array(
  114. 'name' => $term_name,
  115. );
  116. }
  117. else {
  118. $match = array(
  119. 'name' => $term_name,
  120. 'cv_id' => $cv_id,
  121. );
  122. }
  123. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  124. $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
  125. $num_terms = count($terms);
  126. }
  127. // If no term has been selected yet then provide the auto complete field.
  128. if ($num_terms == 0) {
  129. $form['term_name'] = array(
  130. '#title' => t('Content Type'),
  131. '#type' => 'textfield',
  132. '#description' => t("The content type must be the name of a term in
  133. a controlled vocabulary and the controlled vocabulary should
  134. already be loaded into Tripal. For example, to create a content
  135. type for storing 'genes', use the 'gene' term from the
  136. Sequence Ontology (SO)."),
  137. '#required' => TRUE,
  138. '#default_value' => $term_name,
  139. '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv_id",
  140. );
  141. }
  142. else {
  143. $form['term_name'] = array(
  144. '#type' => 'hidden',
  145. '#value' => $term_name,
  146. );
  147. }
  148. // If the term belongs to more than one vocabulary then add additional fields
  149. // to let the user select the vocabulary.
  150. if ($num_terms > 1) {
  151. $cvs = array();
  152. foreach ($terms as $term) {
  153. $cvs[$term->cv_id->cv_id] = 'Vocabulary: <b>' . $term->cv_id->name . '</b> (' . $term->cv_id->definition . ')<br>' . $term->name . ': ' . $term->definition;
  154. }
  155. $form['cv_id'] = array(
  156. '#type' => 'radios',
  157. '#title' => t('Select the appropriate vocabulary'),
  158. '#options' => $cvs,
  159. );
  160. }
  161. // Add in the button for the cases of no terms or too many.
  162. $form['select_button'] = array(
  163. '#type' => 'submit',
  164. '#value' => t('Use this term'),
  165. '#name' => 'select_cvterm'
  166. );
  167. return $form;
  168. }
  169. /**
  170. * Implements hook_validate() for the tripal_entities_admin_publish_form.
  171. *
  172. */
  173. function tripal_entities_admin_add_type_form_validate($form, &$form_state) {
  174. if (array_key_exists('clicked_button', $form_state) and
  175. $form_state['clicked_button']['#name'] =='select_cvterm') {
  176. // First, make sure the term is unique. If not then we can't check it.
  177. $term_name = NULL;
  178. $cv_id = NULL;
  179. $cvterm = NULL;
  180. if (array_key_exists('term_name', $form_state['values'])) {
  181. $term_name = $form_state['input']['term_name'];
  182. }
  183. if (array_key_exists('cv_id', $form_state['input'])) {
  184. $cv_id = $form_state['input']['cv_id'];
  185. }
  186. // If a term and cv_id are provided then we can look for the term using
  187. // both and we should find a unique term. If only ther term is provided
  188. // we can still look for a unique term but there must only be one.
  189. if ($term_name and !$cv_id) {
  190. $match = array(
  191. 'name' => $term_name,
  192. );
  193. }
  194. else {
  195. $match = array(
  196. 'name' => $term_name,
  197. 'cv_id' => $cv_id,
  198. );
  199. }
  200. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  201. $form_state['storage']['terms'] = $terms;
  202. // If we do not have any terms then the term provided by the user does not
  203. // exists and we need to provide an error message.
  204. if (count($terms) == 0) {
  205. form_set_error('term_name', t('The term does not exist in this database.'));
  206. }
  207. // If we have more than one term then we need to set an error so that the
  208. // form can provide a list of vocabularies to select from.
  209. if (count($terms) > 1) {
  210. form_set_error('term_name', t('The term is not unique. A list of vocabularies
  211. that contain this term. Please select the most appropriate vocabulary.'));
  212. }
  213. }
  214. }
  215. /**
  216. * Implements hook_submit() for the tripal_entities_admin_publish_form.
  217. *
  218. */
  219. function tripal_entities_admin_add_type_form_submit($form, &$form_state) {
  220. if ($form_state['clicked_button']['#name'] =='select_cvterm') {
  221. $cvterm = $form_state['storage']['terms'][0];
  222. $bundle_id = 'bio-data_' . $cvterm->cvterm_id;
  223. // Before we try to add this type, check to see if it already exists
  224. // as a bundle.
  225. $einfo = entity_get_info('TripalEntity');
  226. if (!in_array($bundle_id, array_keys($einfo['bundles']))) {
  227. $error = '';
  228. $success = tripal_create_entity_type($cvterm, $error);
  229. if (!$success) {
  230. drupal_set_message($error, 'error');
  231. $form_state['redirect'] = "admin/structure/bio-data";
  232. }
  233. else {
  234. drupal_set_message('New biological data type created. Fields are added automatically to this type.');
  235. $form_state['redirect'] = "admin/structure/bio-data";
  236. }
  237. }
  238. else {
  239. drupal_set_message('This type already exists.', 'warning');
  240. }
  241. }
  242. }
  243. /**
  244. * Implements hook_add_bundle_fields().
  245. *
  246. * @param $entity_type_name
  247. * @param $bundle_id
  248. * @param $cvterm
  249. */
  250. function tripal_entities_add_bundle_fields($entity_type_name, $bundle_id, $cvterm) {
  251. // Adds the fields for the base table to the entity.
  252. tripal_entities_add_bundle_base_fields($entity_type_name, $bundle_id, $cvterm);
  253. // Check to see if there are any kv-property tables associated to this
  254. // base table. If so, add the fields for that type of table.
  255. tripal_entities_add_bundle_kvproperty_adder_field($entity_type_name, $bundle_id, 'featureprop');
  256. }
  257. /**
  258. * Adds the fields for a kv-property table fields
  259. *
  260. * @param $entity_type_name
  261. * @param $bundle_id
  262. * @param $kv_table
  263. */
  264. function tripal_entities_add_bundle_kvproperty_adder_field($entity_type_name, $bundle_id, $kv_table) {
  265. // First add a generic property field so that users can add new proeprty types.
  266. $field_name = $kv_table;
  267. // Initialize the field array.
  268. $field_info = array(
  269. 'field_type' => 'kvproperty_adder',
  270. 'widget_type' => 'tripal_fields_kvproperty_adder_widget',
  271. 'field_settings' => array(),
  272. 'widget_settings' => array('display_label' => 1),
  273. 'description' => '',
  274. 'label' => 'Additional Properties',
  275. 'is_required' => 0,
  276. );
  277. tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_id);
  278. }
  279. /**
  280. * Adds the fields for the base table to the entity.
  281. */
  282. function tripal_entities_add_bundle_base_fields($entity_type_name, $bundle_id, $cvterm) {
  283. // Get the details for this bundle
  284. $bundle = db_select('tripal_bundle', 't')
  285. ->fields('t')
  286. ->condition('type', 'TripalEntity')
  287. ->condition('bundle', $bundle_id)
  288. ->execute()
  289. ->fetchObject();
  290. $bundle_data = unserialize($bundle->data);
  291. $table_name = $bundle_data['data_table'];
  292. $type_table = $bundle_data['type_table'];
  293. $type_field = $bundle_data['field'];
  294. // Iterate through the columns of the table and see if fields have been
  295. // created for each one. If not, then create them.
  296. $schema = chado_get_schema($table_name);
  297. $columns = $schema['fields'];
  298. foreach ($columns as $column_name => $details) {
  299. $field_name = $table_name . '__' . $column_name;
  300. // Skip the primary key field.
  301. if ($column_name == $schema['primary key'][0]) {
  302. continue;
  303. }
  304. // Skip the type field.
  305. if ($table_name == $type_table and $column_name == $type_field) {
  306. continue;
  307. }
  308. // Get the field defaults for this column.
  309. $field_info = tripal_entities_get_table_column_field_default($table_name, $schema, $column_name);
  310. // Determine if the field is required.
  311. if (array_key_exists('not null', $details) and $details['not null'] === TRUE) {
  312. $field_info['is_required'] = array_key_exists('default', $details) ? 0 : 1;
  313. }
  314. // If we don't have a field type then we don't need to create a field.
  315. if (!$field_info['field_type']) {
  316. // If we don't have a field type but it is required and doesn't have
  317. // a default value then we are in trouble.
  318. if ($field_info['is_required'] and !array_key_exists('default', $details)) {
  319. throw new Exception(t('The %table.%field type, %type, is not yet supported for Entity fields, but it is required,',
  320. array('%table' => $table_name, '%field' => $column_name, '%type' => $details['type'])));
  321. }
  322. continue;
  323. }
  324. // If this field is a foreign key field then we will have a special custom
  325. // field provided by Tripal.
  326. $is_fk = FALSE;
  327. if (array_key_exists('foreign keys', $schema)) {
  328. foreach ($schema['foreign keys'] as $remote_table => $fk_details) {
  329. if (array_key_exists($column_name, $fk_details['columns'])) {
  330. $is_fk = TRUE;
  331. }
  332. }
  333. }
  334. // Add the field to the bundle.
  335. tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_id);
  336. }
  337. }
  338. /**
  339. * Returns a $field_info array for a field based on a database column.
  340. *
  341. */
  342. function tripal_entities_get_table_column_field_default($table_name, $schema, $column_name) {
  343. $details = $schema['fields'][$column_name];
  344. // Create an array with information about this field.
  345. $field_info = array(
  346. 'field_type' => '',
  347. 'widget_type' => '',
  348. 'field_settings' => array(
  349. 'chado_table' => $table_name,
  350. 'chado_column' => $column_name,
  351. ),
  352. 'widget_settings' => array('display_label' => 1),
  353. 'description' => '',
  354. 'label' => ucwords(preg_replace('/_/', ' ', $column_name)),
  355. 'is_required' => 0,
  356. );
  357. // Alter the field info array depending on the column details.
  358. switch($details['type']) {
  359. case 'char':
  360. $field_info['field_type'] = 'text';
  361. $field_info['widget_type'] = 'text_textfield';
  362. $field_info['field_settings']['max_length'] = $details['length'];
  363. break;
  364. case 'varchar':
  365. $field_info['field_type'] = 'text';
  366. $field_info['widget_type'] = 'text_textfield';
  367. $field_info['field_settings']['max_length'] = $details['length'];
  368. break;
  369. case 'text':
  370. $field_info['field_type'] = 'text';
  371. $field_info['widget_type'] = 'text_textarea';
  372. $field_info['field_settings']['max_length'] = 17179869184;
  373. break;
  374. case 'blob':
  375. // not sure how to support a blob field.
  376. continue;
  377. break;
  378. case 'int':
  379. $field_info['field_type'] = 'number_integer';
  380. $field_info['widget_type'] = 'number';
  381. break;
  382. case 'float':
  383. $field_info['field_type'] = 'number_float';
  384. $field_info['widget_type'] = 'number';
  385. $field_info['field_settings']['precision'] = 10;
  386. $field_info['field_settings']['scale'] = 2;
  387. $field_info['field_settings']['decimal_separator'] = '.';
  388. break;
  389. case 'numeric':
  390. $field_info['field_type'] = 'number_decimal';
  391. $field_info['widget_type'] = 'number';
  392. break;
  393. case 'serial':
  394. // Serial fields are most likely not needed as a field.
  395. break;
  396. case 'boolean':
  397. $field_info['field_type'] = 'list_boolean';
  398. $field_info['widget_type'] = 'options_onoff';
  399. $field_info['field_settings']['allowed_values'] = array(0 => "No", 1 => "Yes");
  400. break;
  401. case 'datetime':
  402. // Use the Drupal Date and Date API to create the field/widget
  403. $field_info['field_type'] = 'datetime';
  404. $field_info['widget_type'] = 'date_select';
  405. $field_info['widget_settings']['increment'] = 1;
  406. $field_info['widget_settings']['tz_handling'] = 'none';
  407. $field_info['widget_settings']['collapsible'] = TRUE;
  408. // TODO: Add settings so that the minutes increment by 1.
  409. // And turn off the timezone, as the Chado field doesn't support it.
  410. break;
  411. }
  412. return $field_info;
  413. }