You are here

messaging_method.class.inc in Messaging 6.3

Drupal Messaging Framework - Send_Method class file

File

classes/messaging_method.class.inc
View source
<?php

/**
 * @file
 * Drupal Messaging Framework - Send_Method class file
 */

/**
 * Sending method, implements all specific method functionality
 * 
 * Old callback functions are
 * - send
 * - destination
 */
class Messaging_Send_Method {

  // Method key
  public $method;

  // Full info array
  public $info;
  function __construct($info, $method) {
    $this->method = $method;
    $this->info = $info;
  }
  function get_info($property = NULL) {
    if ($property) {
      return isset($this->info[$property]) ? $this->info[$property] : NULL;
    }
    else {
      return $this->info;
    }
  }

  /**
   * Send message to destination by calling the method's send callback
   */
  function send($destination, $message) {

    // Translate destination object to old fashion parameters
    $callback = $this
      ->get_callback('send');
    $params = $message
      ->get_params($this->method);
    return $this
      ->callback_invoke($callback, $destination, $message, $params);
  }

  /**
   * Send a message to multiple destinations
   *
   * @param $source
   *   Message or message template
   * @param $destinations
   *   Array of destinations for this method
   */
  function send_multiple($source, $destinations) {
    $result = array();
    $template = $source
      ->build($this->method, NULL);
    $template->destinations = $destinations;
    $template
      ->prepare();
    $template
      ->render();
    foreach ($destinations as $index => $destination) {
      $message = clone $template;
      $message->destination = $destination;
      $result[$index] = $message
        ->send();
    }
    return $result;
  }

  /**
   * Queue multiple copies of the same message
   *
   * @param $source
   *   Message or message template
   * @param $destinations
   *   Array of destinations for this method
   */
  function queue_multiple($source, $destinations) {
    $result = array();
    $template = $source
      ->build($this->method, NULL);
    $template->destinations = $destinations;
    $template
      ->prepare();
    $template->queue = 1;
    $template
      ->render();
    foreach ($destinations as $index => $destination) {
      $message = clone $template;
      $message->destination = $destination;
      $result[$index] = $message
        ->queue();
    }
    return $result;
  }

  /**
   * Get destination for user
   */
  function user_destination($account) {
    if (($property = $this->destination) && !empty($account->{$property})) {

      // Get destination property from user account
      return $account->{$property};
    }
    elseif ($callback = $this
      ->get_callback('destination')) {

      // Backwards compatibility, call destination callback
      return $this
        ->callback_invoke($callback, $account);
    }
  }

  /**
   * Check user availability
   */

  /**
   * Get default sender
   */
  function get_default_sender() {
    return array(
      'name' => variable_get('site_name', 'Drupal'),
      'from' => '',
    );
  }

  /**
   * Prepare message for processing with this method
   */
  function message_prepare($message) {

    // If the messaging method is of type push, cron processing will be enabled
    if ($message->queue && $this->type & MESSAGING_TYPE_PUSH) {
      $this->cron = 1;
    }

    // It will be queued always for pull methods, cron disabled though, so it will wait till it's pulled
    if (!$message->queue && $this->type & MESSAGING_TYPE_PULL) {
      $message->queue = 1;
      $message->cron = 0;
    }
  }

  /**
   * Check destination, user availability, etc...
   *
   * At this stage it is still possible to redirect to other sending method with $message->redirect = TRUE
   */
  function message_check($message) {
  }

  /**
   * Run before sending prepared message
   */
  function message_presend($message) {
  }

  /**
   * Send a message to a single destination
   */
  function message_send($message) {
    $message
      ->prepare();
    $message
      ->render();
    return $this
      ->send($message->destination, $message);
  }

  /**
   * Queue the message
   */
  function message_queue($message) {
    $message->result = TRUE;
    $message->queue = 1;
    $message
      ->save();
    return $message->result;
  }

  /**
   * Test message sending
   */
  function message_test($message) {
    $message
      ->log('Emulating message sending (test run)', array(
      'message' => (string) $message,
    ));
  }

  /**
   * Run after sending message
   */
  function message_aftersend($message) {

    // Depending on parameters and what's happened so far we make the final queue/log decision
    if ($message->queue || $message->log) {
      $message
        ->store();
    }
  }

  /**
   * Run after message has been queued
   */
  function message_afterqueue($message) {
  }

  /**
   * Render a template object
   *
   * It builds subject and body properties
   */
  function message_render($template) {
    $info = $this->info + array(
      'glue' => ' ',
      'filter' => NULL,
    );

    // Render body if anything to render
    if ($body = $template->body) {

      // Apply footer prefix if provided and the message has a footer element.
      // Note: If $body is a string the final isset($body['footer']) will be true
      if (is_array($body) && !empty($info['footer']) && isset($body['footer'])) {
        $body['footer_prefix'] = $info['footer'];
        $body['footer_text'] = $body['footer'];
        unset($body['footer']);
      }
      $template->body = $this
        ->render_text($body, $info['glue'], $info['filter']);
    }

    // Render subject if anything to render
    if ($subject = $template->subject) {

      // Render separately subject and body info, adding default parameters
      $info += array(
        'subject_glue' => ' ',
      );
      $template->subject = $this
        ->check_subject($this
        ->render_text($subject, $info['subject_glue']));
    }
    return $template;
  }

  /**
   * Composes message from different parts, recursively and applies filter
   *
   * Filter is applied now only once
   *
   * @param $text
   *   Simple string or array of message parts
   *   It may have named elements like #prefix and #text
   *   or it may be single strings to render straight forward
   * @param $glue
   *   Text to glue all lines together
   * @param $filter
   *   Input format to apply to the results
   */
  function render_text($text, $glue, $filter = NULL) {
    if (!$text) {
      return '';
    }
    elseif (is_array($text)) {
      $elements = array();

      // First render children recursively, without filtering
      foreach (element_children($text) as $key) {
        $elements[$key] = $this
          ->render_text($text[$key], $glue);
      }

      // Apply theme if set, just implode if not
      if (!empty($text['#theme'])) {
        $output = theme($text['#theme'], $text, $glue);
      }
      else {
        $output = implode($glue, $elements);
      }
    }
    else {
      $output = $text;
    }

    // The filter is applied now only once
    if ($filter) {
      $output = check_markup($output, $filter, FALSE);
    }
    return $output;
  }

  /**
   * Converts strings to plain utf-8 single line
   */
  static function check_subject($text) {
    $text = messaging_check_plain($text);

    // taken from _sanitizeHeaders() in PEAR mail() : http://pear.php.net/package/Mail
    $text = preg_replace('=((0x0A/%0A|0x0D/%0D|\\n|\\r)\\S).*=i', NULL, $text);
    return $text;
  }

  /**
   * Implement for testing
   */
  function test($destination, $message) {
    return TRUE;
  }

  /**
   * Magic function, getting non existent properties
   */
  public function __get($name) {
    if (isset($this->info[$name])) {
      return $this->info[$name];
    }
  }

  /**
   * Magic function, invoking non existent methods
   *
   * For backwards compatibility with old array callbacks
   */
  public function __call($name, $arguments) {

    // If we have an old style callback like this, go for it
    if ($callback = $this
      ->get_callback($name)) {
      if (is_array($callback)) {

        // It is an array: function, arg1, arg2...
        $function = array_shift($callback);
        $arguments = array_unshift($callback, $arguments);
      }
      else {

        // It is just a function name
        $function = $callback;
      }
      return call_user_func_array($function, $params);
    }
  }

  /**
   * Get callback from method info
   */
  public function get_callback($type) {
    return $this
      ->get_info($type . ' callback');
  }

  /**
   * Invoke callback with a variable number of arguments
   */
  public function callback_invoke() {
    $args = func_get_args();
    $callback = array_shift($args);
    if (is_array($callback)) {

      // It is an array: function, arg1, arg2...
      $function = array_shift($callback);
      $params = $callback;
    }
    else {

      // It is just a function name
      $function = $callback;
      $params = array();
    }

    // Merge parameters and go for it
    $params = array_merge($params, $args);
    return call_user_func_array($function, $params);
  }

}

/**
 * Base class for mail sending methods
 */
class Messaging_Mail_Method extends Messaging_Send_Method {
  public $default_from;
  function __construct($info, $method) {
    parent::__construct($info, $method);
    $this->default_from = variable_get('site_mail', ini_get('sendmail_from'));
  }
  function get_default_sender() {
    return array(
      'name' => variable_get('site_name', 'Drupal'),
      'from' => $this->default_from,
    );
  }

  /**
   * Rebuild message in Drupal mail format
   * @param $message
   *   Message object
   */
  function message_prepare($message) {
    if (empty($message->params['from'])) {
      if (!empty($message->sender_account) && !empty($message->sender_account->mail)) {
        $from = check_plain($message->sender_account->name) . ' <' . $message->sender_account->mail . '>';
      }
      elseif (!empty($message->sender_name) && $default_from) {
        $from = check_plain($message->sender_name) . ' <' . $this->default_from . '>';
      }
      else {
        $from = $this->default_from;
      }
      $message->params['from'] = $from;
    }
    $message->params['mail_headers'] = $this
      ->mail_headers($message);
  }

  /**
   * Get mail headers. Helper function for mail methods
   */
  function mail_headers($message) {
    $headers = !empty($message->params['headers']) ? $message->params['headers'] : array();

    // Add some default headers
    $headers += array(
      'MIME-Version' => '1.0',
      'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
      'Content-Transfer-Encoding' => '8Bit',
      'X-Mailer' => 'Drupal',
    );
    $from = !empty($message->params['from']) ? $message->params['from'] : $this->default_from;

    // Set default headers depending on data
    $headers += array(
      'From' => $from,
      'Reply-To' => $from,
    );
    if ($this->default_from) {

      // To prevent e-mail from looking like spam, the addresses in the Sender and
      // Return-Path headers should have a domain authorized to use the originating
      // SMTP server. Errors-To is redundant, but shouldn't hurt.
      $more_headers['Sender'] = $more_headers['Return-Path'] = $more_headers['Errors-To'] = $this->default_from;
      $headers += $more_headers;
    }
    return $headers;
  }

  /**
   * Message ready for sending, invoke mail alter
   */
  function message_presend($message) {
    $mail = array(
      'id' => 'messaging_' . (!empty($message->type) ? 'message-' . $message->type : 'message'),
      'to' => $message->destination,
      'from' => $message->params['from'],
      'language' => $message
        ->get_language(),
      'params' => $message->params,
      'subject' => $message->subject,
      'body' => $message->body,
      'headers' => $message->params['mail_headers'],
      'attachments' => !empty($message->files) ? $message->files : array(),
    );

    // Invoke hook_mail_alter()
    drupal_alter('mail', $mail);

    // Rebuild message with results
    $message->destination = $mail['to'];
    $message->params = $mail['params'];
    $message->params['from'] = $mail['from'];
    $message->params['mail_headers'] = $mail['headers'];
    $message->subject = $mail['subject'];
    $message->body = $mail['body'];

    // Other parts are not suppossed to change, like language, files
  }

}

Classes

Namesort descending Description
Messaging_Mail_Method Base class for mail sending methods
Messaging_Send_Method Sending method, implements all specific method functionality