From 322dd995bfa9a72910c4a3dd5f2c5c3f17cfdf16 Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Mon, 20 Apr 2015 18:21:45 +0200 Subject: [PATCH] more module updates --- .../contrib/dev/variable/variable.api.php | 39 ++++ .../contrib/dev/variable/variable.form.inc | 19 +- .../contrib/dev/variable/variable.info | 6 +- .../contrib/dev/variable/variable.module | 46 +++- .../dev/variable/variable.variable.inc | 5 +- .../variable_admin/variable_admin.info | 6 +- .../variable_admin/variable_admin.module | 2 - .../variable_advanced/variable_advanced.info | 11 - .../variable_advanced.module | 5 - .../variable_advanced.variable.inc | 73 ------ .../variable_example/variable_example.info | 6 +- .../variable_realm/variable_realm.form.inc | 6 + .../variable_realm/variable_realm.info | 6 +- .../variable_realm/variable_realm.module | 4 +- .../variable_store/variable_store.info | 6 +- .../variable_views/variable_views.info | 6 +- ...iews_data_export_plugin_display_export.inc | 219 ++++++++++++++++-- .../views_data_export_plugin_style_export.inc | 83 ++++--- ...ws_data_export_plugin_style_export_csv.inc | 21 +- ...ws_data_export_plugin_style_export_xml.inc | 99 ++++++++ .../theme/views_data_export.theme.inc | 119 ++++++---- .../views_data_export.drush.inc | 44 +++- .../views_data_export/views_data_export.info | 35 +-- .../views_data_export.install | 88 +++++-- .../views_data_export.module | 101 ++++---- 25 files changed, 747 insertions(+), 308 deletions(-) delete mode 100644 sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.info delete mode 100644 sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.module delete mode 100644 sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.variable.inc diff --git a/sites/all/modules/contrib/dev/variable/variable.api.php b/sites/all/modules/contrib/dev/variable/variable.api.php index 7e0c7a5c..2dcad164 100644 --- a/sites/all/modules/contrib/dev/variable/variable.api.php +++ b/sites/all/modules/contrib/dev/variable/variable.api.php @@ -84,6 +84,8 @@ * - "repeat": Array of variable properties for children variables. * - "localize": Boolean value, TRUE for variables that should be localized. This may be used by other modules. * - "validate callback": Callback to validate the variable value, it will be added to form element #validate. + * + * @see hook_variable_info_alter() */ function hook_variable_info($options) { $variables['site_name'] = array( @@ -102,6 +104,17 @@ function hook_variable_info($options) { return $variables; } +/** + * Alter the variable definitions. + * + * @param $info + * The variable info array, keyed by variable name. + * + * @see hook_variable_info() + */ +function hook_variable_info_alter(&$info) { +} + /** * Define types of variables or list of values used by a module. * @@ -145,6 +158,8 @@ function hook_variable_info($options) { * * A special attribute: * - "type": Variable subtype, the properties for the subtype will be added to these ones. + * + * @see hook_variable_type_info_alter() */ function hook_variable_type_info() { $type['mail_address'] = array( @@ -162,6 +177,17 @@ function hook_variable_type_info() { return $type; } +/** + * Alter the variable type definitions. + * + * @param $info + * The variable type info array, keyed by variable type name. + * + * @see hook_variable_type_info() + */ +function hook_variable_type_info_alter(&$info) { +} + /** * Define groups of variables used by a module. * @@ -181,6 +207,8 @@ function hook_variable_type_info() { * - "description": The human readable description of the group. Must be localized. * - "access": Permission required to edit group's variables. Will default to 'administer site configuration'. * - "path": Array of administration paths where these variables can be accessed. + * + * @see hook_variable_group_info_alter() */ function hook_variable_group_info() { $groups['system_site_information'] = array( @@ -197,6 +225,17 @@ function hook_variable_group_info() { return $groups; } +/** + * Alter the variable group definitions. + * + * @param $info + * The variable type info array, keyed by variable group name. + * + * @see hook_variable_group_info() + */ +function hook_variable_group_info_alter(&$info) { +} + /** * Alter system settings forms. * diff --git a/sites/all/modules/contrib/dev/variable/variable.form.inc b/sites/all/modules/contrib/dev/variable/variable.form.inc index 15c8043f..08beeedc 100644 --- a/sites/all/modules/contrib/dev/variable/variable.form.inc +++ b/sites/all/modules/contrib/dev/variable/variable.form.inc @@ -154,14 +154,19 @@ function variable_form_element_options($variable, $options = array()) { } /** - * Implement validate callback + * Execute submit callbacks for variables in form. */ -function variable_form_element_validate($element, &$form_state, $form) { - $variable = $element['#variable']; - variable_include($variable); - $variable['value'] = isset($element['#value']) ? $element['#value'] : NULL; - if ($error = call_user_func($variable['validate callback'], $variable)) { - form_error($element, $error); +function variable_form_submit_callback($form, &$form_state) { + if (isset($form['#variable_edit_form'])) { + // This may contain some realm options. + $options = isset($form['#variable_options']) ? $form['#variable_options'] : array(); + foreach ($form['#variable_edit_form'] as $name) { + $variable = variable_get_info($name); + if ($variable && isset($variable['submit callback'])) { + variable_include($variable); + $variable['submit callback']($variable, $options, $form, $form_state); + } + } } } diff --git a/sites/all/modules/contrib/dev/variable/variable.info b/sites/all/modules/contrib/dev/variable/variable.info index d630da9c..dc842ac6 100644 --- a/sites/all/modules/contrib/dev/variable/variable.info +++ b/sites/all/modules/contrib/dev/variable/variable.info @@ -12,9 +12,9 @@ files[] = includes/taxonomy.variable.inc files[] = includes/translation.variable.inc files[] = includes/user.variable.inc files[] = variable.test -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/dev/variable/variable.module b/sites/all/modules/contrib/dev/variable/variable.module index 86e14c24..472bba70 100644 --- a/sites/all/modules/contrib/dev/variable/variable.module +++ b/sites/all/modules/contrib/dev/variable/variable.module @@ -415,16 +415,35 @@ function variable_hook_info() { * Form for variable list * * @param $list - * Variable name or list of variable names + * Variable name or list of variable names. + * @param $options + * Optional array with variable options. */ -function variable_edit_form($form, $form_state, $list, $options = array()) { - // Pass on the values on the form for further reference. - $form['#variable_edit_form'] = $list; - form_load_include($form_state, 'form.inc', 'variable'); +function variable_edit_form($form, &$form_state, $list, $options = array()) { + $list = is_array($list) ? $list : array($list); + $form = variable_base_form($form, $form_state, $list, $options); $form += variable_edit_subform($list, $options); return variable_settings_form($form, $options); } +/** + * Build base form for variable list without fields. + * + * @param $list + * List of variable names. + * @param $options + * Optional array with variable options. + */ +function variable_base_form($form, &$form_state, $list, $options = array()) { + form_load_include($form_state, 'form.inc', 'variable'); + // Pass on the values on the form for further reference. + $form['#variable_edit_form'] = $list; + $form['#variable_options'] = $options; + // Run submit callback for variables in form. + $form['#submit'][] = 'variable_form_submit_callback'; + return $form; +} + /** * Form elements for variable list. * @@ -682,7 +701,23 @@ function variable_form_alter(&$form, &$form_state, $form_id) { } } +/** + * Implement validate callback. + * + * This needs to be in the module as it may be needed by form ajax callbacks. + */ +function variable_form_element_validate($element, &$form_state, $form) { + $options = isset($form['#variable_options']) ? $form['#variable_options'] : array(); + $variable = $element['#variable']; + variable_include($variable); + $variable['value'] = isset($element['#value']) ? $element['#value'] : NULL; + $error = $variable['validate callback']($variable, $options, $element, $form, $form_state); + + if ($error) { + form_error($element, $error); + } +} /** * Implements hook_module_implements_alter(). @@ -765,6 +800,7 @@ function variable_settings_form_submit($form, &$form_state) { form_state_values_clean($form_state); // This may contain some realm options. $options = isset($form['#variable_options']) ? $form['#variable_options'] : array(); + // Now run regular settings submission but using variable_set_value() foreach ($form_state['values'] as $key => $value) { if (is_array($value) && isset($form_state['values']['array_filter'])) { diff --git a/sites/all/modules/contrib/dev/variable/variable.variable.inc b/sites/all/modules/contrib/dev/variable/variable.variable.inc index d03679ec..e07dc933 100644 --- a/sites/all/modules/contrib/dev/variable/variable.variable.inc +++ b/sites/all/modules/contrib/dev/variable/variable.variable.inc @@ -376,7 +376,10 @@ function variable_format_multiple($variable, $options = array()) { * Validate numeric variable. */ function variable_validate_number($variable) { - if (!is_numeric($variable['value'])) { + if (empty($variable['required']) && empty($variable['value'])) { + return; + } + elseif (!is_numeric($variable['value'])) { return t('The value is not a number.'); } } diff --git a/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.info b/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.info index 2396d6ed..2279ed5a 100644 --- a/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.info +++ b/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.info @@ -3,9 +3,9 @@ description = Variable Administration UI dependencies[] = variable package = Variable core = 7.x -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.module b/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.module index fd602b6d..4bed3004 100644 --- a/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.module +++ b/sites/all/modules/contrib/dev/variable/variable_admin/variable_admin.module @@ -105,5 +105,3 @@ function variable_admin_realm_title($realm) { $info = variable_realm_info($realm); return isset($info['title']) ? $info['title'] : $realm; } - - diff --git a/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.info b/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.info deleted file mode 100644 index d5b04c94..00000000 --- a/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.info +++ /dev/null @@ -1,11 +0,0 @@ -name = Variable advanced -description = Provides access to advanced low level variables. By using this you will be able to break your site badly. -dependencies[] = variable -package = Variable -core = 7.x -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" -core = "7.x" -project = "variable" -datestamp = "1376034993" - diff --git a/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.module b/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.module deleted file mode 100644 index 1ec12756..00000000 --- a/sites/all/modules/contrib/dev/variable/variable_advanced/variable_advanced.module +++ /dev/null @@ -1,5 +0,0 @@ - t('Advanced options'), - 'description' => t('Advanced settings not usually exposed. Changing these variables may seriously break your site so make sure you know what you do.'), - ); - return $groups; -} - -/** - * Implements hook_variable_info(). - */ -function variable_advanced_variable_info($options) { - // Bootstrap caching options - $variables['page_cache_invoke_hooks'] = array( - 'title' => t('Cache invoke hooks'), - 'type' => 'enable', - 'default' => 1, - 'group' => 'advanced', - 'description' => T('Invoke boot and exit hooks when the page is served from cache.'), - ); - $variables['actions_max_stack'] = array( - 'title' => t('Actions recursion level'), - 'type' => 'number', - 'default' => 35, - 'group' => 'advanced', - 'description' => t('Maximum recursion level for actions before the execution is aborted.', array(), $options), - ); - // Bootstrap language variables. - $variables['language_count'] = array( - 'title' => t('Language count'), - 'type' => 'number', - 'default' => 1, - 'group' => 'advanced', - 'description' => t('Number of enabled languages, used for quick bootstrap. Not to be changed manually.', array(), $options), - ); - $variables['language_types'] = array( - 'title' => t('Language types'), - 'type' => 'array', - 'default callback' => 'drupal_language_types', - 'group' => 'advanced', - 'description' => t('Available language types.'), - ); - // Bootstrap proxy configuration - $variables['reverse_proxy'] = array( - 'title' => t('Reverse proxy'), - 'type' => 'enable', - 'default' => 0, - 'group' => 'advanced', - 'description' => t('If Drupal is behind a reverse proxy, we use the X-Forwarded-For header instead of $_SERVER[\'REMOTE_ADDR\'], which would be the IP address of the proxy server, and not the client\'s. The actual header name can be configured by the reverse_proxy_header variable.', array(), $options), - ); - $variables['reverse_proxy_header'] = array( - 'title' => t('Reverse proxy header'), - 'default' => 'HTTP_X_FORWARDED_FOR', - 'group' => 'advanced', - ); - $variables['reverse_proxy_addresses'] = array( - 'title' => t('Reverse proxy addresses'), - 'type' => 'array', - 'group' => 'advanced', - 'default' => array(), - 'description' => t('If an array of known reverse proxy IPs is provided, then trust the XFF header if request really comes from one of them.', array(), $options), - ); - return $variables; -} diff --git a/sites/all/modules/contrib/dev/variable/variable_example/variable_example.info b/sites/all/modules/contrib/dev/variable/variable_example/variable_example.info index 583cc16f..36a4229f 100644 --- a/sites/all/modules/contrib/dev/variable/variable_example/variable_example.info +++ b/sites/all/modules/contrib/dev/variable/variable_example/variable_example.info @@ -6,9 +6,9 @@ package = Example modules core = 7.x files[] = variable_example.variable.inc -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.form.inc b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.form.inc index 32c7f784..191f79a7 100644 --- a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.form.inc +++ b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.form.inc @@ -86,7 +86,13 @@ function variable_realm_edit_variables_form($form, &$form_state, $realm_name, $r $form['realm_name'] = array('#type' => 'value', '#value' => $realm_name); $form['realm_key'] = array('#type' => 'value', '#value' => $realm_key); $options['realm'] = variable_realm($realm_name, $realm_key); + if ($variable_list = $controller->getEnabledVariables()) { + $form = variable_base_form($form, $form_state, $variable_list, $options); + // variable_base_form() adds its own submit handler overriding the default, + // so we need to add it as a explicit submit callback here. + $form['#submit'][] = 'variable_realm_edit_variables_form_submit'; + // Group variables by variable group for vertical tabls $group_list = array(); foreach ($variable_list as $variable_name) { diff --git a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.info b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.info index 00275eb7..4fe58ab3 100644 --- a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.info +++ b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.info @@ -8,9 +8,9 @@ version = 7.x-2.x files[] = variable_realm.class.inc files[] = variable_realm_union.class.inc -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.module b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.module index 174eaa7b..81d6f5cb 100644 --- a/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.module +++ b/sites/all/modules/contrib/dev/variable/variable_realm/variable_realm.module @@ -29,10 +29,10 @@ function variable_realm_boot() { * Implements hook_init() * * Let realms be overriden by query string parameters, but only for: - * - Admin paths (not variable admin pages) + * - Admin paths (not variable realm admin pages) */ function variable_realm_init() { - if (arg(0) == 'admin' && arg(3) != 'variable' && ($params = variable_realm_params()) && user_access('administer site configuration')) { + if (arg(0) == 'admin' && (arg(3) != 'variable' || arg(4) != 'realm') && ($params = variable_realm_params()) && user_access('administer site configuration')) { foreach ($params as $realm_name => $realm_key) { variable_realm_switch($realm_name, $realm_key, FALSE); } diff --git a/sites/all/modules/contrib/dev/variable/variable_store/variable_store.info b/sites/all/modules/contrib/dev/variable/variable_store/variable_store.info index f42e3059..12f55d22 100644 --- a/sites/all/modules/contrib/dev/variable/variable_store/variable_store.info +++ b/sites/all/modules/contrib/dev/variable/variable_store/variable_store.info @@ -8,9 +8,9 @@ version = 7.x-2.x files[] = variable_store.class.inc files[] = variable_store.test -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/dev/variable/variable_views/variable_views.info b/sites/all/modules/contrib/dev/variable/variable_views/variable_views.info index 9fe5dd84..ab58eb77 100644 --- a/sites/all/modules/contrib/dev/variable/variable_views/variable_views.info +++ b/sites/all/modules/contrib/dev/variable/variable_views/variable_views.info @@ -9,9 +9,9 @@ files[] = includes/views_plugin_argument_default_variable.inc files[] = includes/views_handler_field_variable_title.inc files[] = includes/views_handler_field_variable_value.inc -; Information added by drupal.org packaging script on 2013-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2014-04-23 +version = "7.x-2.5" core = "7.x" project = "variable" -datestamp = "1376034993" +datestamp = "1398250128" diff --git a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_display_export.inc b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_display_export.inc index 4c5103ac..a461566a 100644 --- a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_display_export.inc +++ b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_display_export.inc @@ -63,8 +63,12 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed $options = parent::option_definition(); $options['use_batch'] = array('default' => 'no_batch'); $options['items_per_page'] = array('default' => '0'); + $options['return_path'] = array('default' => ''); $options['style_plugin']['default'] = 'views_data_export_csv'; + // This is the default size of a segment when doing a batched export. + $options['segment_size']['default'] = 100; + if (isset($options['defaults']['default']['items_per_page'])) { $options['defaults']['default']['items_per_page'] = FALSE; } @@ -113,6 +117,27 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed 'batch' => t('Export data in small segments to build a complete export. Recommended for large exports sets (1000+ rows)'), ), ); + // Allow the administrator to configure the number of items exported per batch. + $form['segment_size'] = array( + '#type' => 'select', + '#title' => t('Segment size'), + '#description' => t('If each row of your export consumes a lot of memory to render, then reduce this value. Higher values will generally mean that the export completes in less time but will have a higher peak memory usage.'), + '#options' => drupal_map_assoc(range(1, 500)), + '#default_value' => $this->get_option('segment_size'), + '#process' => array('ctools_dependent_process'), + '#dependency' => array( + 'radio:use_batch' => array('batch') + ), + ); + $form['return_path'] = array( + '#title' => t('Return path'), + '#type' => 'textfield', + '#description' => t('Return path after the batched operation, leave empty for default. This path will only be used if the export URL is visited directly, and not by following a link when attached to another view display.'), + '#default_value' => $this->get_option('return_path'), + '#dependency' => array( + 'radio:use_batch' => array('batch') + ), + ); if (!$this->is_compatible()) { $form['use_batch']['#disabled'] = TRUE; $form['use_batch']['#default_value'] = 'no_batch'; @@ -123,9 +148,35 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed ); } break; + + case 'cache': + // We're basically going to disable using cache plugins, by disabling + // the UI. + if (isset($form['cache']['type']['#options'])) { + foreach ($form['cache']['type']['#options'] as $id => $v) { + if ($id != 'none') { + unset($form['cache']['type']['#options'][$id]); + } + $form['cache']['type']['#description'] = t("Views data export isn't currently compatible with caching plugins."); + } + } + break; + } } + function get_option($option) { + // Force people to never use caching with Views data export. Sorry folks, + // but it causes too many issues for our workflow. If you really want to add + // caching back, then you can subclass this display handler and override + // this method to add it back. + if ($option == 'cache') { + return array('type' => 'none'); + } + + return parent::get_option($option); + } + /** * Save the options from the options form. */ @@ -135,6 +186,8 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed switch ($form_state['section']) { case 'use_batch': $this->set_option('use_batch', $form_state['values']['use_batch']); + $this->set_option('segment_size', $form_state['values']['segment_size']); + $this->set_option('return_path', $form_state['values']['return_path']); break; } } @@ -253,17 +306,23 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed // Build up our querystring for the final page callback. $querystring = array( 'eid' => $this->batched_execution_state->eid, + 'return-url' => NULL, ); - // If we were attached to another view, grab that for the final URL. - if (!empty($_GET['attach']) && isset($this->view->display[$_GET['attach']])) { + + // If we have a configured return path, use that. + if ($this->get_option('return_path')) { + $querystring['return-url'] = $this->get_option('return_path'); + } + // Else if we were attached to another view, grab that for the final URL. + else if (!empty($_GET['attach']) && isset($this->view->display[$_GET['attach']])) { // Get the path of the attached display: - $querystring['return-url'] = $this->view->display[$_GET['attach']]->handler->get_path(); + $querystring['return-url'] = $this->view->get_url(NULL, $this->view->display[$_GET['attach']]->handler->get_path()); } //Set the batch off $batch = array( 'operations' => array ( - array('_views_data_export_batch_process', array($this->batched_execution_state->eid, $this->view->current_display)), + array('_views_data_export_batch_process', array($this->batched_execution_state->eid, $this->view->current_display, $this->view->get_exposed_input())), ), 'title' => t('Building export'), 'init_message' => t('Export is starting up.'), @@ -280,6 +339,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed // e.g. Drush to grab this batch and yet execute it in // it's own special way $batch['view_name'] = $this->view->name; + $batch['exposed_filters'] = $this->view->get_exposed_input(); $batch['display_id'] = $this->view->current_display; $batch['eid'] = $this->batched_execution_state->eid; $batch_redirect = array($final_destination, array('query' => $querystring)); @@ -433,7 +493,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed // Grab our results from the index, and push them into the view result. // TODO: Handle external databases. - $result = db_query_range('SELECT * FROM {' . $this->index_tablename() . '} ORDER BY ' . $this->batched_execution_state->sandbox['weight_field_alias'] . ' ASC', 0, 100); + $result = db_query_range('SELECT * FROM {' . $this->index_tablename() . '} ORDER BY ' . $this->batched_execution_state->sandbox['weight_field_alias'] . ' ASC', 0, $this->get_option('segment_size')); $this->view->result = array(); foreach ($result as $item_hashed) { $item = new stdClass(); @@ -493,7 +553,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed // Change the items per page. $this->view->set_items_per_page(20); // Force a pager to be used. - $this->set_option('pager', array('type' => 'some')); + $this->set_option('pager', array('type' => 'some', 'options' => array())); return '

' . t('A maximum of 20 items will be shown here, all results will be shown on export.') . '

' . check_plain($this->view->render()) . '
'; } return $this->view->render(); @@ -531,7 +591,16 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed $view->build(); // Change the query object to use our custom one. - $query = new views_data_export_plugin_query_default_batched(); + switch ($this->_get_database_driver()) { + case 'pgsql': + $query_class = 'views_data_export_plugin_query_pgsql_batched'; + break; + + default: + $query_class = 'views_data_export_plugin_query_default_batched'; + break; + } + $query = new $query_class(); // Copy the query over: foreach ($view->query as $property => $value) { $query->$property = $value; @@ -600,9 +669,14 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed * Get the output file path. */ function outputfile_path() { - if (empty($this->_output_file) && !empty($this->batched_execution_state->fid)) { - // Return the filename associated with this file. - $this->_output_file = $this->file_load($this->batched_execution_state->fid); + if (empty($this->_output_file)) { + if (!empty($this->batched_execution_state->fid)) { + // Return the filename associated with this file. + $this->_output_file = $this->file_load($this->batched_execution_state->fid); + } + else { + return NULL; + } } return $this->_output_file->uri; } @@ -614,7 +688,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed */ protected function outputfile_create() { - $dir = 'temporary://views_plugin_display'; + $dir = variable_get('views_data_export_directory', 'temporary://views_plugin_display'); // Make sure the directory exists first. if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { @@ -675,7 +749,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed * An array containing the file information, or 0 in the event of an error. */ function file_save_file($filepath) { - return file_save_data('', $filepath); + return file_save_data('', $filepath, FILE_EXISTS_REPLACE); } /** @@ -704,7 +778,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed */ function is_compatible() { $incompatible_drivers = array ( - 'pgsql', + //'pgsql', ); $db_driver = $this->_get_database_driver(); return !in_array($db_driver, $incompatible_drivers); @@ -713,7 +787,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed function _get_database_driver() { $name = !empty($this->view->base_database) ? $this->view->base_database : 'default'; $conn_info = Database::getConnectionInfo($name); - return $conn_info[$name]['driver']; + return $conn_info['default']['driver']; } } @@ -808,6 +882,123 @@ class views_data_export_plugin_query_default_batched extends views_plugin_query_ db_query($insert_query, $args); + $view->result = array(); + + $this->pager->post_execute($view->result); + + if ($this->pager->use_pager()) { + $view->total_rows = $this->pager->get_total_items(); + } + + // Now create an index for the weight field, otherwise the queries on the + // index will take a long time to execute. + db_add_unique_key($display_handler->index_tablename(), $display_handler->batched_execution_state->sandbox['weight_field_alias'], array($display_handler->batched_execution_state->sandbox['weight_field_alias'])); + } + catch (Exception $e) { + $view->result = array(); + debug('Exception: ' . $e->getMessage()); + } + + } + $view->execute_time = microtime(TRUE) - $start; + } +} + +class views_data_export_plugin_query_pgsql_batched extends views_data_export_plugin_query_default_batched { + + + /** + * Executes the query and fills the associated view object with according + * values. + * + * Values to set: $view->result, $view->total_rows, $view->execute_time, + * $view->current_page. + */ + function execute(&$view) { + $display_handler = &$view->display_handler; + $external = FALSE; // Whether this query will run against an external database. + $query = $view->build_info['query']; + $count_query = $view->build_info['count_query']; + + $query->addMetaData('view', $view); + $count_query->addMetaData('view', $view); + + if (empty($this->options['disable_sql_rewrite'])) { + $base_table_data = views_fetch_data($this->base_table); + if (isset($base_table_data['table']['base']['access query tag'])) { + $access_tag = $base_table_data['table']['base']['access query tag']; + $query->addTag($access_tag); + $count_query->addTag($access_tag); + } + } + + $items = array(); + if ($query) { + $additional_arguments = module_invoke_all('views_query_substitutions', $view); + + // Count queries must be run through the preExecute() method. + // If not, then hook_query_node_access_alter() may munge the count by + // adding a distinct against an empty query string + // (e.g. COUNT DISTINCT(1) ...) and no pager will return. + // See pager.inc > PagerDefault::execute() + // http://api.drupal.org/api/drupal/includes--pager.inc/function/PagerDefault::execute/7 + // See http://drupal.org/node/1046170. + $count_query->preExecute(); + + // Build the count query. + $count_query = $count_query->countQuery(); + + // Add additional arguments as a fake condition. + // XXX: this doesn't work... because PDO mandates that all bound arguments + // are used on the query. TODO: Find a better way to do this. + if (!empty($additional_arguments)) { + // $query->where('1 = 1', $additional_arguments); + // $count_query->where('1 = 1', $additional_arguments); + } + + $start = microtime(TRUE); + + if ($this->pager->use_count_query() || !empty($view->get_total_rows)) { + $this->pager->execute_count_query($count_query); + } + + // Let the pager modify the query to add limits. + $this->pager->pre_execute($query); + + if (!empty($this->limit) || !empty($this->offset)) { + // We can't have an offset without a limit, so provide a very large limit instead. + $limit = intval(!empty($this->limit) ? $this->limit : 999999); + $offset = intval(!empty($this->offset) ? $this->offset : 0); + $query->range($offset, $limit); + } + + try { + // The $query is final and ready to go, we are going to redirect it to + // become an insert into our table, sneaky! + // Our query will look like: + // CREATE TABLE {idx} SELECT @row := @row + 1 AS weight_alias, cl.* FROM + // (-query-) AS cl, (SELECT @row := 0) AS r + // We do some magic to get the row count. + + $display_handler->batched_execution_state->sandbox['weight_field_alias'] = $display_handler->_weight_alias_create($view); + + $display_handler->batched_execution_state->sandbox['field_aliases'] = $display_handler->field_aliases_create($view); + $select_aliases = array(); + foreach ($display_handler->batched_execution_state->sandbox['field_aliases'] as $hash => $alias) { + $select_aliases[] = "cl.$alias AS $hash"; + } + + // TODO: this could probably be replaced with a query extender and new query type. + $query->preExecute(); + $args = $query->getArguments(); + // Create temporary sequence + $seq_name = $display_handler->index_tablename() . '_seq'; + db_query('CREATE TEMP sequence ' . $seq_name); + // Query uses sequence to create row number + $insert_query = 'CREATE TABLE {' . $display_handler->index_tablename() . "} AS SELECT nextval('". $seq_name . "') AS " . $display_handler->batched_execution_state->sandbox['weight_field_alias'] . ', ' . implode(', ', $select_aliases) . ' FROM (' . (string)$query . ') AS cl'; + db_query($insert_query, $args); + + $view->result = array(); $this->pager->post_execute($view->result); diff --git a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export.inc b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export.inc index 934fb48c..493796f6 100644 --- a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export.inc +++ b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export.inc @@ -149,29 +149,33 @@ class views_data_export_plugin_style_export extends views_plugin_style { * feed image link. */ function attach_to($display_id, $path, $title) { - - $type = $this->definition['export feed type']; - $theme_pattern = array( - 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id . '__' . $type, - 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id, - 'views_data_export_feed_icon__' . $this->view->name . '__' . $type, - 'views_data_export_feed_icon__' . $display_id . '__' . $type, - 'views_data_export_feed_icon__' . $display_id, - 'views_data_export_feed_icon__' . $type, - 'views_data_export_feed_icon', - ); - $query = $this->view->get_exposed_input(); - // Stash the display id we're coming form in the url so we can hijack it later. - if ($this->options['parent_sort']) { - $query['attach'] = $display_id; + if ($this->display->handler->access()) { + $type = $this->definition['export feed type']; + $theme_pattern = array( + 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id . '__' . $type, + 'views_data_export_feed_icon__' . $this->view->name . '__' . $display_id, + 'views_data_export_feed_icon__' . $this->view->name . '__' . $type, + 'views_data_export_feed_icon__' . $display_id . '__' . $type, + 'views_data_export_feed_icon__' . $display_id, + 'views_data_export_feed_icon__' . $type, + 'views_data_export_feed_icon', + ); + $query = $this->view->get_exposed_input(); + // Stash the display id we're coming form in the url so we can hijack it later. + if ($this->options['parent_sort']) { + $query['attach'] = $display_id; + } + if (!isset($this->view->feed_icon)) { + $this->view->feed_icon = ''; + } + $this->view->feed_icon .= theme($theme_pattern, array( + 'image_path' => $this->definition['export feed icon'], + 'url' => $this->view->get_url(NULL, $path), + 'query' => $query, + 'text' => $this->options['attach_text'], + ) + ); } - $this->view->feed_icon .= theme($theme_pattern, array( - 'image_path' => $this->definition['export feed icon'], - 'url' => $this->view->get_url(NULL, $path), - 'query' => $query, - 'text' => $this->options['attach_text'], - ) - ); } function build_sort() { @@ -291,7 +295,6 @@ class views_data_export_plugin_style_export extends views_plugin_style { * Add any HTTP headers that this style plugin wants to. */ function add_http_headers() { - $view = &$this->view; drupal_add_http_header('Cache-Control', 'max-age=60, must-revalidate'); @@ -301,6 +304,22 @@ class views_data_export_plugin_style_export extends views_plugin_style { } } + if (isset($this->options['filename']) && !empty($this->options['provide_file'])) { + $filename = $this->generate_filename(); + + if ($filename) { + drupal_add_http_header('Content-Disposition', 'attachment; filename="'. $filename .'"'); + } + } + } + + /** + * Generate the filename for the export. + */ + function generate_filename() { + $view = $this->view; + $filename = ''; + if (isset($this->options['filename']) && !empty($this->options['provide_file'])) { // General tokens. $tokens = array( @@ -311,7 +330,7 @@ class views_data_export_plugin_style_export extends views_plugin_style { $count = 0; foreach ($view->display_handler->get_handlers('argument') as $arg => $handler) { $token = '%' . ++$count; - $tokens[$token . '-title'] = check_plain($handler->title()); + $tokens[$token . '-title'] = $handler->get_title(); $tokens[$token . '-value'] = isset($view->args[$count - 1]) ? check_plain($view->args[$count - 1]) : ''; } @@ -322,7 +341,14 @@ class views_data_export_plugin_style_export extends views_plugin_style { continue; } if (!empty($view->exposed_input[$handler->options['expose']['identifier']])) { - $exposed[] = check_plain($handler->options['expose']['identifier']) . '_' . check_plain($view->exposed_input[$handler->options['expose']['identifier']]); + $identifier = $handler->options['expose']['identifier']; + $option = $view->exposed_input[$identifier]; + // The option may be a string or an array, depending on whether the + // widget is a text box/area or a select box. + if (is_array($option)) { + $option = implode('--', $option); + } + $exposed[] = check_plain($identifier) . '_' . check_plain($option); } } if (!empty($exposed)) { @@ -351,11 +377,8 @@ class views_data_export_plugin_style_export extends views_plugin_style { } $filename = strtr($this->options['filename'], $tokens); - - - if ($filename) { - drupal_add_http_header('Content-Disposition', 'attachment; filename="'. $filename .'"'); - } } + + return $filename; } } diff --git a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_csv.inc b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_csv.inc index 85a8e0db..daebeafd 100644 --- a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_csv.inc +++ b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_csv.inc @@ -44,12 +44,15 @@ class views_data_export_plugin_style_export_csv extends views_data_export_plugin 'default' => TRUE, 'translatable' => FALSE, ); + $options['keep_html'] = array( + 'default' => FALSE, + 'translatable' => FALSE, + ); $options['encoding'] = array( 'default' => '', 'translatable' => FALSE, ); - return $options; } @@ -93,7 +96,7 @@ class views_data_export_plugin_style_export_csv extends views_data_export_plugin '#type' => 'textfield', '#title' => t('Replacement'), '#default_value' => $this->options['newline_replacement'], - '#process' => array('form_process_checkboxes', 'ctools_dependent_process'), + '#process' => array('ctools_dependent_process'), '#dependency' => array('edit-style-options-replace-newlines' => array(TRUE)), ); $form['header'] = array( @@ -101,15 +104,17 @@ class views_data_export_plugin_style_export_csv extends views_data_export_plugin '#title' => t('Make first row a list of column headers.'), '#default_value' => !empty($this->options['header']), ); + $form['keep_html'] = array( + '#type' => 'checkbox', + '#default_value' => !empty($this->options['keep_html']), + '#title' => t('Keep HTML tags.'), + ); $form['encoding'] = array( - '#type' => 'select', + '#type' => 'textfield', '#default_value' => !empty($this->options['encoding']) ? $this->options['encoding'] : '', '#title' => t('Character encoding conversion'), - '#options' => array ( - '' => t('No conversion'), - 'ASCII' => t('ASCII'), - ), - '#description' => t('Optionally specify a character conversion that some CSV file readers need. Note, using an external tool is always preferred and you should only use this option as a last resort. This feature requires the "iconv" PHP extension.'), + '#description' => t('Optionally specify a character conversion that some CSV file readers need. Use "utf8_decode" for ISO-8859-1 via utf8_decode PHP function, other values will be passed iconv (this requires the iconv PHP extension), empty or illegal values will leave the output as UTF-8.', + array('@iconv' => 'http://www.php.net/manual/en/function.iconv.php', '@utf8_decode' => 'http://www.php.net/manual/en/function.utf8-decode.php')), ); } } diff --git a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_xml.inc b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_xml.inc index 8e6d7907..f01f65c4 100644 --- a/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_xml.inc +++ b/sites/all/modules/contrib/views/views_data_export/plugins/views_data_export_plugin_style_export_xml.inc @@ -11,6 +11,26 @@ */ class views_data_export_plugin_style_export_xml extends views_data_export_plugin_style_export { + /** + * Initialize a style plugin. + */ + function init(&$view, &$display, $options = NULL) { + // View is not set in option_definition(), so we fill defaults here if + // options are empty. + if (empty($options['root_node']) || empty($options['item_node'])) { + $base_object_name = rtrim($view->base_table, 's'); + + if (empty($options['root_node'])) { + $options['root_node'] = $base_object_name . 's'; + } + if (empty($options['item_node'])) { + $options['item_node'] = $base_object_name; + } + } + + parent::init($view, $display, $options); + } + /** * Set options fields and default values. * @@ -28,6 +48,22 @@ class views_data_export_plugin_style_export_xml extends views_data_export_plugin 'default' => 'dash', 'translatable' => FALSE, ); + $options['root_node'] = array( + 'default' => '', + 'translatable' => FALSE, + ); + $options['item_node'] = array( + 'default' => '', + 'translatable' => FALSE, + ); + $options['no_entity_encode'] = array( + 'default' => array(), + 'translatable' => FALSE, + ); + $options['cdata_wrapper'] = array( + 'default' => array(), + 'translatable' => FALSE, + ); return $options; } @@ -66,5 +102,68 @@ class views_data_export_plugin_style_export_xml extends views_data_export_plugin 'edit-style-options-transform' => array(TRUE), ), ); + $form['root_node'] = array( + '#type' => 'textfield', + '#title' => t('Root node'), + '#default_value' => $this->options['root_node'], + '#description' => t('The XML tag for the root node.'), + ); + $form['item_node'] = array( + '#type' => 'textfield', + '#title' => t('Item node'), + '#default_value' => $this->options['item_node'], + '#description' => t('The XML tag for an item node.'), + ); + + $field_labels = $this->display->handler->get_field_labels(); + + if (!empty($field_labels)) { + $options = $field_labels; + if (empty($this->options['no_entity_encode'])) { + $this->options['no_entity_encode'] = array(); + } + + $form['no_entity_encode'] = array( + '#type' => 'checkboxes', + '#title' => t('Disable encoding of XML entities for these fields'), + '#options' => $options, + '#default_value' => $this->options['no_entity_encode'], + '#description' => t('If checked field contents will be outputted '. + 'without encoding of XML entities. This is '. + 'useful when when used in conjunction with a field '. + 'formatter that outputs properly formatted and '. + 'encoded XML data.'), + ); + + if (empty($this->options['cdata_wrapper'])) { + $this->options['cdata_wrapper'] = array(); + } + + $form['cdata_wrapper'] = array( + '#type' => 'checkboxes', + '#title' => t('Fields value to wrapped using CDATA'), + '#options' => $options, + '#default_value' => $this->options['cdata_wrapper'], + '#description' => t('If checked the fields content will be wrapped using the CDATA tag.'), + ); + } + } + + /** + * Perform any necessary changes to the form values prior to storage. + * There is no need for this function to actually store the data. + * + * @param $form + * @param $form_state + */ + function options_submit(&$form, &$form_state) { + if (isset($form_state['values']['style_options']['no_entity_encode'])) { + // Remove any options values set to 0 + $form_state['values']['style_options']['no_entity_encode'] = array_filter($form_state['values']['style_options']['no_entity_encode']); + } + if (isset($form_state['values']['style_options']['cdata_wrapper'])) { + // Remove any options values set to 0 + $form_state['values']['style_options']['cdata_wrapper'] = array_filter($form_state['values']['style_options']['cdata_wrapper']); + } } } diff --git a/sites/all/modules/contrib/views/views_data_export/theme/views_data_export.theme.inc b/sites/all/modules/contrib/views/views_data_export/theme/views_data_export.theme.inc index 1a4f7d3b..8416d96e 100644 --- a/sites/all/modules/contrib/views/views_data_export/theme/views_data_export.theme.inc +++ b/sites/all/modules/contrib/views/views_data_export/theme/views_data_export.theme.inc @@ -41,7 +41,7 @@ function theme_views_data_export_message($var) { */ function theme_views_data_export_feed_icon($variables) { extract($variables, EXTR_SKIP); - $url_options = array('html' => true); + $url_options = array('html' => TRUE); if ($query) { $url_options['query'] = $query; } @@ -58,7 +58,7 @@ function theme_views_data_export_feed_icon($variables) { function theme_views_data_export_complete_page($variables) { extract($variables, EXTR_SKIP); drupal_set_title(t('Data export successful')); - drupal_add_html_head(array('#tag' => 'meta', '#attributes' => array('http-equiv' =>"refresh", 'content' => '3;url='. $file)), 'views_data_export_download'); + drupal_add_html_head(array('#tag' => 'meta', '#attributes' => array('http-equiv' =>"Refresh", 'content' => '3;url='. $file)), 'views_data_export_download'); $output = ''; $output .= '

'; $output .= t('Your export has been created. View/download the file here (will automatically download in 3 seconds.)', array('@link' => $file)); @@ -105,21 +105,24 @@ function template_preprocess_views_data_export_csv_header(&$vars) { // Format header values. foreach ($vars['header'] as $key => $value) { - $output = decode_entities(strip_tags($value)); + $output = decode_entities($value); + $output = (empty($vars['options']['keep_html'])) ? strip_tags($output) : $output; if (!empty($vars['options']['trim'])) { $output = trim($output); } if (!empty($vars['options']['encoding']) && function_exists('iconv')) { - switch($vars['options']['encoding']) { - case 'ASCII': - $converted = iconv("UTF-8", "ASCII//TRANSLIT", $output); - if ($converted !== FALSE) { - $output = $converted; - } - break; - } + switch($vars['options']['encoding']) { + case 'utf8_decode': + $converted = utf8_decode($output); + break; + default: + $converted = iconv("UTF-8", $vars['options']['encoding'], $output); + break; } - + if ($converted !== FALSE) { + $output = $converted; + } + } $vars['header'][$key] = $wrap . str_replace('"', $replace_value, $output) . $wrap; } } @@ -148,19 +151,23 @@ function template_preprocess_views_data_export_csv_body(&$vars) { // Format row values. foreach ($vars['themed_rows'] as $i => $values) { foreach ($values as $j => $value) { - $output = decode_entities(strip_tags($value)); + $output = decode_entities($value); + $output = (empty($vars['options']['keep_html'])) ? strip_tags($output) : $output; if (!empty($vars['options']['trim'])) { $output = trim($output); } if (!empty($vars['options']['encoding']) && function_exists('iconv')) { switch($vars['options']['encoding']) { - case 'ASCII': - $converted = iconv("UTF-8", "ASCII//TRANSLIT", $output); - if ($converted !== FALSE) { - $output = $converted; - } + case 'utf8_decode': + $converted = utf8_decode($output); break; + default: + $converted = iconv("UTF-8", $vars['options']['encoding'], $output); + break; + } + if ($converted !== FALSE) { + $output = $converted; } } if (!empty($vars['options']['replace_newlines'])) { @@ -242,6 +249,8 @@ function template_preprocess_views_data_export_csv(&$vars) { */ function template_preprocess_views_data_export_txt_body(&$vars) { _views_data_export_header_shared_preprocess($vars); + // We support not outputting fields when they are empty, so indicate so. + $vars['hide_empty_support'] = TRUE; _views_data_export_body_shared_preprocess($vars); } @@ -346,24 +355,14 @@ function template_preprocess_views_data_export_msoffice_header(&$vars) { * Preprocess xml output template. */ function template_preprocess_views_data_export_xml_header(&$vars) { - // Compute the root XML node, using the base table, and appending an 's' if needed. - $root_node = $vars['view']->base_table; - if (rtrim($root_node, 's') == $root_node) { - $root_node .= 's'; - } - $vars['root_node'] = _views_data_export_xml_tag_clean($root_node); + $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']); } /** * Preprocess xml output template. */ function template_preprocess_views_data_export_xml_footer(&$vars) { - // Compute the root XML node, using the base table, and appending an 's' if needed. - $root_node = $vars['view']->base_table; - if (rtrim($root_node, 's') == $root_node) { - $root_node .= 's'; - } - $vars['root_node'] = _views_data_export_xml_tag_clean($root_node); + $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']); } /** @@ -371,27 +370,50 @@ function template_preprocess_views_data_export_xml_footer(&$vars) { */ function template_preprocess_views_data_export_xml_body(&$vars) { _views_data_export_header_shared_preprocess($vars); + // We support not outputting fields when they are empty, so indicate so. + $vars['hide_empty_support'] = TRUE; _views_data_export_body_shared_preprocess($vars); - // Compute the tag name based on the views base table, minus any trailing 's'. - $vars['item_node'] = _views_data_export_xml_tag_clean(rtrim($vars['view']->base_table, 's')); + $view = $vars['view']; + $style_options = $view->display_handler->get_option('style_options'); + + $no_encode = isset($style_options['no_entity_encode']) ? $style_options['no_entity_encode'] : array(); + + $cdata_wrapper = isset($style_options['cdata_wrapper']) ? $style_options['cdata_wrapper'] : array(); + + $vars['item_node'] = _views_data_export_xml_tag_clean($vars['options']['item_node']); foreach ($vars['themed_rows'] as $num => $row) { foreach ($row as $field => $content) { - // Prevent double encoding of the ampersand. Look for the entities produced by check_plain(). - $content = preg_replace('/&(?!(amp|quot|#039|lt|gt);)/', '&', $content); - // Convert < and > to HTML entities. - $content = str_replace( - array('<', '>'), - array('<', '>'), - $content); + + // Perform xml entity encoding unless excluded by style options. + if (empty($no_encode[$field]) && empty($cdata_wrapper[$field])) { + + // Prevent double encoding of the ampersand. Look for the entities produced by check_plain(). + $content = preg_replace('/&(?!(amp|quot|#039|lt|gt);)/', '&', $content); + // Convert < and > to HTML entities. + $content = str_replace( + array('<', '>'), + array('<', '>'), + $content); + } + + // Perform wrapping the field data using the CDATA tag + // unless excluded by style options. + if (!empty($cdata_wrapper[$field])) { + // Escape CDATA end sequence only. + $content = '', ']]]]>', $content) . ']]>'; + } + $vars['themed_rows'][$num][$field] = $content; } } foreach ($vars['header'] as $field => $header) { // If there is no field label, use 'no name'. - $vars['xml_tag'][$field] = !empty($header) ? $header : 'no name'; + if (empty($header)) { + $header = 'no name'; + } if ($vars['options']['transform']) { switch ($vars['options']['transform_type']) { case 'dash': @@ -438,6 +460,12 @@ function _views_data_export_xml_tag_clean($tag) { // Need to trim invalid characters from the start of the string: $tag = ltrim($tag, $invalid_start_chars); + // As a last line of defense, if we've stripped out everything, set it to + // something. + if (empty($tag)) { + $tag = 'invalid-tag-name'; + } + return $tag; } @@ -463,6 +491,7 @@ function _views_data_export_header_shared_preprocess(&$vars) { function _views_data_export_body_shared_preprocess(&$vars) { $view = $vars['view']; $fields = &$view->field; + $hide_empty_support = !empty($vars['hide_empty_support']); $rows = $vars['rows']; @@ -473,7 +502,15 @@ function _views_data_export_body_shared_preprocess(&$vars) { foreach ($keys as $id) { if (empty($fields[$id]->options['exclude'])) { - $vars['themed_rows'][$num][$id] = $view->style_plugin->rendered_fields[$num][$id]; + $content = $view->style_plugin->rendered_fields[$num][$id]; + + if ($hide_empty_support && !empty($fields[$id]->options['hide_empty'])) { + if ($fields[$id]->is_value_empty($content, $fields[$id]->options['empty_zero'])) { + continue; + } + } + + $vars['themed_rows'][$num][$id] = $content; } } } diff --git a/sites/all/modules/contrib/views/views_data_export/views_data_export.drush.inc b/sites/all/modules/contrib/views/views_data_export/views_data_export.drush.inc index 0a7d263a..ce99aa5d 100644 --- a/sites/all/modules/contrib/views/views_data_export/views_data_export.drush.inc +++ b/sites/all/modules/contrib/views/views_data_export/views_data_export.drush.inc @@ -17,6 +17,7 @@ function views_data_export_drush_command() { 'output_file' => 'The file to write the results to - will be overwritten if it already exists', ), 'options' => array ( + '--arguments' => 'Comma separated list of arguments to be passed to the view.', '--format' => 'csv,doc,txt,xls or xml. These options are ignored if the display_id passed is a "views_data_export" display.', '--separator' => 'csv only: What character separates the fields (default:,)', '--trim-whitespace' => 'csv only: Trim whitespace from either side of fields (default:1)', @@ -111,7 +112,7 @@ function drush_views_data_export($view_name, $display_id, $output_file) { return; } $already_run = TRUE; - + // Set the display to the one that we computed earlier. $display_id = drush_get_option('views_data_export_display_id', 'default'); @@ -158,11 +159,42 @@ function drush_views_data_export($view_name, $display_id, $output_file) { // We execute the view normally, and take advantage // of an alter function to interject later and batch it ourselves - $options = array ( - 'output_file' => realpath(drush_get_context('DRUSH_OLDCWD', getcwd())) . '/' . $output_file, - ); - _drush_views_data_export_override_batch($view_name, $display_id, $options); - $view->execute_display($display_id); + $options = array(); + // Let's see if the given $output_file is a absolute path. + if (strpos($output_file, '/') === 0) { + $options['output_file'] = $output_file; + } + else { + $options['output_file'] = realpath(drush_get_context('DRUSH_OLDCWD', getcwd())) . '/' . $output_file; + } + + + if ($view->display_handler->is_batched()) { + // This is a batched export, and needs to be handled as such. + _drush_views_data_export_override_batch($view_name, $display_id, $options); + + $arguments = drush_get_option('arguments', ''); + $arguments = explode(',', $arguments); + $view->execute_display($display_id, $arguments); + } + else { + // This export isn't batched. + ob_start(); + $view->execute_display($display_id); + // Get the results, and clean the output buffer. + $result = ob_get_contents(); + // Clean the buffer. + ob_end_clean(); + // Save the results to file. + // Copy file over + if (file_put_contents($options['output_file'], $result)) { + drush_log("Data export saved to " . $options['output_file'], 'success'); + } + else { + drush_set_error('VIEWS_DATA_EXPORT_COPY_ERROR', dt("The file could not be copied to the selected destination")); + } + } + } diff --git a/sites/all/modules/contrib/views/views_data_export/views_data_export.info b/sites/all/modules/contrib/views/views_data_export/views_data_export.info index c676faff..478b4fb8 100644 --- a/sites/all/modules/contrib/views/views_data_export/views_data_export.info +++ b/sites/all/modules/contrib/views/views_data_export/views_data_export.info @@ -4,40 +4,25 @@ description = "Plugin to export views data into various file formats" package = Views core = 7.x -files[] = views_data_export.module dependencies[] = views ; Plugins files[] = plugins/views_data_export_plugin_display_export.inc files[] = plugins/views_data_export_plugin_style_export.inc files[] = plugins/views_data_export_plugin_style_export_csv.inc -files[] = plugins/views_data_export_plugin_style_export_doc.inc -files[] = plugins/views_data_export_plugin_style_export_txt.inc -files[] = plugins/views_data_export_plugin_style_export_xls.inc files[] = plugins/views_data_export_plugin_style_export_xml.inc -; Theme -files[] = theme/views_data_export.theme.inc -files[] = theme/views-data-export-csv-body.tpl.php -files[] = theme/views-data-export-csv-footer.tpl.php -files[] = theme/views-data-export-csv-header.tpl.php -files[] = theme/views-data-export-doc-body.tpl.php -files[] = theme/views-data-export-doc-footer.tpl.php -files[] = theme/views-data-export-doc-header.tpl.php -files[] = theme/views-data-export-txt-body.tpl.php -files[] = theme/views-data-export-txt-footer.tpl.php -files[] = theme/views-data-export-txt-header.tpl.php -files[] = theme/views-data-export-xls-body.tpl.php -files[] = theme/views-data-export-xls-footer.tpl.php -files[] = theme/views-data-export-xls-header.tpl.php -files[] = theme/views-data-export-xml-body.tpl.php -files[] = theme/views-data-export-xml-footer.tpl.php -files[] = theme/views-data-export-xml-header.tpl.php -files[] = theme/views-data-export.tpl.php +; Tests +files[] = "tests/base.test" +files[] = "tests/csv_export.test" +files[] = "tests/doc_export.test" +files[] = "tests/txt_export.test" +files[] = "tests/xls_export.test" +files[] = "tests/xml_export.test" -; Information added by drupal.org packaging script on 2012-05-10 -version = "7.x-3.0-beta6" +; Information added by Drupal.org packaging script on 2014-08-27 +version = "7.x-3.0-beta8" core = "7.x" project = "views_data_export" -datestamp = "1336632688" +datestamp = "1409118835" diff --git a/sites/all/modules/contrib/views/views_data_export/views_data_export.install b/sites/all/modules/contrib/views/views_data_export/views_data_export.install index d3bee9c0..9bd0dd10 100644 --- a/sites/all/modules/contrib/views/views_data_export/views_data_export.install +++ b/sites/all/modules/contrib/views/views_data_export/views_data_export.install @@ -17,14 +17,14 @@ function views_data_export_schema() { ), 'view_name' => array( 'type' => 'varchar', - 'length' => '32', + 'length' => '128', 'default' => '', 'not null' => TRUE, 'description' => 'The unique name of the view. This is the primary field views are loaded from, and is used so that views may be internal and not necessarily in the database. May only be alphanumeric characters plus underscores.', ), 'view_display_id' => array( 'type' => 'varchar', - 'length' => '32', + 'length' => '64', 'default' => '', 'not null' => TRUE, 'description' => 'The unique name of the view. This is the primary field views are loaded from, and is used so that views may be internal and not necessarily in the database. May only be alphanumeric characters plus underscores.', @@ -75,7 +75,7 @@ function views_data_export_schema() { 'description' => 'The time this cache was created or updated.', ), 'data' => array( - 'type' => 'text', + 'type' => 'blob', 'size' => 'big', 'description' => 'Serialized data being stored.', 'serialize' => TRUE, @@ -115,6 +115,47 @@ function views_data_export_update_7100() { db_add_field('views_data_export_object_cache', 'data', $new_field); } +/** + * Increase the length of the view_name field to match views_schema_7301(). + */ +function views_data_export_update_7300() { + $fields = array(); + + $fields['view_name'] = array( + 'type' => 'varchar', + 'length' => '128', + 'default' => '', + 'not null' => TRUE, + 'description' => 'The unique name of the view. This is the primary field views are loaded from, and is used so that views may be internal and not necessarily in the database. May only be alphanumeric characters plus underscores.', + ); + + $fields['view_display_id'] = array( + 'type' => 'varchar', + 'length' => '64', + 'default' => '', + 'not null' => TRUE, + 'description' => 'An identifier for this display; usually generated from the display_plugin, so should be something like page or page_1 or block_2, etc.', + ); + + // Apply the updates to the DB. + foreach ($fields as $field_name => $spec) { + db_change_field('views_data_export', $field_name, $field_name, $spec); + } +} +/** + * Change the object cache table to support postgres installations + */ +function views_data_export_update_7301(){ + $spec = array( + 'type' => 'blob', + 'size' => 'big', + 'description' => 'Serialized data being stored.', + 'serialize' => TRUE, + ); + db_change_field('views_data_export_object_cache', 'data', 'data', $spec); +} + + /** * Implements hook_requirements(). */ @@ -126,17 +167,36 @@ function views_data_export_requirements($phase) { switch ($phase) { case 'runtime': - // Check the max allowed packet size. - $max_allowed_packet = db_query('SHOW VARIABLES WHERE variable_name = :name', array(':name' => 'max_allowed_packet'))->fetchField(1); - if (is_numeric($max_allowed_packet)) { - if ($max_allowed_packet < (16 * 1024 * 1024)) { - $requirements['views_data_export'] = array( - 'title' => $t('MySQL - max allowed packet'), - 'value' => format_size($max_allowed_packet), - 'description' => $t("Your MySQL 'max_allowed_packet' setting may be too low for Views data export to function correctly, Drupal's requirements recommend setting it to at least 16M. See: !link", array('!link' => l('http://drupal.org/requirements', 'http://drupal.org/requirements'))), - 'severity' => REQUIREMENT_WARNING, - ); - } + + $requirements['views_data_export_temp'] = array( + 'title' => t('Views Data Export temporary directory'), + 'severity' => REQUIREMENT_OK, + 'value' => t('Exists'), + ); + + $path = variable_get('views_data_export_directory', 'temporary://views_plugin_display'); + if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) { + $requirements['views_data_export_temp']['description'] = t('The Views Data Export temporary directory, %path could not be created due to a misconfigured directory. Please ensure that the temporary directory is correctly configured and that the webserver has permission to create directories.', array('%path' => file_uri_target($path))); + $requirements['views_data_export_temp']['severity'] = REQUIREMENT_ERROR; + $requirements['views_data_export_temp']['value'] = t('Unable to create'); + } + + $db_type = Database::getConnection()->databaseType(); + switch ($db_type) { + case 'mysql': + // Check the max allowed packet size. + $max_allowed_packet = db_query('SHOW VARIABLES WHERE variable_name = :name', array(':name' => 'max_allowed_packet'))->fetchField(1); + if (is_numeric($max_allowed_packet)) { + if ($max_allowed_packet < (16 * 1024 * 1024)) { + $requirements['views_data_export'] = array( + 'title' => $t('MySQL - max allowed packet'), + 'value' => format_size($max_allowed_packet), + 'description' => $t("Your MySQL 'max_allowed_packet' setting may be too low for Views data export to function correctly, Drupal's requirements recommend setting it to at least 16M. See: !link", array('!link' => l('http://drupal.org/requirements', 'http://drupal.org/requirements'))), + 'severity' => REQUIREMENT_WARNING, + ); + } + } + break; } break; } diff --git a/sites/all/modules/contrib/views/views_data_export/views_data_export.module b/sites/all/modules/contrib/views/views_data_export/views_data_export.module index d4088d75..92d9bf2b 100644 --- a/sites/all/modules/contrib/views/views_data_export/views_data_export.module +++ b/sites/all/modules/contrib/views/views_data_export/views_data_export.module @@ -93,47 +93,49 @@ function views_data_export_cron() { * garbage collect all exports. */ function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) { - - if (!isset($expires)) { - $expires = variable_get('views_data_export_gc_expires', 604800); // one week - } - if (!isset($chunk)) { - $chunk = variable_get('views_data_export_gc_chunk', 30); - } - - if ($chunk == -1) { - $result = db_query("SELECT eid FROM {views_data_export} WHERE time_stamp <= :timestamp ORDER BY time_stamp ASC", array(':timestamp' => REQUEST_TIME - $expires)); - } - else { - $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)); - } - - $eids_to_clear = array(); - foreach ($result as $row) { - $eids_to_clear[] = $row->eid; - } - - // We do two things to exports we want to garbage collect - // 1. Delete the index table for it, if it is still around - // 2. Delete the row from the exports table - // 3. Delete the view from the object_cache - if (count($eids_to_clear)) { - foreach ($eids_to_clear as $eid) { - // 1. Delete index table, if it is still around for some reason - $table = VIEWS_DATA_EXPORT_INDEX_TABLE_PREFIX . $eid; - if (db_table_exists($table)) { - db_drop_table($table); - } + if (lock_acquire('views_data_export_gc')) { + if (!isset($expires)) { + $expires = variable_get('views_data_export_gc_expires', 604800); // one week + } + if (!isset($chunk)) { + $chunk = variable_get('views_data_export_gc_chunk', 30); } - // 2. Delete the entries in the exports table. - db_delete('views_data_export') - ->condition('eid', $eids_to_clear, 'IN') - ->execute(); + if ($chunk == -1) { + $result = db_query("SELECT eid FROM {views_data_export} WHERE time_stamp <= :timestamp ORDER BY time_stamp ASC", array(':timestamp' => REQUEST_TIME - $expires)); + } + else { + $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)); + } - // 3. Clear the cached views - views_data_export_view_clear($eids_to_clear); + $eids_to_clear = array(); + foreach ($result as $row) { + $eids_to_clear[] = $row->eid; + } + // We do two things to exports we want to garbage collect + // 1. Delete the index table for it, if it is still around + // 2. Delete the row from the exports table + // 3. Delete the view from the object_cache + if (count($eids_to_clear)) { + foreach ($eids_to_clear as $eid) { + // 1. Delete index table, if it is still around for some reason + $table = VIEWS_DATA_EXPORT_INDEX_TABLE_PREFIX . $eid; + if (db_table_exists($table)) { + db_drop_table($table); + } + } + + // 2. Delete the entries in the exports table. + db_delete('views_data_export') + ->condition('eid', $eids_to_clear, 'IN') + ->execute(); + + // 3. Clear the cached views + views_data_export_view_clear($eids_to_clear); + } + + lock_release('views_data_export_gc'); } } @@ -142,7 +144,7 @@ function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) { * Batch API callback. * Handles all batching operations by executing the appropriate view. */ -function _views_data_export_batch_process($export_id, $display_id, &$context) { +function _views_data_export_batch_process($export_id, $display_id, $exposed_input, &$context) { // Don't show the admin menu on batch page, some people don't like it. if (module_exists('admin_menu')) { module_invoke('admin_menu', 'suppress'); @@ -151,7 +153,9 @@ function _views_data_export_batch_process($export_id, $display_id, &$context) { // Fetch the view in question from our cache $view = views_data_export_view_retrieve($export_id); $view->set_display($display_id); - + if (!empty($exposed_input)) { + $view->set_exposed_input($exposed_input); + } // Inform the data_export display which export it corresponds to and execute if (!isset($view->display_handler->batched_execution_state)) { $view->display_handler->batched_execution_state = new stdClass(); @@ -260,14 +264,19 @@ function views_data_export_view_retrieve($export_id) { * An export ID or an array of export IDs to clear from the object cache. */ function views_data_export_view_clear($export_id) { - if (is_array($export_id)) { - db_delete('views_data_export_object_cache') - ->condition('eid', $export_id, 'IN') - ->execute(); - } - else { - db_delete('views_data_export_object_cache') + db_delete('views_data_export_object_cache') ->condition('eid', $export_id) ->execute(); +} + +/** + * Implements hook_file_presave(). + */ +function views_data_export_file_presave($file) { + // Ensure temporary files really are temporary. + // @see: https://drupal.org/node/2198399 + if (strpos($file->filename, 'views_data_export') === 0) { + // There is no FILE_STATUS_TEMPORARY. + $file->status = 0; } }