tripal_entities.admin.inc 17 KB

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