You are here

backup_migrate_prune.module in Backup and migrate prune 7

Same filename and directory in other branches
  1. 7.2 backup_migrate_prune.module

Create (manually or scheduled) and restore backups of your Drupal MySQL database with an option to exclude table data (e.g. cache_*)

File

backup_migrate_prune.module
View source
<?php

/**
 * @file
 * Create (manually or scheduled) and restore backups of your Drupal MySQL
 * database with an option to exclude table data (e.g. cache_*)
 */

/* Drupal Hooks */

/**
 * Implementation of hook_help().
 */

/**
 * Implementation of hook_menu().
 */
function backup_migrate_prune_menu() {
  $base_index = count(explode('/', BACKUP_MIGRATE_MENU_PATH));
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune'] = array(
    'title' => 'Prune',
    'description' => 'Administer your gardeners (workers that prune your backups).',
    'page callback' => 'backup_migrate_menu_callback',
    'page arguments' => array(
      '',
      'backup_migrate_ui_manual_prune_list',
      TRUE,
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 5,
  );
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune/list'] = array(
    'title' => 'Prune',
    'description' => 'Administer your gardeners (workers that prune your backups).',
    'page callback' => 'backup_migrate_menu_callback',
    'page arguments' => array(
      '',
      'backup_migrate_ui_manual_prune_list',
      TRUE,
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 5,
  );
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune/add'] = array(
    'title' => 'Add a gardener',
    'description' => 'Administer your gardeners (workers that prune your backups).',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'backup_migrate_prune_add_form',
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_LOCAL_ACTION,
    'weight' => 2,
  );
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune/edit/%'] = array(
    'title' => 'Add a gardener',
    'description' => 'Administer your gardeners (workers that prune your backups).',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'backup_migrate_prune_add_form',
      $base_index + 2,
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_CALLBACK,
  );
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune/delete/%'] = array(
    'title' => 'Delete',
    'description' => 'Delete the gardener.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'backup_migrate_prune_delete_gardener',
      $base_index + 2,
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_CALLBACK,
  );
  $items[BACKUP_MIGRATE_MENU_PATH . '/prune/prune/%'] = array(
    'title' => 'Prune the destination',
    'description' => 'Prune the destination.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'backup_migrate_prune_prune_form',
      $base_index + 2,
    ),
    'access arguments' => array(
      'access backup and migrate',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}
function backup_migrate_prune_add_form($form, $form_state, $gardener_id = NULL) {
  backup_migrate_include('destinations');
  try {
    $gardener = new Gardener($gardener_id);
  } catch (ErrorException $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
  }
  $form = array();
  if ($gardener_id) {
    drupal_set_title(t('Edit gardener: @name.', array(
      '@name' => $gardener
        ->getName(),
    )));
    $message = t('If you change the deletion settings of a gardener will probably end up deleting backups you kept previously. If you are not sure about the resulting configuration <strong>do not change</strong> the deletion settings.<br />Example: If you kept the backups in June for the last 3 years and you change that setting to March all the June backups will be gone.');
    $form['warning'] = array(
      'title' => array(
        '#markup' => '<h3>' . t('Important notice') . '</h3>',
      ),
      'message' => array(
        '#markup' => $message,
      ),
    );
  }
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
    '#description' => t('Enter a name describing your gardener.'),
    '#required' => TRUE,
    '#default_value' => $gardener
      ->getName(),
  );
  foreach (backup_migrate_get_destinations() as $key => $value) {
    $options[$key] = $value->name;
  }
  $form['destination'] = array(
    '#type' => 'select',
    '#title' => t('Destination'),
    '#description' => t('Select the destination to act upon.'),
    '#options' => $options,
    '#required' => TRUE,
    '#default_value' => $gardener_id ? $gardener
      ->getDestination()
      ->get_id() : '',
  );
  $form['settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Deletion settings'),
    '#tree' => TRUE,
  );
  $form['settings']['thisweek_slot'] = array(
    '#type' => 'fieldset',
    '#title' => t('Backups created this week'),
    '#description' => t('Prune backups created this week leaving one backup per day.'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#tree' => TRUE,
  );
  $form['settings']['thisweek_slot']['active'] = array(
    '#type' => 'checkbox',
    '#title' => t('Active'),
    '#default_value' => TRUE,
    '#disabled' => TRUE,
  );
  $form['settings']['thismonth_slot'] = array(
    '#type' => 'fieldset',
    '#title' => t('Backups created this month'),
    '#description' => t('Prune backups created this month leaving only one backup per week.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#tree' => TRUE,
  );
  $form['settings']['thismonth_slot']['active'] = array(
    '#type' => 'checkbox',
    '#title' => t('Active'),
  );
  $form['settings']['thismonth_slot']['keep'] = array(
    '#type' => 'select',
    '#options' => array(
      1 => t('Monday'),
      2 => t('Tuesday'),
      3 => t('Wednesday'),
      4 => t('Thursday'),
      5 => t('Friday'),
      6 => t('Saturday'),
      7 => t('Sunday'),
    ),
    '#title' => t('Preferred day to keep'),
    '#description' => t('Select the day in the week you want to keep. The most recent backup will be kept. If there is no backup on your preferred day a random day will be used.'),
  );
  $form['settings']['thisyear_slot'] = array(
    '#type' => 'fieldset',
    '#title' => t('Backups created this year'),
    '#description' => t('Prune backups created this year leaving only one backup per month.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#tree' => TRUE,
  );
  $form['settings']['thisyear_slot']['active'] = array(
    '#type' => 'checkbox',
    '#title' => t('Active'),
  );
  $form['settings']['thisyear_slot']['keep'] = array(
    '#type' => 'select',
    '#options' => array(
      1 => t('1st week'),
      2 => t('2nd week'),
      3 => t('3rd week'),
      4 => t('4th week'),
    ),
    '#title' => t('Preferred week to keep'),
    '#description' => t('Select the week of the month to keep. Only the first four weeks will be considered. If there is no backup on your preferred week a random week will be used.'),
  );
  $form['settings']['pastyears_slot'] = array(
    '#type' => 'fieldset',
    '#title' => t('Backups created past years'),
    '#description' => t('Prune backups created more than one year ago leaving only one backup per year.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#tree' => TRUE,
  );
  $form['settings']['pastyears_slot']['active'] = array(
    '#type' => 'checkbox',
    '#title' => t('Active'),
  );
  $form['settings']['pastyears_slot']['keep'] = array(
    '#type' => 'select',
    '#options' => array(
      1 => t('January'),
      2 => t('February'),
      3 => t('March'),
      4 => t('April'),
      5 => t('May'),
      6 => t('June'),
      7 => t('July'),
      8 => t('August'),
      9 => t('September'),
      10 => t('October'),
      11 => t('November'),
      12 => t('December'),
    ),
    '#title' => t('Preferred month to keep'),
    '#description' => t('Select the month in the year you want to keep. If there is no backup on your preferred month a random month will be used.'),
  );
  $settings = $gardener
    ->getSettings();
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  if ($settings) {

    // Fill in the default values
    $form['settings']['thismonth_slot']['active']['#default_value'] = $settings['thismonth_slot']['active'];
    $form['settings']['thismonth_slot']['keep']['#default_value'] = $settings['thismonth_slot']['keep'];
    $form['settings']['thisyear_slot']['active']['#default_value'] = $settings['thisyear_slot']['active'];
    $form['settings']['thisyear_slot']['keep']['#default_value'] = $settings['thisyear_slot']['keep'];
    $form['settings']['pastyears_slot']['active']['#default_value'] = $settings['pastyears_slot']['active'];
    $form['settings']['pastyears_slot']['keep']['#default_value'] = $settings['pastyears_slot']['keep'];
  }
  $form['gardener_id'] = array(
    '#type' => 'hidden',
    '#value' => $gardener_id,
  );
  $form['#submit'][] = 'backup_migrate_prune_menu_submit';
  return $form;
}
function backup_migrate_prune_menu_submit($form, &$form_state) {
  backup_migrate_include('destinations');
  $form_state['redirect'] = array(
    BACKUP_MIGRATE_MENU_PATH . '/prune',
  );
  try {

    // Create an empty gardener or a populated gardener
    $gardener = new Gardener($form_state['values']['gardener_id']);

    // Set the configuration for the gardener
    $gardener
      ->setName($form_state['values']['name']);
    $gardener
      ->setSettings($form_state['values']['settings']);
    $gardener
      ->setCreated(time());
    $gardener
      ->setDestination(backup_migrate_get_destination($form_state['values']['destination']));

    // Save the gardener
    $gardener
      ->save();
  } catch (ErrorException $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
  }
}

/**
 * Page callback for the prune list
 * 
 * @todo Move presentation code to a theme function
 */
function backup_migrate_ui_manual_prune_list() {
  backup_migrate_include('destinations');
  $query = db_select('backup_migrate_gardener', 'bmg')
    ->fields('bmg')
    ->execute();
  $rows = array();
  $days = array(
    1 => t('Monday'),
    2 => t('Tuesday'),
    3 => t('Wednesday'),
    4 => t('Thursday'),
    5 => t('Friday'),
    6 => t('Saturday'),
    7 => t('Sunday'),
  );
  $week = array(
    1 => t('1st week'),
    2 => t('2nd week'),
    3 => t('3rd week'),
    4 => t('4th week'),
  );
  $month = array(
    1 => t('January'),
    2 => t('February'),
    3 => t('March'),
    4 => t('April'),
    5 => t('May'),
    6 => t('June'),
    7 => t('July'),
    8 => t('August'),
    9 => t('September'),
    10 => t('October'),
    11 => t('November'),
    12 => t('December'),
  );
  while ($result = $query
    ->fetchAssoc()) {
    $result['settings'] = unserialize($result['settings']);
    $rows[] = array(
      'data' => array(
        $result['name'],
        backup_migrate_get_destination($result['destination_id'])->name,
        $result['settings']['thismonth_slot']['active'] ? $days[$result['settings']['thismonth_slot']['keep']] : t('- Inactive -'),
        $result['settings']['thisyear_slot']['active'] ? $week[$result['settings']['thisyear_slot']['keep']] : t('- Inactive -'),
        $result['settings']['pastyears_slot']['active'] ? $month[$result['settings']['pastyears_slot']['keep']] : t('- Inactive -'),
        format_date($result['created'], 'short'),
        theme('item_list', array(
          'items' => array(
            l(t('Edit'), BACKUP_MIGRATE_MENU_PATH . '/prune/edit/' . $result['gardener_id']),
            l(t('Delete'), BACKUP_MIGRATE_MENU_PATH . '/prune/delete/' . $result['gardener_id']),
            l(t('Prune'), BACKUP_MIGRATE_MENU_PATH . '/prune/prune/' . $result['gardener_id']),
            l(t('See files'), BACKUP_MIGRATE_MENU_PATH . '/destination/list/files/' . $result['destination_id']),
          ),
        )),
      ),
    );
  }
  $header = array(
    t('Gardener name'),
    t('Destination'),
    t('Keep day'),
    t('Keep week'),
    t('Keep month'),
    t('Created'),
    t('Actions'),
  );
  return theme('table', array(
    'header' => $header,
    'rows' => $rows,
  ));
}
function backup_migrate_prune_delete_gardener($form, &$form_state, $gardener_id) {
  $form['gardener_id'] = array(
    '#type' => 'hidden',
    '#value' => $gardener_id,
  );
  $form = confirm_form($form, t('Are you sure you want to delete this gardener?'), BACKUP_MIGRATE_MENU_PATH . '/prune/list');
  return $form;
}
function backup_migrate_prune_delete_gardener_submit($form, &$form_state) {
  $form_state['redirect'] = array(
    BACKUP_MIGRATE_MENU_PATH . '/prune/list',
  );
  try {
    $gardener = new Gardener($form_state['values']['gardener_id']);
    $gardener
      ->delete();
  } catch (ErrorException $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
  }
}

/**
 * Form for Form API
 */
function backup_migrate_prune_prune_form($form, &$form_state, $gardener_id) {
  try {
    $gardener = new Gardener($gardener_id);
  } catch (ErrorException $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
  }
  $question = t('Are you sure you want to prune the destination with the rules provided by gardener %gardener?', array(
    '%gardener' => $gardener
      ->getName(),
  ));
  $path = BACKUP_MIGRATE_MENU_PATH . '/prune';
  $description = t('If you continue several backup files may be deleted. Proceed only if you are sure you want to delete old backups.');
  $yes = t('Delete old backups');
  $form = array(
    'gardener_id' => array(
      '#type' => 'hidden',
      '#value' => $gardener_id,
    ),
  );
  return confirm_form($form, $question, $path, $description, $yes);
}

/**
 * Submit function for backup_migrate_prune_prune_form
 */
function backup_migrate_prune_prune_form_submit($form, &$form_state) {
  backup_migrate_prune_prune($form_state['values']['gardener_id']);
  $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . '/prune';
}

/**
 * Helper function to prune a destination
 * @param $gardener_id
 *   The id of the gardener
 */
function backup_migrate_prune_prune($gardener_id) {
  try {
    $gardener = new Gardener($gardener_id);
    if ($deleted = $gardener
      ->prune()) {
      watchdog('backup_migrate_prune', t('Deleted %num backups.', array(
        '%num' => $deleted,
      )), array(), WATCHDOG_NOTICE);
    }
  } catch (ErrorException $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
  }
}

/**
 * Implementation hook_cron().
 */
function backup_migrate_prune_cron() {
  $query = db_select('backup_migrate_gardener', 'bmg')
    ->fields('bmg')
    ->execute();
  while ($gardener = $query
    ->fetchAssoc()) {
    backup_migrate_prune_prune($gardener['gardener_id']);
  }
}