tripal_entities.admin.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <?php
  2. /**
  3. * Launchpad for feature administration.
  4. *
  5. * @ingroup tripal_feature
  6. */
  7. function tripal_entities_admin_view() {
  8. $output = drupal_render(drupal_get_form('tripal_entities_admin_data_types_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. $breadcrumb[] = l('Biological Data', 'admin/tripal/data_types');
  15. drupal_set_breadcrumb($breadcrumb);
  16. /* // Add the view
  17. $view = views_embed_view('tripal_feature_admin_features','default');
  18. if (isset($view)) {
  19. $output .= $view;
  20. }
  21. else {
  22. $output .= '<p>The Feature module uses primarily views to provide an '
  23. . 'administrative interface. Currently one or more views needed for this '
  24. . 'administrative interface are disabled. <strong>Click each of the following links to '
  25. . 'enable the pertinent views</strong>:</p>';
  26. $output .= '<ul>';
  27. $output .= '<li>'.l('Features View', 'admin/tripal/chado/tripal_feature/views/features/enable').'</li>';
  28. $output .= '</ul>';
  29. }
  30. // Add a summary chart.
  31. //-----------------------------------
  32. $output .= theme('tripal_feature_bar_chart_type_organism_summary');
  33. drupal_add_js('
  34. Drupal.behaviors.tripalFeature_moveAdminSummaryChart = {
  35. attach: function (context, settings) {
  36. jQuery("#tripal-feature-admin-summary").insertBefore( jQuery(".view-filters") );
  37. }};
  38. ', 'inline'); */
  39. return $output;
  40. }
  41. /**
  42. *
  43. * @param unknown $form
  44. * @param unknown $form_state
  45. * @return multitype:
  46. */
  47. function tripal_entities_admin_data_types_form($form, &$form_state) {
  48. $form = array();
  49. // Set the defaults.
  50. $cv_id = NULL;
  51. $term_name = NULL;
  52. // Set defaults using the form state.
  53. if (array_key_exists('values', $form_state)) {
  54. $cv_id = array_key_exists('cv_id', $form_state['values']) ? $form_state['values']['cv_id'] : NULL;
  55. $term_name = array_key_exists('term_name', $form_state['values']) ? $form_state['values']['term_name'] : NULL;
  56. }
  57. // Let the user select the vocabulary and tripal_data but only if they haven't
  58. // already selected a tripal_data.
  59. $sql = "
  60. SELECT CV.cv_id, CV.name
  61. FROM {cv} CV
  62. ORDER BY CV.name
  63. ";
  64. $vocabs = chado_query($sql);
  65. $cvs = array();
  66. while ($vocab = $vocabs->fetchObject()) {
  67. $cvs[$vocab->cv_id] = $vocab->name;
  68. }
  69. $form['cv_id'] = array(
  70. '#type' => 'select',
  71. '#title' => t('Vocabulary'),
  72. '#options' => $cvs,
  73. '#required' => FALSE,
  74. '#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.'),
  75. '#default_value' => $cv_id,
  76. '#ajax' => array(
  77. 'callback' => "tripal_entities_admin_data_types_form_ajax_callback",
  78. 'wrapper' => 'tripal_entities_admin_data_types_form',
  79. 'effect' => 'fade',
  80. 'method' => 'replace'
  81. )
  82. );
  83. $form['refresh_data_types'] = array(
  84. '#type' => 'submit',
  85. '#value' => t('Refresh Data Types'),
  86. '#submit' => array('tripal_entity_admin_data_types_form_submit_refresh_data_types'),
  87. );
  88. $form['publish_new_data'] = array(
  89. '#type' => 'submit',
  90. '#value' => t('Publish New Data'),
  91. '#submit' => array('tripal_entity_admin_data_types_form_submit_publish_new_data'),
  92. );
  93. $form['#prefix'] = '<div id="tripal_entities_admin_data_type_form">';
  94. $form['#suffix'] = '</div>';
  95. return $form;
  96. }
  97. /**
  98. * Submit a job to populate the entity tables
  99. * This operation makes available data types in the database publishable
  100. */
  101. function tripal_entity_admin_data_types_form_submit_refresh_data_types () {
  102. global $user;
  103. tripal_add_job('Create publishable data types', 'tripal_entity', 'tripal_entities_populate_entity_tables', array(), $user->uid);
  104. }
  105. /**
  106. *
  107. * @param unknown $form
  108. * @param unknown $form_state
  109. * @return multitype:
  110. */
  111. function tripal_entities_admin_publish_form($form, &$form_state) {
  112. $form = array();
  113. // Set the defaults.
  114. $cv_id = NULL;
  115. $term_name = NULL;
  116. // Set defaults using the form state.
  117. if (array_key_exists('values', $form_state)) {
  118. $cv_id = array_key_exists('cv_id', $form_state['values']) ? $form_state['values']['cv_id'] : NULL;
  119. $term_name = array_key_exists('term_name', $form_state['values']) ? $form_state['values']['term_name'] : NULL;
  120. }
  121. // Let the user select the vocabulary and tripal_data but only if they haven't
  122. // already selected a tripal_data.
  123. $sql = "
  124. SELECT CV.cv_id, CV.name
  125. FROM {tripal_vocabulary} TET
  126. INNER JOIN {cv} CV on CV.cv_id = TET.cv_id
  127. ORDER BY CV.name
  128. ";
  129. $vocabs = chado_query($sql);
  130. $cvs = array();
  131. while ($vocab = $vocabs->fetchObject()) {
  132. $cvs[$vocab->cv_id] = $vocab->name;
  133. }
  134. $form['cv_id'] = array(
  135. '#type' => 'select',
  136. '#title' => t('Vocabulary'),
  137. '#options' => $cvs,
  138. '#required' => TRUE,
  139. '#description' => t('Select a vocabulary that contains the term you would like to set as publishable. Only vocabularies that are linked to data are shown.'),
  140. '#default_value' => $cv_id,
  141. '#ajax' => array(
  142. 'callback' => "tripal_entities_admin_publish_form_ajax_callback",
  143. 'wrapper' => 'tripal_entities_admin_publish_form',
  144. 'effect' => 'fade',
  145. 'method' => 'replace'
  146. )
  147. );
  148. // If we have a CV ID then we want to provide an autocomplete field
  149. if ($cv_id) {
  150. $form['cvterm_select']['term_name'] = array(
  151. '#title' => t('Data Type'),
  152. '#type' => 'textfield',
  153. '#description' => t("Please enter the name of the data type to set as publishable. The data type must be a valid term in the selected vocabulary. This field will autopopulate as you type to help find available data types."),
  154. '#required' => TRUE,
  155. '#default_value' => $term_name,
  156. '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv_id",
  157. );
  158. $form['cvterm_select']['select_button'] = array(
  159. '#type' => 'submit',
  160. '#value' => t('Publish Data'),
  161. '#name' => 'publish',
  162. );
  163. }
  164. $form['#prefix'] = '<div id="tripal_entities_admin_publish_form">';
  165. $form['#suffix'] = '</div>';
  166. return $form;
  167. }
  168. /**
  169. * An Ajax callback for the tripal_entities_admin_publish_form..
  170. */
  171. function tripal_entities_admin_publish_form_ajax_callback($form, $form_state) {
  172. // return the form so Drupal can update the content on the page
  173. return $form;
  174. }
  175. /**
  176. * Implements hook_validate() for the tripal_entities_admin_publish_form.
  177. *
  178. */
  179. function tripal_entities_admin_publish_form_validate($form, &$form_state) {
  180. $cv_id = $form_state['values']['cv_id'];
  181. $term_name = $form_state['values']['term_name'];
  182. // Make sure the term_name is a real term in the vocabulary.
  183. $type = tripal_get_cvterm(array(
  184. 'name' => $term_name,
  185. 'cv_id' => $cv_id
  186. ));
  187. if (!$type) {
  188. form_set_error('term_name', t("The data type is not a valid name for the selected vocabulary."));
  189. }
  190. // Make sure the term is used in the site:
  191. $values = array(
  192. 'cvterm_id' => $type->cvterm_id,
  193. );
  194. $bundles = chado_select_record('tripal_term', array('term_id'), $values);
  195. if (count($bundles) == 0) {
  196. form_set_error('term_name', t("The data type, %type, is not associated with data on this site and thus cannot be set as publishable.", array('%type' => $term_name)));
  197. }
  198. // Make sure the term is not already published.
  199. $values = array(
  200. 'cvterm_id' => $type->cvterm_id,
  201. 'publish' => 1,
  202. );
  203. $bundles = chado_select_record('tripal_term', array('term_id'), $values);
  204. if (count($bundles) > 0) {
  205. form_set_error('term_name', t("This data type is already set as publishable."));
  206. }
  207. }
  208. /**
  209. * Implements hook_submit() for the tripal_entities_admin_publish_form.
  210. *
  211. */
  212. function tripal_entities_admin_publish_form_submit($form, &$form_state) {
  213. $cv_id = $form_state['values']['cv_id'];
  214. $term_name = $form_state['values']['term_name'];
  215. // Get the data type using the $term_name and $cv_id.
  216. $type = chado_generate_var('cvterm', array('cv_id' => $cv_id, 'name' => $term_name));
  217. // Start the transaction.
  218. $transaction = db_transaction();
  219. try {
  220. // We don't need to check if the vocabulary is used because the
  221. // form only shows those vocabs that are used.
  222. // Mark this entity as published.
  223. $match = array('cv_id' => $cv_id);
  224. $values = array('publish' => 1);
  225. $success = chado_update_record('tripal_vocabulary', $match, $values);
  226. if (!$success) {
  227. throw new Exception('Cannot set the vocabulary as publishable');
  228. }
  229. // We have already checked in the validate if the term already exists
  230. // as a bundle. So, if we're here we can enable it.
  231. $match = array('cvterm_id' => $type->cvterm_id);
  232. $values = array('publish' => 1);
  233. $success = chado_update_record('tripal_term', $match, $values);
  234. if (!$success) {
  235. throw new Exception('Cannot set the data type as publishable');
  236. }
  237. // Get the bundle
  238. $records = chado_select_record('tripal_term', array('*'), $match);
  239. $bundle = $records[0];
  240. $bundle_name = $type->dbxref_id->db_id->name . '_' . $type->dbxref_id->accession;
  241. $entity_type_name = $type->dbxref_id->db_id->name;
  242. // Get the list of tables where this cvterm is used.
  243. $values = array('term_id' => $bundle->term_id);
  244. $tables = chado_select_record('tripal_term_usage', array('*'), $values);
  245. // Iterate through the tables.
  246. foreach ($tables as $table) {
  247. $tablename = $table->data_table;
  248. // We only want to look at base tables.
  249. if ($tablename == 'cvterm_dbxref' || $tablename == 'cvterm_relationship' ||
  250. $tablename == 'cvtermpath' || $tablename == 'cvtermprop' || $tablename == 'chadoprop' ||
  251. $tablename == 'cvtermsynonym' || preg_match('/_relationship$/', $tablename) ||
  252. preg_match('/_cvterm$/', $tablename)) {
  253. continue;
  254. }
  255. // Add in the bundle's fields.
  256. tripal_entities_add_bundle_fields($tablename, $entity_type_name, $bundle_name);
  257. }
  258. drupal_set_message(t('Data type, %type, is now set as publishable.', array('%type' => $term_name)));
  259. }
  260. catch (Exception $e) {
  261. $transaction->rollback();
  262. drupal_set_message('Failure publishing this data type: ' . $e->getMessage(), 'error');
  263. watchdog_exception('trp_entities', $e);
  264. }
  265. }
  266. /**
  267. *
  268. * @param $table
  269. * @param $entity_type
  270. * @param $bundle_name
  271. */
  272. function tripal_entities_add_bundle_fields($tablename, $entity_type_name, $bundle_name) {
  273. // Iterate through the columns of the table and see if fields have been
  274. // created for each one. If not, then create them.
  275. $schema = chado_get_schema($tablename);
  276. $columns = $schema['fields'];
  277. foreach ($columns as $column_name => $details) {
  278. $field_name = $tablename . '__' . $column_name;
  279. $field = field_info_field($field_name);
  280. // Skip the primary key field.
  281. if ($column_name == $schema['primary key'][0]) {
  282. continue;
  283. }
  284. // Determine if the field is required.
  285. $is_required = 0;
  286. if (array_key_exists('not null', $details)) {
  287. $is_required = $details['not null'] ? 1 : 0;
  288. }
  289. // Determine what type of field this should be.
  290. // Drupal data types are: https://www.drupal.org/node/159605.
  291. // Field types are here: https://www.drupal.org/node/1879542
  292. $field_type = '';
  293. $widget_type = '';
  294. $settings = array();
  295. $label = '';
  296. switch($details['type']) {
  297. case 'char':
  298. // unsupported by postgres
  299. break;
  300. case 'varchar':
  301. $field_type = 'text';
  302. $widget_type = 'text_textfield';
  303. $settings['max_length'] = $details['length'];
  304. break;
  305. case 'text':
  306. $field_type = 'text';
  307. $widget_type = 'text_textarea';
  308. $settings['max_length'] = '';
  309. break;
  310. case 'blob':
  311. // not sure how to support a blob field.
  312. continue;
  313. break;
  314. case 'int':
  315. $field_type = 'number_integer';
  316. $widget_type = 'number';
  317. break;
  318. case 'float':
  319. $field_type = 'number_float';
  320. $widget_type = 'number';
  321. $settings['precision'] = 10;
  322. $settings['scale'] = 2;
  323. $settings['decimal_separator'] = '.';
  324. break;
  325. case 'numeric':
  326. $field_type = 'number_decimal';
  327. $widget_type = 'number';
  328. break;
  329. case 'serial':
  330. // Serial fields are most likely not needed as a field.
  331. break;
  332. case 'boolean':
  333. // TODO: what is the proper field for booleans?????
  334. break;
  335. case 'datetime':
  336. // TODO: What is the proper datetime fields ??????
  337. break;
  338. default:
  339. drupal_set_message(t("Unhandled field type: %type", array('%type' => $details['type'])), 'warning');
  340. $field_type = 'text';
  341. $widget_type = 'text_textarea';
  342. if (array_key_exists('length', $details)) {
  343. $settings['max_length'] = $details['length'];
  344. }
  345. }
  346. // If we don't have a field type then we don't need to create a field.
  347. if (!$field_type) {
  348. // If we don't have a field type but it is required and doesn't have
  349. // a default value then we are in trouble.
  350. if ($is_required and !array_key_exists('default', $details)) {
  351. throw new Exception(t('The %table.%field type, %type, is not yet supported for Entity fields, but it is required,',
  352. array('%table' => $tablename, '%field' => $column_name, '%type' => $details['type'])));
  353. }
  354. continue;
  355. }
  356. // If this field is a foreign key field then we will have a special custom
  357. // field provided by Tripal.
  358. $is_fk = FALSE;
  359. if (array_key_exists('foreign keys', $details)) {
  360. foreach ($details['foreign keys'] as $remote_table => $fk_details) {
  361. if (array_key_exists($field_name, $fk_details['columns'])) {
  362. $is_fk = TRUE;
  363. }
  364. }
  365. }
  366. // If this column is a FK relationship then use a custom Tripal
  367. // defined field type for it.
  368. if ($is_fk) {
  369. // TODO: We need a better way to get the fields for FK relationships.
  370. // It's not a good idea to enumerate them all here. We need some sort
  371. // of hook or something that will let us lookup the correct field.
  372. switch ($column_name) {
  373. case 'organism_id':
  374. $field_type = 'organism_id';
  375. $label = 'Organism';
  376. break;
  377. }
  378. continue;
  379. }
  380. // If the field doesn't exist then create it.
  381. if (!$field) {
  382. $field = array(
  383. 'field_name' => $field_name,
  384. 'type' => $field_type,
  385. 'cardinality' => 1,
  386. 'locked' => TRUE,
  387. 'storage' => array(
  388. 'type' => 'tripal_entities_storage'
  389. ),
  390. );
  391. field_create_field($field);
  392. }
  393. // Attach the field to the bundle.
  394. $field_instance = array(
  395. 'field_name' => $field_name,
  396. 'label' => $label ? $label : ucwords(preg_replace('/_/', ' ', $column_name)),
  397. 'widget' => array(
  398. 'type' => $widget_type
  399. ),
  400. 'entity_type' => $entity_type_name,
  401. 'required' => $is_required,
  402. 'settings' => $settings,
  403. 'bundle' => $bundle_name,
  404. );
  405. field_create_instance($field_instance);
  406. }
  407. }
  408. /**
  409. *
  410. * @param unknown $form
  411. * @param unknown $form_state
  412. * @return multitype:
  413. */
  414. function tripal_entities_admin_access_form($form, &$form_state) {
  415. $form = array();
  416. return $form;
  417. }