You are here

mailsystem.module in Mail System 7.3

Provide UI for controlling the mail_system variable.

File

mailsystem.module
View source
<?php

/**
 * @file
 * Provide UI for controlling the mail_system variable.
 */

/**
 * Implements hook_permission().
 *
 * Defines a permission for managing the mail_system variable.
 */
function mailsystem_permission() {
  return array(
    'administer mailsystem' => array(
      'title' => t('Administer Mail System'),
      'description' => t('Select the default, per-module, and per-mailing <a href="!interface"><code>@interface</code></a> to use for formatting and sending email messages.', array(
        '!interface' => url('http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7'),
        '@interface' => 'MailSystemInterface',
      )),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function mailsystem_menu() {
  $items['admin/config/system/mailsystem'] = array(
    'title' => 'Mail System',
    'description' => 'Configure per-module Mail System settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailsystem_admin_settings',
    ),
    'access arguments' => array(
      'administer mailsystem',
    ),
    'file' => 'mailsystem.admin.inc',
  );
  return $items;
}

/**
 * Returns the id for the default mail_system setting.
 */
function mailsystem_default_id() {

  // @todo: Is there a way to get this from core?
  return 'default-system';
}

/**
 * Returns the value for the default mail_system setting.
 */
function mailsystem_default_value() {

  // @todo: Is there a way to get this from core?
  return 'DefaultMailSystem';
}

/**
 * Returns the default settings for the mail_system variable.
 */
function mailsystem_defaults() {
  return array(
    mailsystem_default_id() => mailsystem_default_value(),
  );
}

/**
 * Returns the current mail_system settings.
 *
 * @return array
 *   The contents of the mail_system variable merged with its defaults.
 */
function mailsystem_get() {
  return array_merge(mailsystem_defaults(), variable_get('mail_system', mailsystem_defaults()));
}

/**
 * Returns a list of module delegations.
 *
 * @return array
 *   An associative array ($id => $value) where:
 *   - $id is the machine-readable module name optionally followed by '_'
 *     and a key.
 *   - $value is an associative array whose keys are the names of methods
 *     defined by MailSystemInterface and whose values are the names of
 *     the class to use for that method.
 */
function mailsystem_read_settings() {
  $mail_system = mailsystem_get();
  $settings = array();
  foreach ($mail_system as $id => $class) {
    if ($class == 'MailsystemDelegateMailSystem') {
      $settings[$id] = variable_get('mailsystem_delegate:' . $id);
    }
    else {
      $settings[$id]['mail'] = $class;
      $settings[$id]['format'] = $class;
    }
  }
  return $settings;
}

/**
 * Helps other modules safely set their own key within mail_system.
 *
 * This function should be called from hook_enable() implementations.
 *
 * @param array $setting
 *   An associative array ($id => $value) where:
 *   - $id is the machine-readable module name optionally followed by '_'
 *     and a key.
 *   - $value is one of
 *     - (string) The name of a class that implements MailSystemInterface.
 *     - (array) An associative array whose keys are the names of methods
 *       defined by MailSystemInterface and whose values are the names of
 *       the class to use for that method.
 *
 * @see drupal_mail()
 */
function mailsystem_set(array $setting) {
  $mail_system = mailsystem_get();
  foreach ($setting as $key => $class) {
    variable_del("mailsystem_delegate:{$key}");
    if (is_array($class)) {

      // Save the settings for our delegateer-class into a variable.
      $setting[$key] = mailsystem_delegate_set_mailsystem_settings($key, $class);
    }
  }
  variable_set('mail_system', array_merge(mailsystem_get(), $setting));
}

/**
 * Helps other modules safely remove their settings from mail_system.
 *
 * Function should be called from the other module's hook_disable() function.
 *
 * @param array $setting
 *   An associative array ($module => $classname) describing
 *   a module and associated MailSystemInterface class that are being disabled.
 *   - $module is the machine-readable module name.
 *   - $classname is a class that implements MailSystemInterface.
 *
 *   If $classname is empty, only the $module entry is removed.
 */
function mailsystem_clear(array $setting) {
  variable_set('mail_system', array_merge(mailsystem_defaults(), array_diff_key(array_diff(mailsystem_get(), $setting), $setting)));
  foreach (array_keys($setting) as $key) {
    variable_del("mailsystem_delegate:{$key}");
  }
}

/**
 * Save settings for the delegate mail system for a given mail-id.
 *
 * @param int $id
 *   Is the machine-readable module name optionally followed by '_'
 *   and a key.
 * @param array $settings
 *   An associative array whose keys are the names of methods
 *   defined by MailSystemInterface and whose values are the names of
 *       the class to use for that method.
 *
 * @return string
 *   A string specifying the name of the delegator class.
 */
function mailsystem_delegate_set_mailsystem_settings($id, array $settings) {
  variable_set('mailsystem_delegate:' . $id, $settings);
  return 'MailsystemDelegateMailSystem';
}

/**
 * Returns an MailSystemInterface class instance for a given action.
 *
 *  Of a class implementing the MailSystemInterface
 * responsible for performing the given action.
 *
 * @param string $module
 *   The machine-readable module name.
 * @param string $key
 *   The email key.
 * @param string $action
 *   The name of the MailSystemInterface method to be invoked. Should be one of:
 *   - format: Format a message composed by drupal_mail() prior to sending.
 *   - mail: Send a message composed by drupal_mail().
 *
 * @return MailSystemInterface
 *   A mail system implementation.
 *
 * @see drupal_mail_system()
 */
function _mailsystem_delegate_get_mailsystem($module, $key, $action) {
  $instances =& drupal_static(__FUNCTION__, array());

  // Try to use custom settings defined for the message's module and key.
  $settings = variable_get('mailsystem_delegate:' . $module . '_' . $key);
  if ($settings === NULL) {

    // Try to use custom settings defined for the message's module.
    $settings = variable_get('mailsystem_delegate:' . $module);
  }
  if ($settings === NULL) {

    // Try to use the configured site-wide default mail system settings.
    $settings = variable_get('mailsystem_delegate:' . mailsystem_default_id());
  }

  // Use the class configured for the given action.
  if ($settings && isset($settings[$action])) {
    $class = $settings[$action];
  }
  else {
    $mailsystems = mailsystem_get();
    $class = $mailsystems[mailsystem_default_id()];

    // Fallback to drupal default in order to prevent an infinite recursion.
    if ($class == 'MailsystemDelegateMailSystem') {
      $class = mailsystem_default_value();
    }
  }
  if (empty($instances[$class])) {
    $interfaces = class_implements($class);
    if (isset($interfaces['MailSystemInterface'])) {
      $instances[$class] = new $class();
    }
    else {
      throw new Exception(t('Class %class does not implement interface %interface', array(
        '%class' => $class,
        '%interface' => 'MailSystemInterface',
      )));
    }
  }
  return $instances[$class];
}

/**
 * Returns a list of classes which implement MailSystemInterface.
 *
 * This method assumes that all classes which implement MailSystemInterface
 * have filenames containing '.mail.' or class names containing 'MailSystem'.
 *
 * If necessary you may override the default discovery whitelist by setting
 * the mailsystem_get_classes_whitelist and mailsystem_get_classes_blacklist
 * variables. The default value is as follows:
 *
 * @code
 * variable_set('mailsystem_get_classes_whitelist', array(
 *   array(
 *     'field' => 'name',
 *     'value' => '%MailSystem',
 *     'operator' => 'LIKE',
 *   ),
 *   array(
 *     'field' => 'filename',
 *     'value' => '%.mail.%',
 *     'operator' => 'LIKE',
 *   ),
 * ));
 *
 * variable_set('mailsystem_get_classes_blacklist', array(
 *   array(
 *     'field' => 'filename',
 *     'value' => '%.test',
 *     'operator' => 'NOT LIKE',
 *   ),
 * ));
 * @endcode
 *
 * The 'field' value specifies in which database-field of the registry table
 * the lookup for 'value' should take place. Typical values for 'field' are
 * either 'name' for the classname or 'filename' for the name of the file the
 * class is contained in.
 *
 * For example, if your own mail system implementation called 'MyMailer' should
 * be available in the mailsystem module you may add the following record to
 * the whitelist:
 *
 * @code
 * array(
 *   'field' => 'name',
 *   'value' => 'MyMailer',
 * );
 * @endcode
 *
 * Note that if you set the blacklist, you need to negate the operator. Use
 * 'NOT Like' or the not-equal operator '<>'.
 */
function mailsystem_get_classes() {
  $mailsystem_classes =& drupal_static(__FUNCTION__);
  if (!isset($mailsystem_classes)) {
    $query = db_select('registry', 'registry')
      ->fields('registry', array(
      'name',
      'filename',
    ))
      ->condition('type', 'class');
    if ($whitelist = _mailsystem_get_registry_whitelist_condition()) {
      $query
        ->condition($whitelist);
    }
    if ($blacklist = _mailsystem_get_registry_blacklist_condition()) {
      $query
        ->condition($blacklist);
    }
    $mail_classes = $query
      ->execute()
      ->fetchAllKeyed();
    $mailsystem_classes = array();
    foreach ($mail_classes as $classname => $classfile) {
      if (file_exists($classfile)) {
        $interfaces = class_implements($classname);
        if (isset($interfaces['MailSystemInterface'])) {
          $mailsystem_classes[$classname] = $classname;
        }
      }
    }
    ksort($mailsystem_classes);
  }
  return $mailsystem_classes;
}

/**
 * Return a DatabaseCondition representing the registry-whitelist.
 *
 * @return DatabaseCondition|null
 *   DatabaseCondition representing the whitelist conditions or NULL.
 *
 * @see mailsystem_get_classes
 */
function _mailsystem_get_registry_whitelist_condition() {
  $whitelist = variable_get('mailsystem_get_classes_whitelist', array(
    array(
      'field' => 'name',
      'value' => '%MailSystem',
      'operator' => 'LIKE',
    ),
    array(
      'field' => 'filename',
      'value' => '%.mail.%',
      'operator' => 'LIKE',
    ),
  ));
  if (!empty($whitelist)) {
    $or = db_or();
    foreach ($whitelist as $entry) {
      if (!empty($entry['field']) && !empty($entry['value']) && !empty($entry['operator'])) {
        $or
          ->condition($entry['field'], $entry['value'], $entry['operator']);
        $condition_added = TRUE;
      }
    }
    if ($or
      ->count()) {
      return $or;
    }
  }
}

/**
 * Return a DatabaseCondition representing the registry-blacklist.
 *
 * By default all files ending with .test are excluded if the simpletest module
 * is disabled. The blacklist pattern can be overridden using the variable
 * mailsystem_get_classes_blacklist.
 *
 * @return DatabaseCondition|null
 *   DatabaseCondition representing the blacklist conditions or NULL.
 *
 * @see mailsystem_get_classes
 */
function _mailsystem_get_registry_blacklist_condition() {
  if (!module_exists('simpletest')) {
    $default_blacklist = array(
      array(
        'field' => 'filename',
        'value' => '%.test',
        'operator' => 'NOT LIKE',
      ),
    );
  }
  else {
    $default_blacklist = array();
  }
  $blacklist = variable_get('mailsystem_get_classes_blacklist', $default_blacklist);
  if (!empty($blacklist)) {
    $and = db_and();
    foreach ($blacklist as $entry) {
      if (!empty($entry['field']) && !empty($entry['value']) && !empty($entry['operator'])) {
        $and
          ->condition($entry['field'], $entry['value'], $entry['operator']);
      }
    }
    if ($and
      ->count()) {
      return $and;
    }
  }
}

/**
 * Implements hook_theme_registry_alter().
 */
function mailsystem_theme_registry_alter(&$theme_registry) {
  module_load_include('inc', 'mailsystem', 'mailsystem.theme');
  return mailsystem_theme_theme_registry_alter($theme_registry);
}

/**
 * Retrieves the key of the theme used to render the emails.
 *
 * @todo Add some kind of hook to let other modules alter this behavior.
 */
function mailsystem_get_mail_theme() {
  global $theme_key;
  $theme = variable_get('mailsystem_theme', 'current');
  switch ($theme) {
    case 'default':
      $theme = variable_get('theme_default', NULL);
      break;
    case 'current':
      $theme = $theme_key;
      break;
    case 'domain':

      // Fetch the theme for the current domain.
      if (module_exists('domain_theme')) {

        // Assign the selected theme, based on the active domain.
        global $_domain;
        $domain_theme = domain_theme_lookup($_domain['domain_id']);

        // The above returns -1 on failure.
        $theme = $domain_theme != -1 ? $domain_theme['theme'] : $theme_key;
      }
      break;
  }
  return $theme;
}

/**
 * Implements hook_system_info_alter().
 *
 * Prevent the module from being disabled while the mail_system variable is
 * still using the MailsystemDelegateMailSystem class.
 */
function mailsystem_system_info_alter(&$info, $file, $type) {
  if ($type == 'module' && $file->name == 'mailsystem') {
    $mail_system = mailsystem_get();
    foreach ($mail_system as $key => $class) {
      if ($class == 'MailsystemDelegateMailSystem') {
        $info['required'] = TRUE;
        $info['explanation'] = t('<em>Mail System</em> cannot be disabled until each custom setting on its <a href="@url">configure page</a> is either removed, or uses the same class for both its formatting and delivery class.', array(
          '@url' => url('admin/config/system/mailsystem'),
        ));
      }
    }
  }
}

Functions

Namesort descending Description
mailsystem_clear Helps other modules safely remove their settings from mail_system.
mailsystem_defaults Returns the default settings for the mail_system variable.
mailsystem_default_id Returns the id for the default mail_system setting.
mailsystem_default_value Returns the value for the default mail_system setting.
mailsystem_delegate_set_mailsystem_settings Save settings for the delegate mail system for a given mail-id.
mailsystem_get Returns the current mail_system settings.
mailsystem_get_classes Returns a list of classes which implement MailSystemInterface.
mailsystem_get_mail_theme Retrieves the key of the theme used to render the emails.
mailsystem_menu Implements hook_menu().
mailsystem_permission Implements hook_permission().
mailsystem_read_settings Returns a list of module delegations.
mailsystem_set Helps other modules safely set their own key within mail_system.
mailsystem_system_info_alter Implements hook_system_info_alter().
mailsystem_theme_registry_alter Implements hook_theme_registry_alter().
_mailsystem_delegate_get_mailsystem Returns an MailSystemInterface class instance for a given action.
_mailsystem_get_registry_blacklist_condition Return a DatabaseCondition representing the registry-blacklist.
_mailsystem_get_registry_whitelist_condition Return a DatabaseCondition representing the registry-whitelist.