You are here

function _subscriptions_mail_cron in Subscriptions 2.0.x

Same name and namespace in other branches
  1. 6 subscriptions_mail.cron.inc \_subscriptions_mail_cron()
  2. 7 subscriptions_mail.cron.inc \_subscriptions_mail_cron()

Implementation of hook_cron().

Takes items from {subscriptions_queue} and generates notification emails.

1 call to _subscriptions_mail_cron()
subscriptions_mail_cron in subscriptions_mail/subscriptions_mail.module
Implements hook_cron().

File

subscriptions_mail/subscriptions_mail.cron.inc, line 13
Subscriptions module mail gateway (cron functions).

Code

function _subscriptions_mail_cron() {
  global $user, $language;
  _subscriptions_mail_module_load_include('templates.inc');
  $mails_allowed = variable_get('subscriptions_number_of_mails', 0);
  $from = _subscriptions_mail_site_mail();
  $single_count = $single_failed = $digest_count = $digest_failed = 0;
  $loaded_objects = array();
  $fields = array();

  // Strategy for cron:
  // Use a defined percentage of the total cron time (default: 50%), but leave at least 5s.
  $total_seconds = ini_get('max_execution_time');
  $total_seconds = empty($total_seconds) ? 240 : $total_seconds;
  $lost_seconds = timer_read('page') / 1000;
  $available_seconds = $total_seconds - $lost_seconds;
  $usable_seconds = min(array(
    $available_seconds - 5,
    $total_seconds * subscriptions_mail_get_cron_percentage() / 100,
  ));
  $watchdog = 'watchdog';

  // disable automatic translation
  $watchdog_variables = array(
    '@Subscriptions' => 'Subscriptions',
  );

  //TEST: watchdog('cron', "Subscriptions has $available_seconds of $total_seconds seconds available.");
  if ($usable_seconds <= 0) {
    $watchdog_variables += array(
      '@link' => url(SUBSCRIPTIONS_CONFIG_PATH, array(
        'fragment' => 'edit-subscriptions-cron-percent',
      )),
    );
    if ($usable_seconds == 0) {
      $watchdog('cron', t('@Subscriptions cannot send any notifications because its <a href="@link">cron job time</a> is 0!', $watchdog_variables), NULL, WATCHDOG_WARNING);
    }
    else {
      $watchdog('cron', t('@Subscriptions cannot send any notifications because the cron run has less than 5 available seconds left!', $watchdog_variables), NULL, WATCHDOG_WARNING);
    }
  }
  while ((empty($mails_allowed) || $single_count + $digest_count < $mails_allowed) && timer_read('page') / 1000 < $lost_seconds + $usable_seconds) {
    $result = db_query_range("SELECT * FROM {subscriptions_queue} WHERE suspended = 0 AND last_sent + send_interval < :time ORDER BY sqid", 0, 1, array(
      ':time' => time(),
    ));
    if (!($queue_item = $result
      ->fetchAssoc())) {
      break;

      // No more ready queue items, terminate loop.
    }
    if (!($subscriber = user_load($queue_item['uid']))) {
      $watchdog('subscriptions', t('Subscriber %uid not found.', array(
        '%uid' => $queue_item['uid'],
      )), NULL, WATCHDOG_WARNING);
      continue;
    }
    $saved_user = $user;
    $saved_language = $language;
    drupal_save_session(FALSE);

    // Clear the term cache to avoid getting a different user's set of terms.
    entity_load('taxonomy_term', array(), array(), TRUE);
    $lang_code = $language->language;
    $user = $subscriber;
    $digest_data = array(
      'subs' => array(
        'type' => 'digest',
      ),
    );
    $watchdog_variables['%user_name'] = $user->name;
    do {

      // once and repeat while adding to a digest
      $watchall = variable_get('subscriptions_watchall', 0);
      if (!$user->status) {
        if ($watchall) {
          $watchdog('subscriptions', t('Subscription of blocked user %user_name ignored.', $watchdog_variables), NULL, WATCHDOG_DEBUG);
        }
      }
      elseif (!$user->access && !variable_get('subscriptions_mail_unaccessed_users', FALSE)) {
        if ($watchall) {
          $watchdog('subscriptions', t('Subscription of never-logged-in user %user_name ignored.', $watchdog_variables), NULL, WATCHDOG_DEBUG);
        }
      }
      else {
        $queue_item['mail'] = $user->mail;

        /** @var $load_function string */
        $load_function = $queue_item['load_function'];
        $load_args = $queue_item['load_args'];
        if (!isset($loaded_objects[$user->uid][$load_function][$load_args]) && $load_function($queue_item)) {
          $object = $queue_item['object'];
          $access = module_invoke_all('subscriptions', 'access', $load_function, $load_args, $object);

          // Allow other modules to alter the data.
          drupal_alter('subscriptions_access', $access);

          // One FALSE vote is enough to deny. Also, we need a non-empty array.
          $allow = !empty($access) && array_search(FALSE, $access) === FALSE;
          if (!$allow && $watchall) {
            $watchdog('subscriptions', t("User %user_name was denied access to %load(!args).", $watchdog_variables + array(
              '%load' => $load_function,
              '!args' => filter_xss(serialize($load_args)),
            )), NULL, WATCHDOG_DEBUG);
            $watchall = FALSE;
          }
          $loaded_objects[$user->uid][$load_function][$load_args] = $allow ? $object : FALSE;
        }
        if (empty($loaded_objects[$user->uid][$load_function][$load_args])) {
          if ($watchall) {
            $watchdog('subscriptions', t('User %user_name was unable or not allowed to %load(!args).', $watchdog_variables + array(
              '%load' => $load_function,
              '!args' => filter_xss(serialize($load_args)),
            )), NULL, WATCHDOG_DEBUG);
          }
        }
        else {
          $object = $loaded_objects[$user->uid][$load_function][$load_args];
          $module = $queue_item['module'];
          $ori_field = $field = $queue_item['field'];
          $ori_value = $value = $queue_item['value'];
          if (!isset($fields[$lang_code][$module])) {
            $fields[$lang_code][$module] = module_invoke_all('subscriptions', 'fields', $module);
          }
          $data_function = $fields[$lang_code][$module][$field]['data_function'];
          $mailmod = empty($fields[$lang_code][$module][$field]['mail_module']) ? 'subscriptions_mail' : $fields[$lang_code][$module][$field]['mail_module'];
          $mailkey = $fields[$lang_code][$module][$field]['mailkey'];
          if ($mailkey_altered = module_invoke_all('subscriptions', 'mailkey_alter', $mailkey, $object, $queue_item)) {
            $mailkey = $mailkey_altered[0];
          }
          $digest = $queue_item['digest'] > 0 || $queue_item['digest'] == -1 && _subscriptions_get_setting('digest', 0) > 0;

          //$show_node_info = (isset($object->type) ? variable_get('node_submitted_' . $object->type, TRUE) : TRUE);
          $data = array(
            'subs' => array(
              'type' => $fields[$lang_code][$module][$field]['subs_type'],
              'unsubscribe_path' => "s/del/{$module}/{$ori_field}/{$ori_value}/" . $queue_item['author_uid'] . '/' . $queue_item['uid'] . '/' . md5(drupal_get_private_key() . $module . $ori_field . $ori_value . $queue_item['author_uid'] . $queue_item['uid']),
            ),
            'user' => user_load(!empty($object->revision_uid) ? $object->revision_uid : $object->uid),
          );
          $data_function($data, $object, $queue_item);
          drupal_alter('subscriptions_data', $data, $object, $queue_item);

          //mail_edit_format($values['subscriptions_comment_body'], $data + array('comment' => $comment), array('language' => $language));
          if ($digest) {
            $digest_data = subscriptions_mail_digest_add_item($digest_data, $mailmod, $mailkey, $data, $user);
            $digest_data['subs']['send_intervals'][$queue_item['send_interval']] = $queue_item['send_interval'];
          }
          else {
            _subscriptions_mail_send($mailmod, $mailkey, $queue_item['name'], $queue_item['mail'], $from, $queue_item['uid'], array(
              $queue_item['send_interval'],
            ), $data) ? ++$single_count : ++$single_failed;
          }
        }
      }
      db_delete('subscriptions_queue')
        ->condition('load_function', $queue_item['load_function'])
        ->condition('load_args', $queue_item['load_args'])
        ->condition('uid', $queue_item['uid'])
        ->execute();
      if (!empty($digest)) {

        // Get next ready queue item for this user.
        $result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE uid = :uid AND last_sent + send_interval < :send_interval ORDER BY sqid', 0, 1, array(
          ':uid' => $user->uid,
          ':send_interval' => time(),
        ));
        if (!($queue_item = $result
          ->fetchAssoc())) {
          _subscriptions_mail_send($mailmod, SUBSCRIPTIONS_DIGEST_MAILKEY, $digest_data['subs']['name'], $digest_data['subs']['mail'], $from, $digest_data['subs']['uid'], $digest_data['subs']['send_intervals'], $digest_data) ? ++$digest_count : ++$digest_failed;
          $digest = FALSE;
          $digest_data = array(
            'subs' => array(
              'type' => 'digest',
            ),
          );
        }
      }
    } while (!empty($digest));
    $user = $saved_user;
    $language = $saved_language;
    drupal_save_session(TRUE);
  }
  if (module_exists('taxonomy')) {

    // Clear the term cache again for the next cron client.
    entity_load('taxonomy_term', array(), array(), TRUE);
  }
  if ($single_count + $digest_count + $single_failed + $digest_failed > 0) {
    $current_seconds = timer_read('page') / 1000;
    $variables = $watchdog_variables + array(
      '!single_count' => $single_count,
      '!digest_count' => $digest_count,
      '!single_failed' => $single_failed,
      '!digest_failed' => $digest_failed,
      '!used_seconds' => round($current_seconds - $lost_seconds),
      '!total_seconds' => $total_seconds,
      '!remaining_items' => db_query("SELECT COUNT(*) FROM {subscriptions_queue} WHERE last_sent + send_interval < :send_interval AND suspended = 0", array(
        ':send_interval' => REQUEST_TIME,
      ))
        ->fetchField(),
      '!suspended_items' => db_query("SELECT COUNT(*) FROM {subscriptions_queue} WHERE last_sent + send_interval < :send_interval AND suspended <> 0", array(
        ':send_interval' => REQUEST_TIME,
      ))
        ->fetchField(),
      '!remaining_seconds' => round($total_seconds - $current_seconds),
      '%varname' => 'subscriptions_mail_trash_silently',
      '!cron' => 'cron',
    );
    if (variable_get('subscriptions_mail_trash_silently', 0)) {
      $message = t('@Subscriptions DISCARDED !single_count single and !digest_count digest notifications in !used_seconds of !total_seconds seconds, due to the %varname variable being set.', $variables);
    }
    elseif ($single_failed > 0 || $digest_failed > 0) {
      $message = t('@Subscriptions FAILED !single_failed single and !digest_failed digest notifications, sent !single_count single and !digest_count digest notifications in !used_seconds of !total_seconds seconds.', $variables);
    }
    else {
      $message = t('@Subscriptions sent !single_count single and !digest_count digest notifications in !used_seconds of !total_seconds seconds.', $variables);
    }
    $message .= ' ' . t('!remaining_items queue items remaining (plus !suspended_items suspended), !remaining_seconds seconds left for other !cron client modules.', $variables);
    $watchdog('cron', $message, NULL);
    _subscriptions_mail_check_baseurl(FALSE);
  }
}