tripal_entities.admin.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <?php
  2. /**
  3. * Launchpad for biological data administration.
  4. */
  5. function tripal_entities_admin_view() {
  6. // Render the tripal entites bundle form.
  7. $form = drupal_get_form('tripal_entities_admin_bundles_form');
  8. $output = drupal_render($form) . "<br>[ Image Place Holder for Data Type Summary ]<br>";
  9. // Set the breadcrumb.
  10. $breadcrumb = array();
  11. $breadcrumb[] = l('Home', '<front>');
  12. $breadcrumb[] = l('Administration', 'admin');
  13. $breadcrumb[] = l('Tripal', 'admin/tripal');
  14. drupal_set_breadcrumb($breadcrumb);
  15. return $output;
  16. }
  17. /**
  18. * Provide a data listing for tripal entites (ie: biological data).
  19. * Note: This hook returns a rendered page but we want a form.
  20. */
  21. function tripal_entities_content_view() {
  22. // Retrieve our data listing form and render it.
  23. $form = drupal_get_form('tripal_entities_content_overview_form');
  24. $output = drupal_render($form);
  25. // Set the breadcrumb.
  26. $breadcrumb = array();
  27. $breadcrumb[] = l('Home', '<front>');
  28. $breadcrumb[] = l('Administration', 'admin');
  29. drupal_set_breadcrumb($breadcrumb);
  30. return $output;
  31. }
  32. /**
  33. * Display a listing of Biological Data to the administrator.
  34. *
  35. * @TODO Filters and bulk operations needed to be added to this form.
  36. *
  37. * @param array $form
  38. * @param array $form_state
  39. * @return
  40. * A form array describing this listing to the Form API.
  41. */
  42. function tripal_entities_content_overview_form($form, &$form_state) {
  43. // Set the title to be informative (defaults to content for some reason).
  44. drupal_set_title('Biological Data');
  45. // Retrieve a pages list of all tripal entitles (ie: biological data).
  46. // This will return the 25 most recently created entities.
  47. $entities = db_select('tripal_entity', 'td')
  48. ->fields('td')
  49. ->orderBy('created', 'DESC')//ORDER BY created
  50. ->range(0,25)
  51. ->execute();
  52. $headers = array('Title', 'Vocabulary', 'Term', 'Author', 'Status', 'Updated', 'Operations');
  53. $rows = array();
  54. // For each entity retrieved add a row to the data listing.
  55. while ($entity = $entities->fetchObject()) {
  56. // Retrieve details about the term this entity is based on.
  57. $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $entity->cvterm_id));
  58. // Retrieve details about the user who created this data.
  59. $author = user_load($entity->uid);
  60. // Add information to the table.
  61. $rows[] = array(
  62. l($entity->title, 'BioData/' . $entity->id),
  63. $cvterm->cv_id->name . ' (' . $cvterm->dbxref_id->db_id->name . ')',
  64. $cvterm->name,
  65. l($author->name, 'user/' . $entity->uid),
  66. $entity->status == 1 ? 'published' : 'unpublished',
  67. format_date($entity->changed, 'short'),
  68. l('edit', 'BioData/' . $entity->id . '/edit') . '&nbsp;&nbsp;' .
  69. l('delete', 'BioData/' . $entity->id . '/delete')
  70. );
  71. }
  72. // If there are no entites created yet then add a message to the table to
  73. // provide guidance to administrators.
  74. if (empty($rows)) {
  75. $rows[] = array(
  76. array(
  77. 'data' => t('No biological data available.'),
  78. 'colspan' => 7
  79. )
  80. );
  81. }
  82. // Render the data listing.
  83. $table_vars = array(
  84. 'header' => $headers,
  85. 'rows' => $rows,
  86. 'attributes' => array(),
  87. 'sticky' => TRUE,
  88. 'caption' => '',
  89. 'colgroups' => array(),
  90. 'empty' => '',
  91. );
  92. $form['results'] = array(
  93. '#type' => 'markup',
  94. '#markup' => theme('table', $table_vars),
  95. );
  96. return $form;
  97. }
  98. /**
  99. * Tripal administration form for Biological data (Admin > Tripal > Biological Data).
  100. *
  101. * @TODO Add graph showing available data types.
  102. *
  103. * @param unknown $form
  104. * @param unknown $form_state
  105. * @return multitype:
  106. */
  107. function tripal_entities_admin_bundles_form($form, &$form_state) {
  108. $form = array();
  109. // Set the defaults.
  110. $cv_id = NULL;
  111. $term_name = NULL;
  112. // Set defaults using the form state.
  113. if (array_key_exists('values', $form_state)) {
  114. $cv_id = array_key_exists('cv_id', $form_state['values']) ? $form_state['values']['cv_id'] : NULL;
  115. $term_name = array_key_exists('term_name', $form_state['values']) ? $form_state['values']['term_name'] : NULL;
  116. }
  117. // Let the user select the vocabulary and tripal_entity but only if they haven't
  118. // already selected a tripal_entity.
  119. $sql = "
  120. SELECT CV.cv_id, CV.name
  121. FROM {cv} CV
  122. ORDER BY CV.name
  123. ";
  124. $vocabs = chado_query($sql);
  125. $cvs = array();
  126. while ($vocab = $vocabs->fetchObject()) {
  127. $cvs[$vocab->cv_id] = $vocab->name;
  128. }
  129. $form['cv_id'] = array(
  130. '#type' => 'select',
  131. '#title' => t('Vocabulary'),
  132. '#options' => $cvs,
  133. '#required' => FALSE,
  134. '#description' => t('Select a vocabulary to view potential data types in the chart below. Limit the chart to only published data types by selecting the checkbox.'),
  135. '#default_value' => $cv_id,
  136. '#ajax' => array(
  137. 'callback' => "tripal_entities_admin_bundles_form_ajax_callback",
  138. 'wrapper' => 'tripal_entities_admin_bundles_form',
  139. 'effect' => 'fade',
  140. 'method' => 'replace'
  141. )
  142. );
  143. $form['refresh_bundles'] = array(
  144. '#type' => 'submit',
  145. '#value' => t('Refresh Data Types'),
  146. '#name' => 'refresh_bundles',
  147. );
  148. $form['publish_new_data'] = array(
  149. '#type' => 'submit',
  150. '#value' => t('Publish New Data'),
  151. '#name' => 'publish_new_data',
  152. );
  153. $form['#prefix'] = '<div id="tripal_entities_admin_bundle_form">';
  154. $form['#suffix'] = '</div>';
  155. return $form;
  156. }
  157. /**
  158. * Submit a job to populate the entity tables
  159. * This operation makes available data types in the database publishable
  160. */
  161. function tripal_entities_admin_bundles_form_submit($form, $form_state) {
  162. global $user;
  163. if ($form_state['clicked_button']['#name'] == 'refresh_bundles') {
  164. tripal_add_job('Create publishable data types', 'tripal_entity', 'tripal_entities_populate_entity_tables', array(), $user->uid);
  165. }
  166. if ($form_state['clicked_button']['#name'] == 'publish_new_data') {
  167. }
  168. }
  169. /**
  170. * Form for creating biological data types (ie: tripal entity types).
  171. *
  172. * This form is available on the menu at Admin >> Structure >> Biological Data
  173. * Types
  174. *
  175. * @param array $form
  176. * @param array $form_state
  177. *
  178. * @return
  179. * An array describing this form to the Form API.
  180. */
  181. function tripal_entities_admin_add_type_form($form, &$form_state) {
  182. $term_name = '';
  183. $num_terms = 0;
  184. $cv_id = '';
  185. // Set defaults using the form state.
  186. if (array_key_exists('input', $form_state)) {
  187. if (array_key_exists('term_name', $form_state['input'])) {
  188. $term_name = $form_state['input']['term_name'];
  189. }
  190. if (array_key_exists('cv_id', $form_state['input'])) {
  191. $cv_id = $form_state['input']['cv_id'];
  192. }
  193. // If a term and cv_id are provided then we can look for the term using
  194. // both and we should find a unique term. If only ther term is provided
  195. // we can still look for a unique term but there must only be one.
  196. if ($term_name and !$cv_id) {
  197. $match = array(
  198. 'name' => $term_name,
  199. );
  200. }
  201. else {
  202. $match = array(
  203. 'name' => $term_name,
  204. 'cv_id' => $cv_id,
  205. );
  206. }
  207. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  208. $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
  209. $num_terms = count($terms);
  210. }
  211. // If no term has been selected yet then provide the auto complete field.
  212. if ($num_terms == 0) {
  213. $form['term_name'] = array(
  214. '#title' => t('Biological Data Type'),
  215. '#type' => 'textfield',
  216. '#description' => t("Please enter the type of data that you want to add.
  217. Once added, priviledged users can add new records of the selected
  218. type. As you type, suggestions will be provided."),
  219. '#required' => TRUE,
  220. '#default_value' => $term_name,
  221. '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv_id",
  222. );
  223. }
  224. else {
  225. $form['term_name'] = array(
  226. '#type' => 'hidden',
  227. '#value' => $term_name,
  228. );
  229. }
  230. // If the term belongs to more than one vocabulary then add additional fields
  231. // to let the user select the vocabulary.
  232. if ($num_terms > 1) {
  233. $cvs = array();
  234. foreach ($terms as $term) {
  235. $cvs[$term->cv_id->cv_id] = 'Vocabulary: <b>' . $term->cv_id->name . '</b> (' . $term->cv_id->definition . ')<br>' . $term->name . ': ' . $term->definition;
  236. }
  237. $form['cv_id'] = array(
  238. '#type' => 'radios',
  239. '#title' => t('Select the appropriate vocabulary'),
  240. '#options' => $cvs,
  241. );
  242. }
  243. // Add in the button for the cases of no terms or too many.
  244. $form['select_button'] = array(
  245. '#type' => 'submit',
  246. '#value' => t('Use this term'),
  247. '#name' => 'select_cvterm'
  248. );
  249. return $form;
  250. }
  251. /**
  252. * Implements hook_validate() for the tripal_entities_admin_publish_form.
  253. *
  254. */
  255. function tripal_entities_admin_add_type_form_validate($form, &$form_state) {
  256. // Check if this term and vocabulary is in the tripal_vocabulary usage tables.
  257. // If not then add it.
  258. if (array_key_exists('clicked_button', $form_state) and
  259. $form_state['clicked_button']['#name'] =='select_cvterm') {
  260. // First, make sure the term is unique. If not then we can't check it.
  261. $term_name = NULL;
  262. $cv_id = NULL;
  263. $cvterm = NULL;
  264. if (array_key_exists('term_name', $form_state['values'])) {
  265. $term_name = $form_state['input']['term_name'];
  266. }
  267. if (array_key_exists('cv_id', $form_state['input'])) {
  268. $cv_id = $form_state['input']['cv_id'];
  269. }
  270. // If a term and cv_id are provided then we can look for the term using
  271. // both and we should find a unique term. If only ther term is provided
  272. // we can still look for a unique term but there must only be one.
  273. if ($term_name and !$cv_id) {
  274. $match = array(
  275. 'name' => $term_name,
  276. );
  277. }
  278. else {
  279. $match = array(
  280. 'name' => $term_name,
  281. 'cv_id' => $cv_id,
  282. );
  283. }
  284. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  285. $form_state['storage']['terms'] = $terms;
  286. // If we do not have any terms then the term provided by the user does not
  287. // exists and we need to provide an error message.
  288. if (count($terms) == 0) {
  289. form_set_error('term_name', t('The term does not exist in this database.'));
  290. }
  291. // If we have more than one term then we need to set an error so that the
  292. // form can provide a list of vocabularies to select from.
  293. if (count($terms) > 1) {
  294. form_set_error('term_name', t('The term is not unique. A list of vocabularies
  295. that contain this term. Please select the most appropriate vocabulary.'));
  296. }
  297. }
  298. }
  299. /**
  300. * Implements hook_submit() for the tripal_entities_admin_publish_form.
  301. *
  302. */
  303. function tripal_entities_admin_add_type_form_submit($form, &$form_state) {
  304. if ($form_state['clicked_button']['#name'] =='select_cvterm') {
  305. $cvterm = $form_state['storage']['terms'][0];
  306. $bundle_id = 'dbxref_' . $cvterm->dbxref_id->dbxref_id;
  307. // Before we try to add this type, check to see if it already exists
  308. // as a bundle.
  309. $einfo = entity_get_info('BioData');
  310. if (!in_array($bundle_id, array_keys($einfo['bundles']))) {
  311. $error = '';
  312. $success = tripal_create_entity_type($cvterm, $error);
  313. if (!$success) {
  314. drupal_set_message($error, 'error');
  315. $form_state['redirect'] = "admin/structure/BioData";
  316. }
  317. else {
  318. drupal_set_message('New biological data type created. Fields are added automatically to this type.');
  319. $form_state['redirect'] = "admin/structure/BioData";
  320. }
  321. }
  322. else {
  323. drupal_set_message('This type already exists.', 'warning');
  324. }
  325. }
  326. }
  327. /**
  328. * Implements hook_add_bundle_fields().
  329. *
  330. * @param $entity_type_name
  331. * @param $bundle_name
  332. * @param $cvterm
  333. */
  334. function tripal_entities_add_bundle_fields($entity_type_name, $bundle_name, $cvterm) {
  335. // Adds the fields for the base table to the entity.
  336. tripal_entities_add_bundle_base_fields($entity_type_name, $bundle_name, $cvterm);
  337. // Check to see if there are any kv-property tables associated to this
  338. // base table. If so, add the fields for that type of table.
  339. tripal_entities_add_bundle_kvproperty_adder_field($entity_type_name, $bundle_name, 'featureprop');
  340. }
  341. /**
  342. * Adds the fields for a kv-property table fields
  343. *
  344. * @param $entity_type_name
  345. * @param $bundle_name
  346. * @param $kv_table
  347. */
  348. function tripal_entities_add_bundle_kvproperty_adder_field($entity_type_name, $bundle_name, $kv_table) {
  349. // First add a generic property field so that users can add new proeprty types.
  350. $field_name = $kv_table;
  351. // Initialize the field array.
  352. $field_info = array(
  353. 'field_type' => 'kvproperty_adder',
  354. 'widget_type' => 'tripal_fields_kvproperty_adder_widget',
  355. 'field_settings' => array(),
  356. 'widget_settings' => array('display_label' => 1),
  357. 'description' => '',
  358. 'label' => 'Additional Properties',
  359. 'is_required' => 0,
  360. );
  361. tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
  362. }
  363. /**
  364. * Adds the fields for the base table to the entity.
  365. */
  366. function tripal_entities_add_bundle_base_fields($entity_type_name, $bundle_name, $cvterm) {
  367. // Get the list of tables where this cvterm is used.
  368. $match = array('cvterm_id' => $cvterm->cvterm_id);
  369. $term = chado_select_record('tripal_term', array('*'), $match);
  370. $values = array('term_id' => $term[0]->term_id);
  371. $tables = chado_select_record('tripal_term_usage', array('*'), $values);
  372. // Iterate through the tables.
  373. foreach ($tables as $table) {
  374. $table_name = $table->data_table;
  375. $type_table = $table->type_table;
  376. $type_field = $table->field;
  377. // We only want to look at base tables.
  378. if ($table_name == 'cvterm_dbxref' || $table_name == 'cvterm_relationship' ||
  379. $table_name == 'cvtermpath' || $table_name == 'cvtermprop' || $table_name == 'chadoprop' ||
  380. $table_name == 'cvtermsynonym' || preg_match('/_relationship$/', $table_name) ||
  381. preg_match('/_cvterm$/', $table_name)) {
  382. continue;
  383. }
  384. // Iterate through the columns of the table and see if fields have been
  385. // created for each one. If not, then create them.
  386. $schema = chado_get_schema($table_name);
  387. $columns = $schema['fields'];
  388. foreach ($columns as $column_name => $details) {
  389. $field_name = $table_name . '__' . $column_name;
  390. // Skip the primary key field.
  391. if ($column_name == $schema['primary key'][0]) {
  392. continue;
  393. }
  394. // Skip the type field.
  395. if ($table_name == $type_table and $column_name == $type_field) {
  396. continue;
  397. }
  398. // Get the field defaults for this column.
  399. $field_info = tripal_entities_get_table_column_field_default($table_name, $schema, $column_name);
  400. // Determine if the field is required.
  401. if (array_key_exists('not null', $details) and $details['not null'] === TRUE) {
  402. $field_info['is_required'] = array_key_exists('default', $details) ? 0 : 1;
  403. }
  404. // If we don't have a field type then we don't need to create a field.
  405. if (!$field_info['field_type']) {
  406. // If we don't have a field type but it is required and doesn't have
  407. // a default value then we are in trouble.
  408. if ($field_info['is_required'] and !array_key_exists('default', $details)) {
  409. throw new Exception(t('The %table.%field type, %type, is not yet supported for Entity fields, but it is required,',
  410. array('%table' => $table_name, '%field' => $column_name, '%type' => $details['type'])));
  411. }
  412. continue;
  413. }
  414. // If this field is a foreign key field then we will have a special custom
  415. // field provided by Tripal.
  416. $is_fk = FALSE;
  417. if (array_key_exists('foreign keys', $schema)) {
  418. foreach ($schema['foreign keys'] as $remote_table => $fk_details) {
  419. if (array_key_exists($column_name, $fk_details['columns'])) {
  420. $is_fk = TRUE;
  421. }
  422. }
  423. }
  424. // Add the field to the bundle.
  425. tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
  426. }
  427. }
  428. }
  429. /**
  430. * Returns a $field_info array for a field based on a databaes column.
  431. *
  432. */
  433. function tripal_entities_get_table_column_field_default($table_name, $schema, $column_name) {
  434. $details = $schema['fields'][$column_name];
  435. // Create an array with information about this field.
  436. $field_info = array(
  437. 'field_type' => '',
  438. 'widget_type' => '',
  439. 'field_settings' => array(
  440. 'chado_table' => $table_name,
  441. 'chado_column' => $column_name,
  442. ),
  443. 'widget_settings' => array('display_label' => 1),
  444. 'description' => '',
  445. 'label' => ucwords(preg_replace('/_/', ' ', $column_name)),
  446. 'is_required' => 0,
  447. );
  448. // Alter the field info array depending on the column details.
  449. switch($details['type']) {
  450. case 'char':
  451. $field_info['field_type'] = 'text';
  452. $field_info['widget_type'] = 'text_textfield';
  453. $field_info['field_settings']['max_length'] = $details['length'];
  454. break;
  455. case 'varchar':
  456. $field_info['field_type'] = 'text';
  457. $field_info['widget_type'] = 'text_textfield';
  458. $field_info['field_settings']['max_length'] = $details['length'];
  459. break;
  460. case 'text':
  461. $field_info['field_type'] = 'text';
  462. $field_info['widget_type'] = 'text_textarea';
  463. $field_info['field_settings']['max_length'] = 17179869184;
  464. break;
  465. case 'blob':
  466. // not sure how to support a blob field.
  467. continue;
  468. break;
  469. case 'int':
  470. $field_info['field_type'] = 'number_integer';
  471. $field_info['widget_type'] = 'number';
  472. break;
  473. case 'float':
  474. $field_info['field_type'] = 'number_float';
  475. $field_info['widget_type'] = 'number';
  476. $field_info['field_settings']['precision'] = 10;
  477. $field_info['field_settings']['scale'] = 2;
  478. $field_info['field_settings']['decimal_separator'] = '.';
  479. break;
  480. case 'numeric':
  481. $field_info['field_type'] = 'number_decimal';
  482. $field_info['widget_type'] = 'number';
  483. break;
  484. case 'serial':
  485. // Serial fields are most likely not needed as a field.
  486. break;
  487. case 'boolean':
  488. $field_info['field_type'] = 'list_boolean';
  489. $field_info['widget_type'] = 'options_onoff';
  490. $field_info['field_settings']['allowed_values'] = array(0 => "No", 1 => "Yes");
  491. break;
  492. case 'datetime':
  493. // Use the Drupal Date and Date API to create the field/widget
  494. $field_info['field_type'] = 'datetime';
  495. $field_info['widget_type'] = 'date_select';
  496. $field_info['widget_settings']['increment'] = 1;
  497. $field_info['widget_settings']['tz_handling'] = 'none';
  498. $field_info['widget_settings']['collapsible'] = TRUE;
  499. // TODO: Add settings so that the minutes increment by 1.
  500. // And turn off the timezone, as the Chado field doesn't support it.
  501. break;
  502. }
  503. return $field_info;
  504. }
  505. /**
  506. *
  507. * @param unknown $form
  508. * @param unknown $form_state
  509. * @return multitype:
  510. */
  511. function tripal_entities_admin_access_form($form, &$form_state) {
  512. $form = array();
  513. return $form;
  514. }