views_data_export_plugin_style_export.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. <?php
  2. /**
  3. * @file
  4. * Plugin include file for export style plugin.
  5. */
  6. /**
  7. * Generalized style plugin for export plugins.
  8. *
  9. * @ingroup views_style_plugins
  10. */
  11. class views_data_export_plugin_style_export extends views_plugin_style {
  12. /**
  13. * Set options fields and default values.
  14. *
  15. * @return
  16. * An array of options information.
  17. */
  18. function option_definition() {
  19. $options = parent::option_definition();
  20. $options['attach_text'] = array(
  21. 'default' => $this->definition['export feed text'],
  22. 'translatable' => TRUE,
  23. );
  24. $options['provide_file'] = array(
  25. 'default' => FALSE,
  26. 'translatable' => FALSE,
  27. );
  28. $options['filename'] = array(
  29. 'default' => $this->definition['export feed file'],
  30. 'translatable' => FALSE,
  31. );
  32. $options['parent_sort'] = array(
  33. 'default' => FALSE,
  34. 'translatable' => FALSE,
  35. );
  36. return $options;
  37. }
  38. /**
  39. * Options form mini callback.
  40. *
  41. * @param $form
  42. * Form array to add additional fields to.
  43. * @param $form_state
  44. * State of the form.
  45. * @return
  46. * None.
  47. */
  48. function options_form(&$form, &$form_state) {
  49. $form['attach_text'] = array(
  50. '#type' => 'textfield',
  51. '#title' => t('Attach text'),
  52. '#default_value' => $this->options['attach_text'],
  53. '#description' => t('This text is used in building the feed link. By default it is the "alt" text for the feed image.'),
  54. );
  55. $form['provide_file'] = array(
  56. '#type' => 'checkbox',
  57. '#title' => t('Provide as file'),
  58. '#default_value' => $this->options['provide_file'],
  59. '#description' => t('By deselecting this, the xml file will be provided as a feed instead of a file for download.'),
  60. );
  61. $form['filename'] = array(
  62. '#type' => 'textfield',
  63. '#title' => t('Filename'),
  64. '#default_value' => $this->options['filename'],
  65. '#description' => t('The filename that will be suggested to the browser for downloading purposes. You may include replacement patterns from the list below.'),
  66. '#process' => array('ctools_dependent_process'),
  67. '#dependency' => array(
  68. 'edit-style-options-provide-file' => array(TRUE),
  69. ),
  70. );
  71. // General token replacement.
  72. $output = t('<p>The following substitution patterns are available for this display. Use the pattern shown on the left to display the value indicated on the right.</p>');
  73. $items = array(
  74. '%view == ' . t('View name'),
  75. '%display == ' . t('Display name'),
  76. );
  77. $output .= theme('item_list', array('items' => $items));
  78. // Get a list of the available arguments for token replacement.
  79. $options = array();
  80. $count = 0; // This lets us prepare the key as we want it printed.
  81. foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
  82. $options[t('Arguments')]['%' . ++$count . '-title'] = t('@argument title', array('@argument' => $handler->ui_name()));
  83. $options[t('Arguments')]['%' . $count . '-value'] = t('@argument value', array('@argument' => $handler->ui_name()));
  84. }
  85. // Append the list with exposed filters stuff.
  86. $options[t('Exposed filters')]['%exposed'] = t('effective exposed filters, like <em>filter1_foo-filter2_bar</em>');
  87. // ...and datestamp.
  88. $time = REQUEST_TIME;
  89. $parts = array(
  90. 'full' => 'Y-m-d\TH-i-s',
  91. 'yy' => 'y',
  92. 'yyyy' => 'Y',
  93. 'mm' => 'm',
  94. 'mmm' => 'M',
  95. 'dd' => 'd',
  96. 'ddd' => 'D',
  97. 'hh' => 'H',
  98. 'ii' => 'i',
  99. 'ss' => 's',
  100. );
  101. foreach ($parts as $part => $format) {
  102. $options[t('Timestamp')]['%timestamp-' . $part] = format_date($time, 'custom', $format);
  103. }
  104. // We have some options, so make a list.
  105. if (!empty($options)) {
  106. foreach (array_keys($options) as $type) {
  107. if (!empty($options[$type])) {
  108. $items = array();
  109. foreach ($options[$type] as $key => $value) {
  110. $items[] = $key . ' == ' . $value;
  111. }
  112. $output .= theme('item_list', array('items' => $items, 'title' => $type));
  113. }
  114. }
  115. }
  116. $form['help'] = array(
  117. '#type' => 'fieldset',
  118. '#title' => t('Replacement patterns'),
  119. '#collapsible' => TRUE,
  120. '#collapsed' => TRUE,
  121. '#value' => $output,
  122. '#dependency' => array(
  123. 'edit-style-options-provide-file' => array(1),
  124. ),
  125. );
  126. $form['parent_sort'] = array(
  127. '#type' => 'checkbox',
  128. '#title' => t('Parent sort'),
  129. '#default_value' => $this->options['parent_sort'],
  130. '#description' => t('Try to apply any additional sorting from the attached display like table sorting to the exported feed.'),
  131. );
  132. }
  133. /**
  134. * Attach this view to another display as a feed.
  135. *
  136. * Provide basic functionality for all export style views like attaching a
  137. * feed image link.
  138. */
  139. function attach_to($display_id, $path, $title) {
  140. if ($this->display->handler->access()) {
  141. $type = $this->definition['export feed type'];
  142. $theme_pattern = array(
  143. 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id . '__' . $type,
  144. 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id,
  145. 'views_data_export_feed_icon__' . $this->view->name . '__' . $type,
  146. 'views_data_export_feed_icon__' . $display_id . '__' . $type,
  147. 'views_data_export_feed_icon__' . $display_id,
  148. 'views_data_export_feed_icon__' . $type,
  149. 'views_data_export_feed_icon',
  150. );
  151. $query = $this->view->get_exposed_input();
  152. // Stash the display id we're coming form in the url so we can hijack it later.
  153. if ($this->options['parent_sort']) {
  154. $query['attach'] = $display_id;
  155. }
  156. if (!isset($this->view->feed_icon)) {
  157. $this->view->feed_icon = '';
  158. }
  159. $this->view->feed_icon .= theme($theme_pattern, array(
  160. 'image_path' => $this->definition['export feed icon'],
  161. 'url' => $this->view->get_url(NULL, $path),
  162. 'query' => $query,
  163. 'text' => $this->options['attach_text'],
  164. )
  165. );
  166. }
  167. }
  168. function build_sort() {
  169. // Bypass doing any sort of testing if parent sorting is disabled.
  170. if (!$this->options['parent_sort']) {
  171. return parent::build_sort();
  172. }
  173. $displays = $this->display->handler->get_option('displays');
  174. // Here is later. We can get the passed argument and use it to know which
  175. // display we can from and then do some addition processing.
  176. // If the display exists and is attached these two tests will succeed.
  177. if (isset($_GET['attach']) && isset($displays[$_GET['attach']]) && $displays[$_GET['attach']]) {
  178. // Setup the second style we're going to be using to sort on.
  179. $plugin_id = $displays[$_GET['attach']];
  180. $parent_display = $this->view->display[$plugin_id];
  181. $style_name = $parent_display->handler->get_option('style_plugin');
  182. $style_options = $parent_display->handler->get_option('style_options');
  183. $this->extra_style = views_get_plugin('style', $style_name);
  184. $this->extra_style->init($this->view, $parent_display, $style_options);
  185. // Call the second styles sort funciton and return the value.
  186. return $this->extra_style->build_sort();
  187. }
  188. }
  189. function build_sort_post() {
  190. // If we found an extra style plugin earlier, pass off the build_sort_post call to it.
  191. if (isset($this->extra_style)) {
  192. return $this->extra_style->build_sort_post();
  193. }
  194. else {
  195. return parent::build_sort_post();
  196. }
  197. }
  198. /**
  199. * Render the display in this style.
  200. */
  201. function render() {
  202. if ($this->uses_row_plugin() && empty($this->row_plugin)) {
  203. vpr('views_plugin_style_default: Missing row plugin');
  204. return;
  205. }
  206. $output = '';
  207. $rows['header'] = $this->render_header();
  208. $rows['body'] = $this->render_body();
  209. $rows['footer'] = $this->render_footer();
  210. $title = '';
  211. $output .= theme($this->theme_functions(), array('view' => $this->view, 'options' => $this->options, 'rows' => $rows, 'title' => $title));
  212. return $output;
  213. }
  214. function render_header() {
  215. $rows = array();
  216. $title = '';
  217. $output = '';
  218. $output .= theme($this->theme_functions($this->definition['additional themes base'] . '_header'), array('view' => $this->view, 'options' => $this->options, 'rows' => $rows, 'title' => $title));
  219. return $output;
  220. }
  221. function render_footer() {
  222. $rows = array();
  223. $title = '';
  224. $output = '';
  225. $output .= theme($this->theme_functions($this->definition['additional themes base'] . '_footer'), array('view' => $this->view, 'options' => $this->options, 'rows' => $rows, 'title' => $title));
  226. return $output;
  227. }
  228. function render_body() {
  229. if ($this->uses_row_plugin() && empty($this->row_plugin)) {
  230. vpr('views_plugin_style_default: Missing row plugin');
  231. return;
  232. }
  233. // Group the rows according to the grouping field, if specified.
  234. $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
  235. // Render each group separately and concatenate. Plugins may override this
  236. // method if they wish some other way of handling grouping.
  237. $output = '';
  238. foreach ($sets as $title => $records) {
  239. if ($this->uses_row_plugin()) {
  240. $rows = array();
  241. foreach ($records as $row_index => $row) {
  242. $this->view->row_index = $row_index;
  243. $rows[] = $this->row_plugin->render($row);
  244. }
  245. }
  246. else {
  247. $rows = $records;
  248. }
  249. $title = '';
  250. $output .= theme($this->theme_functions($this->definition['additional themes base'] . '_body'), array('view' => $this->view, 'options' => $this->options, 'rows' => $rows, 'title' => $title));
  251. }
  252. unset($this->view->row_index);
  253. return $output;
  254. }
  255. /**
  256. * Provide a full list of possible theme templates used by this style.
  257. */
  258. function theme_functions($hook = NULL) {
  259. if (is_null($hook)) {
  260. $hook = $this->definition['theme'];
  261. }
  262. return views_theme_functions($hook, $this->view, $this->display);
  263. }
  264. /**
  265. * Add any HTTP headers that this style plugin wants to.
  266. */
  267. function add_http_headers() {
  268. drupal_add_http_header('Cache-Control', 'max-age=60, must-revalidate');
  269. if (!empty($this->definition['export headers'])) {
  270. foreach ($this->definition['export headers'] as $name => $value) {
  271. drupal_add_http_header($name, $value);
  272. }
  273. }
  274. if (isset($this->options['filename']) && !empty($this->options['provide_file'])) {
  275. $filename = $this->generate_filename();
  276. if ($filename) {
  277. drupal_add_http_header('Content-Disposition', 'attachment; filename="'. $filename .'"');
  278. }
  279. }
  280. }
  281. /**
  282. * Generate the filename for the export.
  283. */
  284. function generate_filename() {
  285. $view = $this->view;
  286. $filename = '';
  287. if (isset($this->options['filename']) && !empty($this->options['provide_file'])) {
  288. // General tokens.
  289. $tokens = array(
  290. '%view' => check_plain($view->name),
  291. '%display' => check_plain($view->current_display),
  292. );
  293. // Argument tokens.
  294. $count = 0;
  295. foreach ($view->display_handler->get_handlers('argument') as $arg => $handler) {
  296. $token = '%' . ++$count;
  297. $tokens[$token . '-title'] = $handler->get_title();
  298. $tokens[$token . '-value'] = isset($view->args[$count - 1]) ? check_plain($view->args[$count - 1]) : '';
  299. }
  300. // Effective exposed filters token.
  301. $exposed = array();
  302. foreach ($view->display_handler->get_handlers('filter') as $arg => $handler) {
  303. if (!$handler->options['exposed']) {
  304. continue;
  305. }
  306. if (!empty($view->exposed_input[$handler->options['expose']['identifier']])) {
  307. $identifier = $handler->options['expose']['identifier'];
  308. $option = $view->exposed_input[$identifier];
  309. // The option may be a string or an array, depending on whether the
  310. // widget is a text box/area or a select box.
  311. if (is_array($option)) {
  312. $option = implode('--', $option);
  313. }
  314. $exposed[] = check_plain($identifier) . '_' . check_plain($option);
  315. }
  316. }
  317. if (!empty($exposed)) {
  318. $tokens['%exposed'] = implode('-', $exposed);
  319. }
  320. else {
  321. $tokens['%exposed'] = 'default' ;
  322. }
  323. // Timestamp token.
  324. $time = REQUEST_TIME;
  325. $parts = array(
  326. 'full' => 'Y-m-d\TH-i-s',
  327. 'yy' => 'y',
  328. 'yyyy' => 'Y',
  329. 'mm' => 'm',
  330. 'mmm' => 'M',
  331. 'dd' => 'd',
  332. 'ddd' => 'D',
  333. 'hh' => 'H',
  334. 'ii' => 'i',
  335. 'ss' => 's',
  336. );
  337. foreach ($parts as $part => $format) {
  338. $tokens['%timestamp-' . $part] = format_date($time, 'custom', $format);
  339. }
  340. $filename = strtr($this->options['filename'], $tokens);
  341. }
  342. return $filename;
  343. }
  344. }