Project

General

Profile

Paste
Download (12.6 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / views_data_export / views_data_export.drush.inc @ 56aebcb7

1
<?php
2

    
3
/**
4
 * Implementation of hook_drush_command().
5
 */
6
function views_data_export_drush_command() {
7
  $items = array();
8

    
9
  $items['views-data-export'] = array (
10
    'aliases' => array (
11
      'vde',
12
    ),
13
    'description' => 'Fully executes a views_data_export display of a view and writes the output to file.',
14
    'arguments' => array (
15
      'view_name' => 'The name of the view',
16
      'display_id' => 'The id of the views_data_export display to execute on the view',
17
      'output_file' => 'The file to write the results to - will be overwritten if it already exists',
18
    ),
19
    'options' => array (
20
      'arguments' => 'Comma separated list of arguments to be passed to the view.',
21
      'format' => 'csv,doc,txt,xls or xml. These options are ignored if the display_id passed is a "views_data_export" display.',
22
      'separator' => 'csv only: What character separates the fields (default:,)',
23
      'trim-whitespace' => 'csv only: Trim whitespace from either side of fields (default:1)',
24
      'header-row' => 'csv only: Make the first row a row of headers (default:1)',
25
      'quote-values' => 'csv only: Surround each field in quotes (default:1)',
26
    ),
27
    'examples' => array (
28
      'drush views-data-export myviewname views_data_export_1 output.csv' => 'Export myviewname:views_data_export_1 and write the output to output.csv in the current directory',
29
    ),
30
    'drupal dependencies' => array (
31
      'views_data_export',
32
    ),
33
    'core' => array('7'),
34
  );
35

    
36
  return $items;
37
}
38

    
39

    
40
/**
41
 * Implementation of hook_drush_help().
42
 *
43
 * This function is called whenever a drush user calls
44
 * 'drush help <name-of-your-command>'
45
 *
46
 * @param
47
 *   A string with the help section (prepend with 'drush:')
48
 *
49
 * @return
50
 *   A string with the help text for your command.
51
 */
52
function views_data_export_drush_help($section) {
53
  switch ($section) {
54
    case 'drush:views-data-export':
55
      return dt("This command may be used to fully execute a views_data_export display of a view, batched if need be, and write the output to a file.");
56
  }
57
}
58

    
59
/**
60
 * Implementation of drush_hook_COMMAND_validate().
61
 */
62
function drush_views_data_export_validate() {
63
  // Because of a bug in the way that Drush 4 computes the name of functions to
64
  // call from a Drush command, we may end up getting called twice, so we just
65
  // don't do anything on subsequent invocations.
66
  static $already_run = FALSE;
67
  if ($already_run) {
68
    return;
69
  }
70
  $already_run = TRUE;
71

    
72
  $args = drush_get_arguments();
73
  array_shift($args);
74

    
75
  if (count($args) !== 3) {
76
    return drush_set_error('ARGUMENTS_REQUIRED', dt('All arguments are required.'));
77
  }
78

    
79
  if (!$view = views_get_view($args[0])) {
80
    return drush_set_error('VIEW_DOES_NOT_EXIST', dt('The view !view does not exist.', array ('!view' => $args[0])));
81
  }
82

    
83
  if (!$view->set_display($args[1])) {
84
    return drush_set_error('VIEW_DOES_NOT_EXIST', dt('The view !view does not have the !display display.', array ('!view' => $args[0], '!display' => $args[1])));
85
  }
86
  else {
87
    if ($view->current_display != $args[1]) {
88
      drush_log(dt('Using different display from specified display: @display', array('@display' => $view->current_display)), 'notice');
89
    }
90
    drush_set_option('views_data_export_display_id', $view->current_display);
91
  }
92

    
93
  $format = drush_get_option('format');
94
  $valid_formats = array('csv', 'doc', 'txt', 'xls', 'xml');
95
  if (!empty($format) && !in_array($format, $valid_formats)) {
96
    return drush_set_error('VIEWS_DATA_EXPORT_INVALID_OPTION', dt('The "--format" option is invalid, please supply one of the following: !formats', array('!formats' => implode(', ', $valid_formats))));
97
  }
98
}
99

    
100
/**
101
 * Drush command callback to export a views data to a file.
102
 *
103
 * @see drush_views_data_export_validate().
104
 * @see views_data_export_views_data_export_batch_alter().
105
 */
106
function drush_views_data_export($view_name, $display_id, $output_file) {
107
  // Because of a bug in the way that Drush 4 computes the name of functions to
108
  // call from a Drush command, we may end up getting called twice, so we just
109
  // don't do anything on subsequent invocations.
110
  static $already_run = FALSE;
111
  if ($already_run) {
112
    return;
113
  }
114
  $already_run = TRUE;
115

    
116
  // Set the display to the one that we computed earlier.
117
  $display_id = drush_get_option('views_data_export_display_id', 'default');
118

    
119
  $view = views_get_view($view_name);
120

    
121
  // If the given display_id is not views_data_alter then
122
  // we programatically clone it to a views_data_alter display
123
  // and then execute that one instead
124
  if ($view->display[$display_id]->display_plugin != 'views_data_export') {
125
    //drush_log("Display '$display_id' is not views_data_export. Making one that is and executing that instead =).", 'success');
126

    
127
    $format = drush_get_option('format');
128
    $settings = array();
129
    switch ($format) {
130
      case 'doc':
131
      case 'xls':
132
      case 'xml':
133
      case 'txt':
134
        $settings['display_options']['style_plugin'] = 'views_data_export_' . $format;
135
        break;
136
      case 'csv':
137
      default:
138
      $settings['display_options']['style_plugin'] = 'views_data_export_csv';
139
      if ($separator = drush_get_option('separator')) {
140
        $settings['display_options']['style_options']['separator'] = $separator;
141
      }
142
      if (!$trim = drush_get_option('trim-whitespace')) {
143
        $settings['display_options']['style_options']['trim'] = 0;
144
      }
145
      if (!$header = drush_get_option('header-row')) {
146
        $settings['display_options']['style_options']['header'] = 0;
147
      }
148
      if (!$quote = drush_get_option('quote-values')) {
149
        $settings['display_options']['style_options']['quote'] = 0;
150
      }
151
      // Seperator
152
    }
153

    
154
    $display_id = _drush_views_data_export_clone_display($view, $display_id, $settings);
155
  }
156

    
157
  $view->set_display($display_id);
158

    
159
  // We execute the view normally, and take advantage
160
  // of an alter function to interject later and batch it ourselves
161

    
162
  $options = array();
163
  // Let's see if the given $output_file is a absolute path.
164
  if (strpos($output_file, '/') === 0) {
165
    $options['output_file'] = $output_file;
166
  }
167
  else {
168
    $options['output_file'] = realpath(drush_get_context('DRUSH_OLDCWD', getcwd())) . '/' . $output_file;
169
  }
170

    
171
  $arguments = drush_get_option('arguments', '');
172
  $arguments = explode(',', $arguments);
173

    
174
  if ($view->display_handler->is_batched()) {
175
    // This is a batched export, and needs to be handled as such.
176
    _drush_views_data_export_override_batch($view_name, $display_id, $options);
177

    
178
    $view->execute_display($display_id, $arguments);
179
  }
180
  else {
181
    // This export isn't batched.
182
    ob_start();
183
    $view->execute_display($display_id, $arguments);
184
    // Get the results, and clean the output buffer.
185
    $result = ob_get_contents();
186
    // Clean the buffer.
187
    ob_end_clean();
188
    // Save the results to file.
189
    // Copy file over
190
    if (file_put_contents($options['output_file'], $result)) {
191
      drush_log("Data export saved to " . $options['output_file'], 'success');
192
    }
193
    else {
194
      drush_set_error('VIEWS_DATA_EXPORT_COPY_ERROR', dt("The file could not be copied to the selected destination"));
195
    }
196
  }
197

    
198
}
199

    
200

    
201
/**
202
 * Helper function that indicates that we want to
203
 * override the batch that the views_data_export view creates
204
 * on it's initial time through.
205
 *
206
 * Also provides a place to stash options that need to stay around
207
 * until the end of the batch
208
 */
209
function _drush_views_data_export_override_batch($view = NULL, $display = NULL, $options = TRUE) {
210
  static $_views;
211
  if (isset($view)) {
212
    $_views[$view][$display] = $options;
213
  }
214
  return $_views;
215
}
216

    
217
/**
218
 * Implementation of hook_views_data_export_batch_alter()
219
 */
220
function views_data_export_views_data_export_batch_alter(&$batch, &$final_destination, &$querystring) {
221

    
222
  // Copy the batch, because we're going to monkey with it, a lot!
223
  $new_batch = $batch;
224

    
225
  $view_name = $new_batch['view_name'];
226
  $display_id = $new_batch['display_id'];
227

    
228
  $ok_to_override = _drush_views_data_export_override_batch();
229

    
230
  // Make sure we do nothing if we are called not following the execution of
231
  // our drush command. This could happen if the file with this function in it
232
  // is included during the normal execution of the view
233
  if (!$ok_to_override[$view_name][$display_id]) {
234
    return;
235
  }
236

    
237
  $options = $ok_to_override[$view_name][$display_id];
238

    
239
  // We actually never return from the drupal_alter, but
240
  // use drush's batch system to run the same batch
241

    
242
  // Add a final callback
243
  $new_batch['operations'][] = array(
244
    '_drush_views_data_export_batch_finished', array($batch['eid'], $options['output_file']),
245
  );
246

    
247
  batch_set($new_batch);
248
  $new_batch =& batch_get();
249
  // Drush handles the different processes, so instruct BatchAPI not to.
250
  $new_batch['progressive'] = FALSE;
251
  // Process the batch using drush.
252
  drush_backend_batch_process();
253

    
254
  // Instruct the view display plugin that it shouldn't set a batch.
255
  $batch = array();
256
}
257

    
258

    
259
/**
260
 * Get's called at the end of the drush batch process that generated our export
261
 */
262
function _drush_views_data_export_batch_finished($eid, $output_file, &$context) {
263
  // Fetch export info
264
  $export = views_data_export_get($eid);
265

    
266
  // Perform cleanup
267
  $view = views_data_export_view_retrieve($eid);
268
  $view->set_display($export->view_display_id);
269
  $view->display_handler->batched_execution_state = $export;
270
  $view->display_handler->remove_index();
271

    
272
  // Get path to temp file
273
  $temp_file = $view->display_handler->outputfile_path();
274

    
275
  // Copy file over
276
  if (@drush_op('copy', $temp_file, $output_file)) {
277
    drush_log("Data export saved to " . $output_file, 'success');
278
  }
279
  else {
280
    drush_set_error('VIEWS_DATA_EXPORT_COPY_ERROR', dt("The file could not be copied to the selected destination"));
281
  }
282

    
283
}
284

    
285

    
286
/**
287
 * Helper function that takes a view and returns a clone of it
288
 * that has cloned a given display to one of type views_data_export
289
 *
290
 * @param &$view
291
 *   Modified to contain the new display
292
 *
293
 * @return
294
 *   The new display_id
295
 */
296
function _drush_views_data_export_clone_display(&$view, $display_id, $settings = array()) {
297

    
298
  // Create the new display
299
  $new_display_id = _drush_views_data_export_generate_display_id($view, 'views_data_export');
300
  $view->display[$new_display_id] = clone $view->display[$display_id];
301

    
302
  // Ensure we have settings we'll need for our display
303
  $default_settings = array (
304
    'id' => $new_display_id,
305
    'display_plugin' => 'views_data_export',
306
    'position' => 99,
307
    'display_options' => array (
308
      'style_plugin' => 'views_data_export_csv',
309
      'style_options' => array(
310
        'attach_text' => 'CSV',
311
        'provide_file' => 1,
312
        'filename' => 'view-%view.csv',
313
        'parent_sort' => 1,
314
        'separator' => ',',
315
        'quote' => 1,
316
        'trim' => 1,
317
        'header' => 1,
318
      ),
319
      'use_batch' => 'batch',
320
      'path' => '',
321
      'displays' => array (
322
        'default' => 'default',
323
      ),
324
    ),
325
  );
326
  $settings = array_replace_recursive($default_settings, $settings);
327

    
328
  $view->display[$new_display_id] = (object)array_replace_recursive((array)$view->display[$new_display_id], $settings);
329

    
330
  return $new_display_id;
331
}
332

    
333

    
334
/**
335
 * Generate a display id of a certain plugin type.
336
 * See http://drupal.org/files/issues/348975-clone-display.patch
337
 *
338
 * @param $type
339
 *   Which plugin should be used for the new display id.
340
 */
341
function _drush_views_data_export_generate_display_id($view, $type) {
342
  // 'default' is singular and is unique, so just go with 'default'
343
  // for it. For all others, start counting.
344
  if ($type == 'default') {
345
    return 'default';
346
  }
347
  // Initial id.
348
  $id = $type . '_1';
349
  $count = 1;
350

    
351
  // Loop through IDs based upon our style plugin name until
352
  // we find one that is unused.
353
  while (!empty($view->display[$id])) {
354
    $id = $type . '_' . ++$count;
355
  }
356

    
357
  return $id;
358
}
359

    
360
/**
361
 * If we're using PHP < 5.3.0 then we'll need
362
 * to define this function ourselves.
363
 * See: http://phpmyanmar.com/phpcodes/manual/function.array-replace-recursive.php
364
 */
365
if (!function_exists('array_replace_recursive')) {
366
function array_replace_recursive($array, $array1) {
367
  // Get array arguments
368
  $arrays = func_get_args();
369

    
370
  // Define the original array
371
  $original = array_shift($arrays);
372

    
373
  // Loop through arrays
374
  foreach ($arrays as $array) {
375
    // Loop through array key/value pairs
376
    foreach ($array as $key => $value) {
377
      // Value is an array
378
      if (is_array($value)) {
379
        // Traverse the array; replace or add result to original array
380
        $original[$key] = array_replace_recursive($original[$key], $array[$key]);
381
      }
382

    
383
      // Value is not an array
384
      else {
385
        // Replace or add current value to original array
386
        $original[$key] = $value;
387
      }
388
    }
389
  }
390

    
391
  // Return the joined array
392
  return $original;
393
}
394
}