You are here

field_defaults.module in Field Defaults 7

Same filename and directory in other branches
  1. 8 field_defaults.module
  2. 7.2 field_defaults.module

field_defaults.module

Allows updating existing content with default values

File

field_defaults.module
View source
<?php

/**
 * @file field_defaults.module
 *
 * Allows updating existing content with default values
 */

/**
 * Implements hook_form_FORM_ID_alter().
 */
function field_defaults_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
  if (isset($form['instance']['default_value_widget'])) {

    // Check for field translations
    $field_translatable = !empty($form['#field']['translatable']);
    $form['instance']['default_value_widget']['update_defaults'] = array(
      '#type' => 'fieldset',
      '#title' => t('Update existing content'),
      '#weight' => 100,
    );
    $form['instance']['default_value_widget']['update_defaults']['field_defaults_update'] = array(
      '#type' => 'checkbox',
      '#title' => t('Update existing content with the default value(s)'),
      '#description' => t('Note: Translatable <strong>fields</strong> will need to be updated per language on the translate tab'),
    );

    // If field translation off, then we need to select what ENTITY LANGUAGE
    // content to update, otherwise we can
    if ($field_translatable) {
      $form['instance']['default_value_widget']['update_defaults']['field_defaults_lang'] = array(
        '#type' => 'value',
        '#value' => 'field_translation',
      );
    }
    else {
      $options = array(
        LANGUAGE_NONE => t('Language neutral'),
      );

      // Only give other options if i18n enabled
      if (module_exists('i18n')) {
        $language_list = language_list();
        foreach ($language_list as $language) {
          $options[$language->language] = $language->name;
        }
        $default_language = language_default();
        $form['instance']['default_value_widget']['update_defaults']['field_defaults_lang'] = array(
          '#type' => 'checkboxes',
          '#title' => t('Update entities of the following languages'),
          '#default_value' => array(
            $default_language->language,
          ),
          '#options' => $options,
        );
      }
      else {
        $form['instance']['default_value_widget']['update_defaults']['field_defaults_lang'] = array(
          '#type' => 'value',
          '#value' => $options,
        );
      }
    }
    $form['#submit'][] = '_field_defaults_ui_submit';
  }
}

/**
 * Submit handler for field ui form
 */
function _field_defaults_ui_submit($form, &$form_state) {
  $update_defaults = $form_state['values']['update_defaults']['field_defaults_update'];
  $field = $form_state['values']['instance']['field_name'];
  if ($update_defaults && isset($form_state['values'][$field])) {
    $field_translate = FALSE;
    $languages = $form_state['values']['update_defaults']['field_defaults_lang'];
    if ($languages == 'field_translation') {
      $default_language = language_default();
      $languages = array(
        $default_language->language => $default_language->name,
      );
      $field_translate = TRUE;
    }
    $batch = array(
      'entity_type' => $form_state['values']['instance']['entity_type'],
      'bundle' => $form_state['values']['instance']['bundle'],
      'field' => $field,
      'default_value' => $form_state['values'][$field][LANGUAGE_NONE],
      'languages' => $languages,
      'field_translation' => $field_translate,
      'redirect' => $form_state['redirect'],
    );

    // update the defaults
    field_defaults_batch_run($batch);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * @TODO: Need to find out how to actually get some details here... might have
 * to build a new form as this one is not bound to the entity so doing some
 * pretty hack-ish works here...
 *
 */
function field_defaults_form_i18n_string_translate_page_form_alter(&$form, &$form_state) {
  $disabled = TRUE;
  foreach ($form['strings']['instance'] as $key => $field) {
    if (strpos($key, 'default_value') !== FALSE) {
      $disabled = $form['strings']['instance'][$key]['#disabled'];
      $parts = explode(':', $key);
    }
  }
  if (!$disabled) {

    // See if we can narrow this field down to its entity type
    $entity_type = FALSE;
    $field = $parts[1];
    $bundle = $parts[2];
    $field_info = field_info_field($field);

    // If only one entity we're golden
    if (count($field_info['entity_types']) == 1) {
      $entity_type = $field_info['entity_types'][0];
    }
    else {
      foreach ($field_info['bundles'] as $type => $bundles) {
        if (in_array($bundle, $bundles)) {
          $entity_type = $type;
        }
      }
    }
    if ($entity_type) {
      $form['field_defaults_batch'] = array(
        '#type' => 'value',
        '#value' => array(
          'entity_type' => $entity_type,
          'bundle' => $bundle,
          'field' => $field,
        ),
      );
      $form['strings']['instance']['update_defaults'] = array(
        '#type' => 'checkbox',
        '#title' => t('Update existing content with the default value'),
        '#weight' => 100,
      );
      $form['#submit'][] = '_field_defaults_translation_submit';
    }
  }
}

/**
 * Submit handler for field ui translation form
 */
function _field_defaults_translation_submit($form, &$form_state) {
  $update_defaults = $form_state['values']['update_defaults'];

  // @TODO: Again, some pretty hacky ways to get at this data
  if ($update_defaults) {

    // Setup batch
    $batch = $form_state['values']['field_defaults_batch'];
    $batch['languages'] = array(
      $form_state['values']['langcode'] => $form_state['values']['langcode'],
    );
    $batch['field_translation'] = TRUE;
    $key = 'field:' . $batch['field'] . ':' . $batch['bundle'] . ':default_value';
    if (isset($form_state['values']['strings'][$key])) {
      $batch['default_value'] = array(
        array(
          'value' => $form_state['values']['strings'][$key],
        ),
      );
      field_defaults_batch_run($batch);
    }
  }
}

/**
 * The batch callback.
 */
function field_defaults_batch_run($variables) {
  $batch = array(
    'operations' => array(),
    'finished' => 'field_defaults_batch_finished',
    'title' => t('Update field defaults'),
    'init_message' => t('Grabbing entities'),
    'progress_message' => t('Processed @current out of @total.'),
    'error_message' => t('updated has encountered an error.'),
  );
  $redirect = isset($variables['redirect']) ? $variables['redirect'] : NULL;

  // Run each language separate
  foreach ($variables['languages'] as $langcode => $value) {

    // unchecked have no values but still have keys
    if ($value) {
      $batch['operations'][] = array(
        'field_defaults_batch_process',
        array(
          $variables,
          $langcode,
        ),
      );
    }
  }
  batch_set($batch);
  batch_process($redirect);
}

/**
 * The batch processor.
 *
 * @TODO: There is a chance of someone using LANGUAGE_NONE for the entity, but
 * still having field translation. This still should work but is leaving erroneous
 * records in the field I believe
 *
 */
function field_defaults_batch_process($variables, $langcode, &$context) {
  $entity_type = $variables['entity_type'];
  $bundle = $variables['bundle'];
  $field = $variables['field'];
  if (!isset($context['sandbox']['current'])) {
    $context['sandbox']['count'] = 0;
    $context['sandbox']['current'] = 0;
  }
  $entity_info = entity_get_info($entity_type);
  $entity_keys = $entity_info['entity keys'];

  // Get all entities to update
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', $entity_type)
    ->propertyCondition($entity_info['entity keys']['id'], $context['sandbox']['current'], '>')
    ->propertyOrderBy($entity_info['entity keys']['id']);
  if (!empty($entity_keys['bundle'])) {
    $query
      ->propertyCondition($entity_keys['bundle'], $bundle);
  }
  if (!$variables['field_translation'] && !empty($entity_keys['language'])) {
    $query
      ->propertyCondition($entity_keys['language'], $langcode);

    // Set language for fields as LANGUAGE_NONE since we are updating based on
    // content and not field
    $langcode = LANGUAGE_NONE;
  }

  // Get the total amount of entities to process.
  if (!isset($context['sandbox']['total'])) {
    $context['sandbox']['total'] = $query
      ->count()
      ->execute();
    $query->count = FALSE;

    // If there are no entities, stop now
    if (!$context['sandbox']['total']) {
      $context['finished'] = 1;
      return;
    }
  }

  // Process 25 entities per iteration.
  $query
    ->range(0, 25);
  $result = $query
    ->execute();
  foreach ($result[$entity_type] as $entity_id => $entity) {

    // Account for revisions
    $revision = $entity_id;
    if (isset($entity->{$entity_keys['revision']})) {
      $revision = $entity->{$entity_keys['revision']};
    }

    // Need to account for Deltas
    foreach ($variables['default_value'] as $delta => $value) {
      $field_keys = array(
        'entity_type' => $entity_type,
        'entity_id' => $entity_id,
        'deleted' => 0,
        'delta' => $delta,
        'language' => $langcode,
      );
      $field_values = array(
        'bundle' => $bundle,
        'revision_id' => $revision,
      );

      // Values can be multiple columns as well depending on widget
      foreach ($value as $key => $data) {
        $field_values[$field . '_' . $key] = $data;
      }

      // Update everything
      db_merge('field_data_' . $field)
        ->key($field_keys)
        ->fields($field_values)
        ->execute();
      db_merge('field_revision_' . $field)
        ->key($field_keys)
        ->fields($field_values)
        ->execute();
    }
    $context['results'][] = t('Field defaults for field @field on @bundle @id updated.', array(
      '@field' => $field,
      '@bundle' => $entity_type . ': ' . $bundle,
      '@id' => $entity_id,
    ));
  }

  // reset cache on these updates
  $update_ids = array_keys($result[$entity_type]);
  entity_get_controller($entity_type)
    ->resetCache($update_ids);
  $context['sandbox']['count'] += count($update_ids);
  $context['sandbox']['current'] = max($update_ids);
  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  }
}

/**
 * The batch finish handler.
 */
function field_defaults_batch_finished($success, $results, $operations) {
  if ($success) {
    drupal_set_message(t('Default values updated on existing content'));
  }
  else {
    $error_operation = reset($operations);
    $message = t('An error occurred while processing %error_operation with arguments: @arguments', array(
      '%error_operation' => $error_operation[0],
      '@arguments' => print_r($error_operation[1], TRUE),
    ));
    drupal_set_message($message, 'error');
  }
}

Functions