tripal_views_handler_area_collections.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. <?php
  2. class tripal_views_handler_area_collections extends views_handler_area_result {
  3. function options_form(&$form, &$form_state) {
  4. // We have no options so we have to implement this function with
  5. // nothing in it.
  6. }
  7. /**
  8. * Implements views_handler_area_result::render().
  9. */
  10. function render($empty = FALSE) {
  11. // If collections are disabled then don't show anything.
  12. $collections_enabled = variable_get('tripal_data_collections_enabled', 1);
  13. if (!$collections_enabled) {
  14. return '';
  15. }
  16. // We need a specific form to work with Tripal content types and the tripal_views_query plugin.
  17. if ($this->query->plugin_name == 'tripal_views_query') {
  18. $form = drupal_get_form('tripal_views_handler_area_collections_form', $this->view, $this->query);
  19. return drupal_render($form);
  20. }
  21. // We also want to support views created via the Drupal Search API.
  22. elseif ($this->query->plugin_name == 'search_api_views_query') {
  23. $form = drupal_get_form('tripal_views_handler_area_collections_search_api_form', $this->view, $this->query);
  24. return drupal_render($form);
  25. }
  26. // If we don't support this type of view, then we should tell the admin
  27. // so they're not left scratching their head like I was ;-).
  28. else {
  29. tripal_set_message('Unfortunatly Tripal Collections are not supported for your current view type.');
  30. }
  31. }
  32. }
  33. /**
  34. * Views Area Handler Form: Tripal Collections on Tripal Entity-based Views
  35. *
  36. * @param $form
  37. * @param $form_state
  38. * @param $view
  39. * The views object that this form will be rendered on.
  40. * @param $query
  41. * The views query object generating the views results.
  42. */
  43. function tripal_views_handler_area_collections_form($form, $form_state, $view, $query) {
  44. // Set form defaults.
  45. $collection_name = '';
  46. $collection_desc = '';
  47. // Get the bundle for this query.
  48. $matches = array();
  49. preg_match('/^(.+?)__(.+?)$/', $view->base_table, $matches);
  50. $vocabulary = $matches[1];
  51. $accession = $matches[2];
  52. $term = tripal_load_term_entity(array('vocabulary' => $vocabulary, 'accession' => $accession));
  53. $bundle = tripal_load_bundle_entity(array('term_id' => $term->id));
  54. $form = array();
  55. $form['save_collection'] = array(
  56. '#type' => 'fieldset',
  57. '#title' => t('Save Results'),
  58. '#collapsible' => TRUE,
  59. '#collapsed' => TRUE,
  60. '#description' => t('A data collection is a virtual container into which you can
  61. save data. You can place your search results into a data collection for
  62. download or use with other tools on this site that support data collections.'),
  63. );
  64. $form['save_collection']['bundle'] = array(
  65. '#type' => 'value',
  66. '#value' => $bundle,
  67. );
  68. $form['save_collection']['view'] = array(
  69. '#type' => 'value',
  70. '#value' => unserialize(serialize($view))
  71. );
  72. $form['save_collection']['query'] = array(
  73. '#type' => 'value',
  74. '#value' => unserialize(serialize($query->query))
  75. );
  76. $form['save_collection']['summary'] = array(
  77. '#type' => 'item',
  78. '#title' => 'Results Summary',
  79. '#markup' => t('There are @total_rows record(s) that can be added to a data collection.', array('@total_rows' => $view->total_rows)),
  80. );
  81. $form['save_collection']['collection_name'] = array(
  82. '#type' => 'textfield',
  83. '#title' => t('Collection Name'),
  84. '#description' => t('Please name this collection for future reference.'),
  85. '#default_value' => $collection_name,
  86. '#required' => TRUE,
  87. );
  88. $form['save_collection']['description_fset'] = array(
  89. '#type' => 'fieldset',
  90. '#title' => t('Add a Description'),
  91. '#collapsible' => TRUE,
  92. '#collapsed' => TRUE,
  93. );
  94. $form['save_collection']['description_fset']['collection_desc'] = array(
  95. '#type' => 'textarea',
  96. '#title' => t('Description'),
  97. '#description' => t('Please provide a description about this data collection. This is meant to help you remember what is in the collection.'),
  98. '#default_value' => $collection_name,
  99. );
  100. // Get the list of fields used in the view.
  101. $current_display = $view->current_display;
  102. if (array_key_exists('fields', $view->display[$current_display]->display_options)) {
  103. $view_fields = $view->display[$current_display]->display_options['fields'];
  104. }
  105. else {
  106. $view_fields = $view->display['default']->display_options['fields'];
  107. }
  108. $form['save_collection']['fields'] = array(
  109. '#type' => 'fieldset',
  110. '#title' => t('Add or Update Fields'),
  111. '#description' => t('You may select any of the additional fields below to
  112. add to this data collection. Please note that different fields may be able
  113. to create different output file types.'),
  114. '#collapsible' => TRUE,
  115. '#collapsed' => TRUE,
  116. );
  117. // We want to theme all of the fields, so we add this next level in the
  118. // form array to theme.
  119. $form['save_collection']['fields']['items'] = array(
  120. '#theme' => 'tripal_views_handler_area_collections_fields_fset'
  121. );
  122. // Get the list of fields in this view.
  123. $field_ids = array();
  124. $defaults = array();
  125. $fields = field_info_instances('TripalEntity', $bundle->name);
  126. foreach ($fields as $field_name => $instance) {
  127. $field = field_info_field($field_name);
  128. $field_type = $field['type'];
  129. if ($instance['field_name'] == 'entity_id') {
  130. continue;
  131. }
  132. // Skip hidden fields.
  133. if ($instance['display']['default']['type'] == 'hidden') {
  134. continue;
  135. }
  136. $field_label = $instance['label'];
  137. // Add in in any non CSV or Tab formatters to the label.
  138. $formatters = array();
  139. $field_formatters = tripal_get_field_field_formatters($field, $instance);
  140. foreach ($field_formatters as $class_name => $label) {
  141. tripal_load_include_downloader_class($class_name);
  142. $formatters[] = $class_name::$label;
  143. }
  144. // Add the field to those supported.
  145. $field_ids[$instance['field_id']]= $field_label;
  146. // Automatically check fields that are in the view and not excluded.
  147. $checked = FALSE;
  148. if (array_key_exists($field_name, $view_fields)) {
  149. if (array_key_exists('exclude', $view_fields[$field_name]) and
  150. $view_fields[$field_name]['exclude'] == TRUE) {
  151. continue;
  152. }
  153. $checked = TRUE;
  154. }
  155. $form['save_collection']['fields']['items'] ['select-' . $instance['field_id']] = array(
  156. '#type' => 'checkbox',
  157. '#title' => $field_label,
  158. '#default_value' => $checked,
  159. );
  160. $form['save_collection']['fields']['items'] ['description-' . $instance['field_id']] = array(
  161. '#type' => 'markup',
  162. '#markup' => $instance['description']
  163. );
  164. $form['save_collection']['fields']['items'] ['formatters-' . $instance['field_id']] = array(
  165. '#type' => 'markup',
  166. '#markup' => join(', ', $formatters)
  167. );
  168. }
  169. $form['save_collection']['button'] = array(
  170. '#type' => 'submit',
  171. '#value' => 'Save Data Collection',
  172. '#name' => 'save_collection',
  173. '#ajax' => array(
  174. 'callback' => "tripal_views_handler_area_collections_form_ajax",
  175. 'wrapper' => 'tripal-views-handler-area-collections',
  176. 'effect' => 'fade',
  177. 'method' => 'replace',
  178. 'prevent' => 'click'
  179. ),
  180. );
  181. $form['#prefix'] = '<div id="tripal-views-handler-area-collections">';
  182. $form['#suffix'] = '</div>';
  183. return $form;
  184. }
  185. /**
  186. * Theme the fields section of the tripal_views_handler_area_collections form.
  187. *
  188. * @ingroup tripal_pub
  189. */
  190. function theme_tripal_views_handler_area_collections_fields_fset($variables) {
  191. $form = $variables['form'];
  192. // Organize the elements by the same field id
  193. $fields = array();
  194. $order = array();
  195. $children = element_children($form);
  196. foreach ($children as $key) {
  197. list($item, $field_id) = preg_split('/-/', $key);
  198. $fields[$field_id][$item] = $form[$key];
  199. if (!in_array($field_id, $order)) {
  200. $order[] = $field_id;
  201. }
  202. }
  203. // Next create a table with each field in a different row.
  204. $headers = array('Field', 'Description', 'Supported Files Types');
  205. $rows = array();
  206. foreach ($order as $field_id) {
  207. $rows[] = array(
  208. drupal_render($fields[$field_id]['select']),
  209. drupal_render($fields[$field_id]['description']),
  210. drupal_render($fields[$field_id]['formatters'])
  211. );
  212. }
  213. $table = array(
  214. 'header' => $headers,
  215. 'rows' => $rows,
  216. 'attributes' => array(),
  217. 'sticky' => TRUE,
  218. 'caption' => '',
  219. 'colgroups' => array(),
  220. 'empty' => '',
  221. );
  222. return theme_table($table);
  223. }
  224. /**
  225. * AJAX: Tripal Collections on Tripal Entity-based Views
  226. */
  227. function tripal_views_handler_area_collections_form_ajax($form, $form_state) {
  228. return $form;
  229. }
  230. /**
  231. * Views Area Handler Form SUBMIT: Tripal Collections on Tripal Entity-based Views
  232. */
  233. function tripal_views_handler_area_collections_form_submit($form, $form_state) {
  234. global $user;
  235. $bundle = $form_state['values']['bundle'];
  236. $view = $form_state['values']['view'];
  237. $query = $form_state['values']['query'];
  238. $collection_name = trim($form_state['values']['collection_name']);
  239. $description = $form_state['values']['collection_desc'];
  240. $field_ids = array_key_exists('field_ids', $form_state['values']) ? $form_state['values']['field_ids'] : array();
  241. $uid = $user->uid;
  242. $bundle_name = $bundle->name;
  243. // Get the fields that have been selected
  244. $selected_fids = array();
  245. foreach ($form_state['values'] as $key => $value) {
  246. $matches = array();
  247. if (preg_match('/select-(\d+)/', $key, $matches)) {
  248. if ($value == 1) {
  249. $selected_fids[] = $matches[1];
  250. }
  251. }
  252. }
  253. // Get the entity Ids that match results
  254. $query->range['length'] = $view->total_rows;
  255. $results = $query->execute();
  256. $entities = array();
  257. foreach ($results['TripalEntity'] as $entity) {
  258. $entities[] = $entity->id;
  259. }
  260. $collection = tripal_create_collection(array(
  261. 'uid' => $uid,
  262. 'collection_name' => $collection_name,
  263. 'description' => $description,
  264. 'bundle_name' => $bundle_name,
  265. 'ids' => $entities,
  266. 'fields' => $selected_fids,
  267. ));
  268. }
  269. /**
  270. * Views Area Handler Form: Tripal Collections on Drupal Search API-based
  271. *
  272. * @param $form
  273. * @param $form_state
  274. * @param $view
  275. * The views object that this form will be rendered on.
  276. * @param $query
  277. * The views query object generating the views results.
  278. */
  279. function tripal_views_handler_area_collections_search_api_form($form, $form_state, $view, $query) {
  280. // Set form defaults.
  281. $collection_name = '';
  282. $collection_desc = '';
  283. $form['save_collection'] = array(
  284. '#type' => 'fieldset',
  285. '#title' => t('Save Results'),
  286. '#collapsible' => TRUE,
  287. '#collapsed' => TRUE,
  288. '#description' => t('A data collection is a virtual container into which you can
  289. save data. You can place your search results into a data collection for
  290. download or use with other tools on this site that support data collections.'),
  291. );
  292. // Save the results of the full query for further processing.
  293. // We use clones to ensure we don't inadvertently change the current view.
  294. $cloned_view = clone $view;
  295. $cloned_query = clone $query;
  296. $cloned_query->set_limit(0);
  297. $cloned_query->execute($cloned_view);
  298. $form['save_collection']['results'] = array(
  299. '#type' => 'hidden',
  300. '#value' => serialize($cloned_view->result),
  301. );
  302. unset($cloned_view, $cloned_query);
  303. $form['save_collection']['summary'] = array(
  304. '#type' => 'item',
  305. '#title' => 'Results Summary',
  306. '#markup' => t('There are @total_rows record(s) that can be added to a data collection.', array('@total_rows' => $view->total_rows)),
  307. );
  308. $form['save_collection']['collection_name'] = array(
  309. '#type' => 'textfield',
  310. '#title' => t('Collection Name'),
  311. '#description' => t('Please name this collection for future reference.'),
  312. '#default_value' => $collection_name,
  313. '#required' => TRUE,
  314. );
  315. $form['save_collection']['description_fset'] = array(
  316. '#type' => 'fieldset',
  317. '#title' => t('Add a Description'),
  318. '#collapsible' => TRUE,
  319. '#collapsed' => TRUE,
  320. );
  321. $form['save_collection']['description_fset']['collection_desc'] = array(
  322. '#type' => 'textarea',
  323. '#title' => t('Description'),
  324. '#description' => t('Please provide a description about this data collection. This is meant to help you remember what is in the collection.'),
  325. '#default_value' => $collection_name,
  326. );
  327. // @todo add ability to choose fields for the collection.
  328. $form['save_collection']['button'] = array(
  329. '#type' => 'submit',
  330. '#value' => 'Save Data Collection',
  331. '#name' => 'save_collection',
  332. '#ajax' => array(
  333. 'callback' => "tripal_views_handler_area_collections_form_ajax",
  334. 'wrapper' => 'tripal-views-handler-area-collections',
  335. 'effect' => 'fade',
  336. 'method' => 'replace',
  337. 'prevent' => 'click'
  338. ),
  339. );
  340. $form['#prefix'] = '<div id="tripal-views-handler-area-collections">';
  341. $form['#suffix'] = '</div>';
  342. return $form;
  343. }
  344. /**
  345. * Views Area Handler Form SUBMIT: Tripal Collections on Drupal Search API-based Views
  346. */
  347. function tripal_views_handler_area_collections_search_api_form_validate($form, $form_state) {
  348. // CHECK: Collection with the given name doesn't already exist.
  349. }
  350. /**
  351. * Views Area Handler Form SUBMIT: Tripal Collections on Drupal Search API-based Views
  352. */
  353. function tripal_views_handler_area_collections_search_api_form_submit($form, $form_state) {
  354. global $user;
  355. // Create the collection.
  356. $collection_details = array(
  357. 'uid' => $user->uid,
  358. 'collection_name' => trim($form_state['values']['collection_name']),
  359. 'description' => $form_state['values']['collection_desc'],
  360. );
  361. // This can't be done via tripal_create_collection() since we support more
  362. // then a single bundle. Instead we are going to use the controller class directly.
  363. $collection = new TripalEntityCollection();
  364. $collection->create($collection_details);
  365. $collection_id = $collection->getCollectionID();
  366. // First, determine the bundle for each entity in our resultset.
  367. $entities = array();
  368. $results = unserialize($form_state['values']['results']);
  369. foreach($results as $r) {
  370. // Retrieve the bundle for the current entity.
  371. // ASSUMPTION: all search results are TripalEntities.
  372. $wrapper = entity_metadata_wrapper('TripalEntity', $r->entity);
  373. $bundle = $wrapper->getBundle();
  374. // If this is the first time we've seen this bundle
  375. // then initialize the array.
  376. if (!isset($entities[$bundle])) {
  377. $entities[$bundle] = array(
  378. 'bundle_name' => $bundle,
  379. 'ids' => array(),
  380. 'fields' => array(),
  381. );
  382. }
  383. // Note: $r->entity is the entity_id due to the way the search_api saves results.
  384. // Doing a check here just in case some search index backends store the data differently.
  385. if (is_int($r->entity)) {
  386. $entities[$bundle]['ids'][] = $r->entity;
  387. }
  388. elseif (is_object($r->entity) AND property_exists($r->entity, 'id')) {
  389. $entities[$bundle]['ids'][] = $r->entity->id;
  390. }
  391. else {
  392. tripal_report_error(
  393. 'Tripal Data Collection',
  394. TRIPAL_ERROR,
  395. 'Unable to save entity to collection. Results from the view are: '.print_r($r, TRUE)
  396. );
  397. }
  398. }
  399. // Now add the entities to the collection based on bundle.
  400. foreach($entities as $bundle_name => $bundle_col) {
  401. $field_ids = array();
  402. foreach (field_info_instances('TripalEntity', $bundle_name) as $field) {
  403. $field_ids[] = $field['field_id'];
  404. }
  405. $bundle_col['fields'] = $field_ids;
  406. $collection->addBundle($bundle_col);
  407. }
  408. // Finally, tell the user we're done and link them to the collection.
  409. drupal_set_message(t("Collection '%name' created with %num_recs record(s). Check the !view to generate file links.",
  410. array(
  411. '%name' => $collection_details['collection_name'],
  412. '%num_recs' => count($results),
  413. '!view' => l('data collections page', 'user/' . $user->uid . '/data-collections'),
  414. ))
  415. );
  416. }