views_data_export.module 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <?php
  2. /**
  3. * @file
  4. * Provides the ability to export to specific
  5. */
  6. define('VIEWS_DATA_EXPORT_HEADER', 'header');
  7. define('VIEWS_DATA_EXPORT_BODY', 'body');
  8. define('VIEWS_DATA_EXPORT_FOOTER', 'footer');
  9. define('VIEWS_DATA_EXPORT_FINISHED', 'finished');
  10. define('VIEWS_DATA_EXPORT_INDEX_TABLE_PREFIX', 'views_data_export_index_');
  11. /**
  12. * Implements hook_init().
  13. */
  14. function views_data_export_init() {
  15. // We have to include our theme preprocessors here until:
  16. // http://drupal.org/node/1096770 is fixed.
  17. module_load_include('inc', 'views_data_export', 'theme/views_data_export.theme');
  18. }
  19. /**
  20. * Implementation of hook_views_api().
  21. */
  22. function views_data_export_views_api() {
  23. return array(
  24. 'api' => 2,
  25. );
  26. }
  27. /**
  28. /**
  29. * Checks whether the passed URI identifies an export file.
  30. *
  31. * @param string $uri
  32. * A file URI.
  33. *
  34. * @return bool
  35. * TRUE if the URI identifies an export file, FALSE otherwise.
  36. */
  37. function views_data_export_is_export_file($uri) {
  38. foreach (entity_load('file', FALSE, array('uri' => $uri)) as $file) {
  39. // See if this is an export file.
  40. $usages = file_usage_list($file);
  41. return !empty($usages['views_data_export']['eid']);
  42. }
  43. return FALSE;
  44. }
  45. /**
  46. * Implementation of hook_theme().
  47. */
  48. function views_data_export_theme() {
  49. // Make sure that views picks up the preprocess functions.
  50. module_load_include('inc', 'views_data_export', 'theme/views_data_export.theme');
  51. $hooks = array();
  52. $hooks['views_data_export_feed_icon'] = array(
  53. 'pattern' => 'views_data_export_feed_icon__',
  54. 'variables' => array(
  55. 'image_path' => NULL,
  56. 'url' => NULL,
  57. 'query' => '',
  58. 'text' => '',
  59. ),
  60. 'file' => 'theme/views_data_export.theme.inc',
  61. );
  62. $hooks['views_data_export_complete_page'] = array (
  63. 'variables' => array(
  64. 'file' => '',
  65. 'errors' => array(),
  66. 'return_url'=> '',
  67. ),
  68. 'file' => 'theme/views_data_export.theme.inc',
  69. );
  70. $hooks['views_data_export_message'] = array (
  71. 'variables' => array(
  72. 'message' => '',
  73. 'type' => 'info',
  74. ),
  75. 'file' => 'theme/views_data_export.theme.inc',
  76. );
  77. return $hooks;
  78. }
  79. /**
  80. * Implementation of hook_cron().
  81. */
  82. function views_data_export_cron() {
  83. views_data_export_garbage_collect();
  84. }
  85. /**
  86. * Removes any temporary index tables that have been left
  87. * behind. This is caused by batch processes which are
  88. * started but never finished.
  89. *
  90. * Removes all trace of exports from the database that
  91. * were created more than $expires seconds ago
  92. *
  93. * @param $expires
  94. * Seconds ago. Defaults to that given in the settings.
  95. * @param $chunk
  96. * The number of tables to test for and delete.
  97. * Defaults to that given in the settings. Pass -1
  98. * for this setting to remove any restriction and to
  99. * garbage collect all exports.
  100. */
  101. function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) {
  102. if (lock_acquire('views_data_export_gc')) {
  103. if (!isset($expires)) {
  104. $expires = variable_get('views_data_export_gc_expires', DRUPAL_MAXIMUM_TEMP_FILE_AGE);
  105. }
  106. if (!isset($chunk)) {
  107. $chunk = variable_get('views_data_export_gc_chunk', 30);
  108. }
  109. if ($chunk == -1) {
  110. $result = db_query("SELECT eid FROM {views_data_export} WHERE time_stamp <= :timestamp ORDER BY time_stamp ASC", array(':timestamp' => REQUEST_TIME - $expires));
  111. }
  112. else {
  113. $result = db_query_range("SELECT eid FROM {views_data_export} WHERE time_stamp <= :timestamp ORDER BY time_stamp ASC", 0, $chunk, array(':timestamp' => REQUEST_TIME - $expires));
  114. }
  115. $eids_to_clear = array();
  116. foreach ($result as $row) {
  117. $eids_to_clear[] = $row->eid;
  118. }
  119. // We do two things to exports we want to garbage collect
  120. // 1. Delete the index table for it, if it is still around.
  121. // 2. Delete the files used during the export.
  122. // 3. Delete the row from the exports table.
  123. // 4. Delete the view from the object_cache.
  124. if (count($eids_to_clear)) {
  125. foreach ($eids_to_clear as $eid) {
  126. // 1. Delete index table, if it is still around for some reason
  127. $table = VIEWS_DATA_EXPORT_INDEX_TABLE_PREFIX . $eid;
  128. if (db_table_exists($table)) {
  129. db_drop_table($table);
  130. }
  131. // 2. Delete the files used during the export.
  132. foreach (views_data_export_export_list_files($eid) as $file) {
  133. file_delete($file, TRUE);
  134. }
  135. }
  136. // 3. Delete the entries in the exports table.
  137. db_delete('views_data_export')
  138. ->condition('eid', $eids_to_clear, 'IN')
  139. ->execute();
  140. // 4. Clear the cached views
  141. views_data_export_view_clear($eids_to_clear);
  142. }
  143. lock_release('views_data_export_gc');
  144. }
  145. }
  146. /**
  147. * Determines where a file is used.
  148. *
  149. * @param $eid
  150. * The ID of a Views Data Export.
  151. *
  152. * @return array
  153. * An array of loaded files objects used by the specified export.
  154. */
  155. function views_data_export_export_list_files($eid) {
  156. $result = db_select('file_usage', 'f')
  157. ->fields('f', array('fid'))
  158. ->condition('id', $eid)
  159. ->condition('type', 'eid')
  160. ->condition('module', 'views_data_export')
  161. ->execute();
  162. return file_load_multiple($result->fetchCol());
  163. }
  164. /**
  165. * Batch API callback.
  166. * Handles all batching operations by executing the appropriate view.
  167. */
  168. function _views_data_export_batch_process($export_id, $display_id, $exposed_input, &$context) {
  169. // Don't show the admin menu on batch page, some people don't like it.
  170. if (module_exists('admin_menu')) {
  171. module_invoke('admin_menu', 'suppress');
  172. }
  173. // Fetch the view in question from our cache
  174. $view = views_data_export_view_retrieve($export_id);
  175. $view->set_display($display_id);
  176. if (!empty($exposed_input)) {
  177. $view->set_exposed_input($exposed_input);
  178. }
  179. // Inform the data_export display which export it corresponds to and execute
  180. if (!isset($view->display_handler->batched_execution_state)) {
  181. $view->display_handler->batched_execution_state = new stdClass();
  182. }
  183. $view->display_handler->batched_execution_state->eid = $export_id;
  184. $view->display_handler->views_data_export_cached_view_loaded = TRUE;
  185. $view->execute_display($display_id);
  186. // Update batch api progress information
  187. $sandbox = $view->display_handler->batched_execution_state->sandbox;
  188. $context['finished'] = $sandbox['finished'];
  189. $context['message'] = $sandbox['message'];
  190. views_data_export_view_store($export_id, $view);
  191. }
  192. /**********/
  193. /** CRUD **/
  194. /**********/
  195. /**
  196. * Save a new export into the database.
  197. */
  198. function views_data_export_new($view_name, $view_display_id, $file) {
  199. // Insert new row into exports table
  200. $record = (object) array(
  201. 'view_name' => $view_name,
  202. 'view_display_id' => $view_display_id,
  203. 'time_stamp' => REQUEST_TIME,
  204. 'fid' => $file,
  205. 'batch_state' => VIEWS_DATA_EXPORT_HEADER,
  206. 'sandbox' => array(),
  207. );
  208. drupal_write_record('views_data_export', $record);
  209. return $record;
  210. }
  211. /**
  212. * Update an export row in the database
  213. */
  214. function views_data_export_update($state) {
  215. // Note, drupal_write_record handles serializing
  216. // the sandbox field as per our schema definition
  217. drupal_write_record('views_data_export', $state, 'eid');
  218. }
  219. /**
  220. * Get the information about a previous export.
  221. */
  222. function views_data_export_get($export_id) {
  223. $object = db_query("SELECT * FROM {views_data_export} WHERE eid = :eid", array(':eid' => (int)$export_id))->fetch();
  224. if ($object) {
  225. $object->sandbox = unserialize($object->sandbox);
  226. }
  227. return $object;
  228. }
  229. /**
  230. * Remove the information about an export.
  231. */
  232. function views_data_export_clear($export_id) {
  233. db_delete('views_data_export')
  234. ->condition('eid', $export_id)
  235. ->execute();
  236. views_data_export_view_clear($export_id);
  237. }
  238. /**
  239. * Store a view in the object cache.
  240. */
  241. function views_data_export_view_store($export_id, $view) {
  242. // Store a clean copy of the view.
  243. $_view = $view->clone_view();
  244. views_data_export_view_clear($export_id);
  245. $record = array(
  246. 'eid' => $export_id,
  247. 'data' => $_view,
  248. 'updated' => REQUEST_TIME,
  249. );
  250. drupal_write_record('views_data_export_object_cache', $record);
  251. }
  252. /**
  253. * Retrieve a view from the object cache.
  254. */
  255. function views_data_export_view_retrieve($export_id) {
  256. views_include('view');
  257. $data = db_query("SELECT * FROM {views_data_export_object_cache} WHERE eid = :eid", array(':eid' => $export_id))->fetch();
  258. if ($data) {
  259. $view = unserialize($data->data);
  260. }
  261. return $view;
  262. }
  263. /**
  264. * Clear a view from the object cache.
  265. *
  266. * @param $export_id
  267. * An export ID or an array of export IDs to clear from the object cache.
  268. */
  269. function views_data_export_view_clear($export_id) {
  270. db_delete('views_data_export_object_cache')
  271. ->condition('eid', $export_id)
  272. ->execute();
  273. }