tripal_views_handler_area_collections.inc 16 KB

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