You are here

macro.module in Macro 6

Same filename and directory in other branches
  1. 7 macro.module
  • allow administrators to record (export) form submissions
  • allow administrators to replay (import) form submissions

File

macro.module
View source
<?php

/**
 * @file
 * - allow administrators to record (export) form submissions
 * - allow administrators to replay (import) form submissions
 */

/**
 * Implementation of hook_help().
 */
function macro_help($section) {
  switch ($section) {
    case 'admin/help#macro':
      $output = t('Todo: Add help text.');
    case 'admin/build/macro/export':
      return t('This output can be saved to the profile`s .macro file, to be automatically played back upon completed install or used on an import on another site.');
    case 'admin/build/macro/import':
      return t('Insert recorded macro here to be played into your site. All referenced modules needs to be enabled.');
    case 'admin/build/macro':
      return t('Configuration settings for the drupal macro engine.');
  }
}

/**
 * Implementation of hook_perm().
 */
function macro_perm() {
  return array(
    'administer macro settings',
    'macro access',
  );
}

/**
 *  Implementation of hook_init().
 */
function macro_init() {
  if (empty($_POST) && variable_get('macro_enabled', FALSE)) {
    $args = array(
      '%d' => count(variable_get('macro_submissions', array())),
      '!link' => l('End session', 'admin/build/macro/export/session/end'),
    );
    drupal_set_message(t('[Active macros: %d | !link]', $args));
  }
}

/**
 * Implementation of hook_menu().
 */
function macro_menu() {
  $items = array();
  $items['admin/build/macro'] = array(
    'title' => 'Macro engine',
    'description' => 'Configure the Drupal macro engine. Export recorded macros or import previously recorded macros.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'macro_admin_settings',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer macro settings',
    ),
  );
  $items['admin/build/macro/export'] = array(
    'title' => 'Export',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'macro_export_macro',
    ),
    'access arguments' => array(
      'macro access',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/macro/import'] = array(
    'title' => 'Import',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'macro_import_macro',
    ),
    'access arguments' => array(
      'macro access',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/macro/settings'] = array(
    'title' => 'Configure',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/build/macro/export/session/end'] = array(
    'page callback' => 'macro_end_macro_session',
    'access arguments' => array(
      'macro access',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_form_alter().
 */
function macro_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'macro_export_macro':

      /** TODO: eventually add file saving with foldering options.
          $form['file-save'] = array('#type' => 'fieldset', '#title' => 'Save To File', '#description' => '');
          $form['file-save']['filename'] = array('#type' => 'textfield', '#title' => 'Filename');
          $form['file-save]['save'] = array('#type' => 'submit', '#value' => 'Save', '#submit' => array('macro_export_file_save_submit'));
          */
      break;

    // Forms to specifically ignore for macro.
    case 'macro_admin_settings':
    case 'macro_import_macro':
    case 'macro_export_macro':
      break;
    default:

      // Add import / export buttons to each form for simplified macro saving.
      if (user_access('macro access') && variable_get('macro_display_actions', FALSE)) {
        $form['macro-actions'] = array(
          '#type' => 'fieldset',
          '#title' => t('Macro actions'),
          '#weight' => 5000,
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
        );
        $form['macro-actions']['import-data'] = array(
          '#type' => 'submit',
          '#name' => 'import',
          '#value' => t('Import'),
          '#submit' => array(
            'macro_import_action_submit',
          ),
        );
        $form['macro-actions']['export-data'] = array(
          '#type' => 'submit',
          '#name' => 'export',
          '#value' => t('Export'),
          '#submit' => array(
            'macro_export_action_submit',
          ),
        );
        if (!variable_get('macro_enabled', FALSE)) {
          $form['macro-actions']['export-session-data'] = array(
            '#type' => 'submit',
            '#value' => t('Start session'),
            '#submit' => array(
              'macro_export_session_action_submit',
            ),
          );
        }
      }

      // Add the record callback on submit.
      if ($form_id != 'macro_import_macro' && variable_get('macro_enabled', FALSE)) {
        $form['#submit'][] = 'macro_record_macro';
      }

      // Clear the current sessions.
      if (variable_get('macro_delete', FALSE)) {
        variable_set('macro_submissions', array());
        variable_set('macro_delete', FALSE);
      }
      break;
  }
}

/**
 *  Form submit handler to redirect to the import form.
 */
function macro_import_action_submit($form, &$form_state) {
  drupal_goto('admin/build/macro/import', drupal_get_destination());
}

/**
 *  Form callback to handle macro export functionality.
 */
function macro_export_action_submit($form, &$form_state) {

  // Start a fresh session.
  variable_set('macro_submissions', array());

  // Record the single macro.
  macro_record_macro($form, $form_state);

  // Send straight to the export form.
  drupal_goto('admin/build/macro/export');
}

/**
 *  Form callback to handle macro export session functionality.
 */
function macro_export_session_action_submit($form, &$form_state) {

  // Start recording submissions and clear the saved submissions for a fresh session.
  variable_set('macro_enabled', TRUE);
  variable_set('macro_submissions', array());
}

/**
 * A form submission handler, that stores the form submissions into the variables table
 */
function macro_record_macro($form, &$form_state) {
  $macros = variable_get('macro_submissions', array());

  // Remove the $form_state as it will be rebuilt on import.
  array_shift($form['#parameters']);

  // TODO: Why is it when the record method is called through the $form['#submit'] when
  // the action buttons are not displayed do these exception values not show up in the 'values' ?
  $exceptions = array(
    'export',
    'export-data',
    'export-session-data',
    'import-data',
    'form_id',
    'submit',
    'reset',
    'form_build_id',
    'form_token',
    'delete',
  );

  // Remove the unneeded values that this module implements.
  foreach ($exceptions as $exception) {
    unset($form_state['values'][$exception]);
  }
  $macro = array(
    'form_id' => $form['form_id']['#value'],
    'path' => $_GET['q'],
    'parameters' => $form['#parameters'],
    'values' => $form_state['values'],
  );

  // Support for multistep.
  if ($form_state['storage']) {
    $macro['storage'] = $form_state['storage'];
  }
  $macros[] = $macro;
  variable_set('macro_submissions', $macros);
  return $macro;
}

/**
 * This recursively runs thru an object and converts it into an array.
 * This is to be called for form entries as we do not want varexport to treat any element
 * as an object. If varexport sees an object, it will output stdClass::__set_state, which is
 * not defined and we cannot define it either. So we recursively cast all objects to arrays.
 */
function _macro_recursively_convert_objects_to_arrays($entity) {
  $converted = array();
  foreach ((array) $entity as $key => $value) {
    if (is_array($value) || is_object($value)) {
      $converted[$key] = _macro_recursively_convert_objects_to_arrays($value);
    }
    else {
      $converted[$key] = $value;
    }
  }
  return $converted;
}

/**
 * A form callback that displays the macro exported.
 *
 * The output of this callback should be saved to the profiles/$profile/macros.inc file, to be
 * automatically played back upon completed install.
 * @return a textarea containing the recorded macros
 */
function macro_export_macro() {
  $form['code'] = array(
    '#type' => 'textarea',
    '#title' => 'macros exported',
    '#default_value' => macro_get_macro(),
    '#rows' => 20,
  );
  return $form;
}

/**
 * The output of this callback should be saved to the profiles/$profile/macros.inc file, to be
 * automatically played back upon completed install.
 * @return a code representation of the recorded macro.
 */
function macro_get_macro() {
  $subs = variable_get('macro_submissions', array());
  $string = '';
  foreach ($subs as $key => $form) {
    $string .= "\$macro[{$key}]['form_id'] = " . var_export($form['form_id'], TRUE) . ";\n";
    $string .= "\$macro[{$key}]['path'] = " . var_export($form['path'], TRUE) . ";\n";
    $string .= "\$macro[{$key}]['values']  = " . var_export(_macro_recursively_convert_objects_to_arrays((array) $form['values']), TRUE) . ";\n";

    // Add multistep support.
    if ($form['storage']) {
      $string .= "\$macro[{$key}]['storage']  = " . var_export(_macro_recursively_convert_objects_to_arrays((array) $form['storage']), TRUE) . ";\n";
    }

    // the form parameters are being used here.
    array_shift($form['parameters']);
    $string .= "\$macro[{$key}]['parameters']  = " . var_export(serialize($form['parameters']), TRUE) . ";\n\n";
  }
  return $string;
}

/**
 * A form callback that displays the macro import form.
 *
 * @return a form for importing a previously recorded macro
 */
function macro_import_macro() {
  $form['macro'] = array(
    '#type' => 'textarea',
    '#title' => 'macro to import',
    '#rows' => 20,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('play macro'),
  );
  return $form;
}

/**
 * Implementation of macro_import_macro hook_submit function.
 *
 * Plays back the submitted macro.
 */
function macro_import_macro_submit($form, &$form_state) {
  include_once './includes/install.inc';
  eval($form_state['values']['macro']);
  drupal_execute_macro($macro);
}

/**
 * Menu callback for the macro settings form.
 */
function macro_admin_settings() {
  $form['settings_general'] = array(
    '#type' => 'fieldset',
    '#title' => t('Macro settings'),
    '#collapsible' => TRUE,
  );
  $form['settings_general']['macro_enabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable macro recording'),
    '#default_value' => variable_get('macro_enabled', FALSE),
    '#description' => t('Set whether the macro engine will record form submissions.'),
  );
  $form['settings_general']['macro_display_actions'] = array(
    '#type' => 'checkbox',
    '#title' => 'Display Actions',
    '#description' => 'Add "import / export" buttons at the bottom of each form that is displayed.',
    '#default_value' => variable_get('macro_display_actions', FALSE),
  );
  $form['settings_general']['macro_delete'] = array(
    '#type' => 'checkbox',
    '#title' => t('Delete recorded macro'),
    '#default_value' => variable_get('macro_delete', FALSE),
    '#description' => t('Set whether to clear previously recorded macro.'),
  );
  return system_settings_form($form);
}

/**
 *  End a macro session from a page callback with a redirect to the export form.
 */
function macro_end_macro_session() {
  variable_set('macro_enabled', FALSE);
  drupal_goto('admin/build/macro/export');
}

/**
 * Attempts to programmatically submit all the forms that have been specified in the $macros collection.
 *
 *  @param array
 *  - a list of macros to execute
 *
 *  @return array
 *  - a list of results based on the macros provided.
 */
function drupal_execute_macro($macro) {
  foreach ($macro as $key => $data) {
    $item = menu_get_item($data['path']);
    if ($item && !empty($item['file'])) {
      include_once $item['file'];
    }
  }
  $results = array();
  foreach ($macro as $key => $data) {
    $param = unserialize($data['parameters']);
    $form_values = array(
      'values' => $data['values'],
    );

    // Support for multistep.
    if ($data['storage']) {
      $form_values['storage'] = $data['storage'];
    }
    $args = array(
      $data['form_id'],
      $form_values,
    );
    $args = array_merge($args, $param);
    $results[] = call_user_func_array('drupal_execute', $args);
    if (form_get_errors()) {
      drupal_set_message(t("An error has occured with macro #%macro_number , form_id %form_id. Please check the errors displayed for more details.", array(
        '%macro_number' => $key,
        '%form_id' => $data['form_id'],
      )));
    }
  }
  return $results;
}

Functions

Namesort descending Description
drupal_execute_macro Attempts to programmatically submit all the forms that have been specified in the $macros collection.
macro_admin_settings Menu callback for the macro settings form.
macro_end_macro_session End a macro session from a page callback with a redirect to the export form.
macro_export_action_submit Form callback to handle macro export functionality.
macro_export_macro A form callback that displays the macro exported.
macro_export_session_action_submit Form callback to handle macro export session functionality.
macro_form_alter Implementation of hook_form_alter().
macro_get_macro The output of this callback should be saved to the profiles/$profile/macros.inc file, to be automatically played back upon completed install.
macro_help Implementation of hook_help().
macro_import_action_submit Form submit handler to redirect to the import form.
macro_import_macro A form callback that displays the macro import form.
macro_import_macro_submit Implementation of macro_import_macro hook_submit function.
macro_init Implementation of hook_init().
macro_menu Implementation of hook_menu().
macro_perm Implementation of hook_perm().
macro_record_macro A form submission handler, that stores the form submissions into the variables table
_macro_recursively_convert_objects_to_arrays This recursively runs thru an object and converts it into an array. This is to be called for form entries as we do not want varexport to treat any element as an object. If varexport sees an object, it will output stdClass::__set_state, which is not…