You are here

party_simplenews.module in Party 8.2

Main module file for Party Simplenews integration

File

modules/party_simplenews/party_simplenews.module
View source
<?php

/**
 * @file
 * Main module file for Party Simplenews integration
 */

/**
 * Load includes
 */
module_load_include('inc', 'party_simplenews', 'party_subscription_settings.api');

/**
 * Implements hook_entity_info()
 */
function party_simplenews_entity_info() {

  // A realy simple entity so we can hang an extra field off of it and treat it as a data set
  $info['party_subscription_settings'] = array(
    'label' => 'Party Mail Subscription Settings',
    'entity class' => 'PartySubscriptionSettings',
    'controller class' => 'PartySubscriptionSettingsController',
    'base table' => 'party_subscription_settings',
    'fieldable' => TRUE,
    'entity keys' => array(
      'id' => 'subscription_settings_id',
    ),
    'module' => 'party_simplenews',
    'view modes' => array(
      'full' => array(
        'label' => t('Full'),
        'custom settings' => FALSE,
      ),
    ),
    'bundles' => array(
      'party_subscription_settings' => array(
        'label' => t('Simplenews Subscription Settings'),
        'admin' => array(
          'path' => 'admin/config/party/subscriptions',
        ),
      ),
    ),
  );
  return $info;
}

/**
 * Implements hook_entity_property_info_alter()
 */
function party_simplenews_entity_property_info_alter(&$info) {
  $properties =& $info['party']['properties'];
  $properties['primary_email'] = array(
    'label' => t('Primary Email Address'),
    'type' => 'text',
    'description' => t('The primary email address of this party'),
    'getter callback' => 'party_simplenews_party_get_properties',
  );
}

/**
 * Implements hook_party_data_set_info() {
 */
function party_simplenews_party_data_set_info() {
  $sets['subscription_settings'] = array(
    'label' => t("Subscription Settings"),
    'entity type' => 'party_subscription_settings',
    'class' => 'PartySubscriptionSettingsDataSet',
    'singleton' => TRUE,
    'max cardinality' => 1,
    'view mode' => 'party',
    'form callback' => 'party_subscription_settings_edit_form',
  );
  return $sets;
}

/**
 * Implements hook_views_api().
 */
function party_simplenews_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'party_simplenews') . '/includes/views',
  );
}

/**
 * Implements hook_form_FORM_ID_alter()
 */
function party_simplenews_form_simplenews_admin_settings_subscription_alter(&$form, &$form_state) {
  $form['party'] = array(
    '#type' => 'fieldset',
    '#title' => t('Party'),
    '#collapsible' => FALSE,
    '#weight' => -1,
  );
  $form['party']['simplenews_sync_party'] = array(
    '#type' => 'checkbox',
    '#title' => t('Synchronize with party'),
    '#default_value' => variable_get('simplenews_sync_party', TRUE),
    '#description' => t('When checked subscriptions will be synchronized with the Party. When Parties are deleted, subscriptions with the same email address will be removed. When not checked subscriptions will be unchanged when associated accounts are deleted or blocked.'),
  );
}

/**
 * Load a subscriber by party_id
 *
 * @param $pid Party
 * @param $ref The field ref of the email field. Normally takes the form
 *   DATA_SET_NAME__ENTITY_ID__FIELD_NAME__DELTA
 */
function party_simplenews_subscriber_load_by_pid($party = NULL, $ref = NULL) {
  $query = db_select('party_simplenews_subscriber', 'pss');
  $query
    ->leftJoin('simplenews_subscriber', 'ss', 'pss.snid = ss.snid');
  $query
    ->fields('ss', array(
    'snid',
  ))
    ->fields('pss', array(
    'party_id',
    'party_field_ref',
  ));
  if (!empty($party)) {
    $query
      ->condition('pss.party_id', $party);
  }
  if (!empty($ref)) {
    $query
      ->condition('pss.party_field_ref', $ref);
  }
  $extras = $query
    ->execute()
    ->fetchAllAssoc('snid');
  if (empty($extras)) {
    return FALSE;
  }
  $subscribers = simplenews_subscriber_load_multiple(array_keys($extras));
  foreach ($subscribers as $subscriber) {
    $subscriber->party_id = $extras[$subscriber->snid]->party_id;
    $subscriber->party_field_ref = $extras[$subscriber->snid]->party_field_ref;
  }
  if (!empty($ref)) {
    return $subscribers ? reset($subscribers) : FALSE;
  }
  return $subscribers ? $subscribers : FALSE;
}

/**
 * Implements hook_simplenews_subscriber_update.
 *
 * Because simplenews uses a custom query object rather than calling
 * drupal_write_record, we have to manually save our extra fields. This can
 * stay in the update hook, as our implementation of the insert hook will end
 * up calling this anyway.
 */
function party_simplenews_simplenews_subscriber_update($subscriber) {
  db_merge('party_simplenews_subscriber')
    ->key(array(
    'snid' => $subscriber->snid,
  ))
    ->fields(array(
    'party_field_ref' => $subscriber->party_field_ref,
    'party_id' => $subscriber->party_id,
  ))
    ->execute();
}

/**
 * Implements hook_simplenews_subscriber_delete().
 */
function party_simplenews_simplenews_subscriber_delete($subscriber) {
  db_delete('party_simplenews_subscriber')
    ->condition('snid', $subscriber->snid)
    ->execute();
}

/**
 * Implements hook_simplenews_subscriber_insert.
 *
 * Ensures that the subscriber record from simplenews has a reference to the
 * correct party.
 *
 * This hook gets called whenever a new subscriber record gets added to the
 * database. The information available at this point can vary.
 * - If the subscription has been made through simplenews' bulk email
 *   subscriber the subscriber may only have the 'email' property.
 * - If the subscription was made through the subscription_settings attached
 *   entity then the 'party_id' and 'party_field_ref' will be available.
 * - If the subscription was made through the user subscribing themself then
 *   'uid' property will be set.
 * These properties are described in more detail below.
 * - 'email' The email address being subscribed to the newsletter. This should
 *   always be availble.
 * - 'uid' The user id of the user being subscribed to the newsletter.
 * - 'party_id' The party id of the party being subscirbed to a newsletter.
 * - 'party_field_ref' A string that tell's party which field the email matches
 *   on the party. This allow's party module to keep the subscription up to
 *   date if the email changes.
 * Once a suitable party has been found for the subscriber, the party_id and
 * party_field_ref are stored in the party_simplenews_subscriber table (see
 * party_simplenews_simplenews_subscriber_update). A subscription settings
 * entity is also attached to the party.
 */
function party_simplenews_simplenews_subscriber_insert($subscriber) {

  // If the party and field_ref is set save them into the
  // party_simplenews_subscriber table and add a subscriptions_settings
  // attached entity (if one does not already exist.
  // @todo: we don't add the party's user to the subscriber record for now as:
  //   1 - multiple user subscriptions may cause problems for simplenews
  //   2 - this may have potential security risks?
  if (!empty($subscriber->party_id) && !empty($subscriber->party_field_ref)) {
    simplenews_subscriber_save($subscriber);
    $party = party_load($subscriber->party_id);
    party_simplenews_add_subsciption_settings_attached_entity($party);
    return;
  }

  // Firstly, if the account id is not 0 and the party_user module is enabled,
  // see if that user has a party and attach it. This avoids the potential
  // security hole above as the party and user are already connected.
  if (module_exists('party_user') && $subscriber->uid != 0) {
    $party = party_user_get_party($subscriber->uid);

    // Define a standard field ref for the user email property.
    $field_ref = 'user__0__mail__0';

    // Set the party and field ref on the simplenews_subscriber record and
    // save. See party_simplenews_simplenews_subscriber_update.
    $subscriber->party_id = $party->pid;
    $subscriber->party_field_ref = $field_ref;
    simplenews_subscriber_save($subscriber);

    // Create the subscription_settings attached entity.
    party_simplenews_add_subsciption_settings_attached_entity($party);
    return;
  }

  // At this point we know we don't have enough information to make an easy
  // link to the correct party, so we try an sniff one out using the email
  // provided.
  // This shouldn't have security issues as we don't link user accounts to
  // parties based on this information.
  // Get a list of all email fields.
  $fields = party_get_email_fields();

  // Iterate over email fields and use an EFQ to try and find entities that
  // match the email we've been provided with.
  $found = FALSE;
  foreach ($fields as $data_set_name => $fields) {
    $definition = party_get_data_set_info($data_set_name);
    $entity_type = $definition['entity type'];
    $bundle = $definition['entity bundle'];
    foreach ($fields as $field_name) {
      $query = new EntityFieldQuery();
      $entities = $query
        ->entityCondition('entity_type', $entity_type)
        ->entityCondition('bundle', $bundle)
        ->fieldCondition($field_name, 'email', $subscriber->mail)
        ->execute();

      // If we don't find an entity with this email address on it, skip the
      // rest.
      if (empty($entities[$entity_type])) {
        continue;
      }

      // The output of EFQ::execute are stub entities keyed by entity_id so we
      // can get the entity_id like this:
      $entity_id = reset(array_keys($entities[$entity_type]));

      // Now we need to find the party id. This code is taken from
      // party_user_get_party
      $result = db_select('party_attached_entity', 'pae')
        ->fields('pae', array(
        'pid',
      ))
        ->condition('eid', $entity_id, '=')
        ->condition('data_set', $data_set_name)
        ->execute()
        ->fetchCol();
      $party_id = reset($result);

      // If we don't find a party keep looking.
      if (!$party_id) {
        continue;
      }

      // We've found a party, so lets save everything
      // Here we're assuming that the delta of the field is 0.
      // @todo: don't assume the delta is 0
      $subscriber->party_id = $party_id;
      $subscriber->party_field_ref = $data_set_name . '__' . $entity_id . '__' . $field_name . '__0';
      simplenews_subscriber_save($subscriber);
      party_simplenews_add_subsciption_settings_attached_entity(party_load($party_id));
      $found = TRUE;
      break;
    }
    if ($found) {
      break;
    }
  }
}

/**
 * Implements hook_entity_update.
 */
function party_simplenews_entity_update($entity, $type) {

  // Get necessary entity info.
  $wrapper = entity_metadata_wrapper($type, $entity);

  // Get data sets.
  $data_sets = party_get_data_set_info();

  // Is this entity party of a data set?
  $data_set_name = FALSE;
  foreach ($data_sets as $name => $def) {
    if ($def['entity type'] == $type && $def['entity bundle'] == $wrapper
      ->getBundle()) {
      $data_set_name = $name;
      break;
    }
  }

  // If it's not part of a data set do nothing else
  if (!$data_set_name) {
    return;
  }

  // Iterate over email fields on this data set
  foreach (party_get_email_fields($data_set_name) as $field_name) {

    // Get the items for this field.
    $items = field_get_items($type, $entity, $field_name);
    foreach ($items as $delta => $item) {

      // Get the subscriber with the right party_field_ref. Note, at the moment the
      // party_field_ref has the attached entity id in it, so we don't need to
      // check the party_id.
      $ref = $data_set_name . '__' . $wrapper
        ->getIdentifier() . '__' . $field_name . '__' . $delta;
      $subscriber = party_simplenews_subscriber_load_by_pid(NULL, $ref);
      if ($subscriber) {
        $subscriber->mail = $item['email'];
        simplenews_subscriber_save($subscriber);
      }
    }
  }
}

/**
 * Implements hook_entity_delete()
 */
function party_simplenews_entity_delete($entity, $type) {
  if ($type == 'party') {
    $subscribers = party_simplenews_subscriber_load_by_pid($entity->pid);
    if (!$subscribers) {
      return;
    }
    foreach ($subscribers as $subscriber) {
      simplenews_subscriber_delete($subscriber);
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter.
 */
function party_simplenews_form_simplenews_admin_subscription_alter(&$form, &$form_state) {
  $table =& $form['admin']['subscribers'];
  $new_header = array();
  foreach ($table['#header'] as $key => $array) {
    $new_header[$key] = $array;
    if ($key == 'username') {
      $new_header['party'] = array(
        'data' => 'Party',
        'field' => 'sn.party_id',
      );
    }
  }
  $table['#header'] = $new_header;

  // Do a query to get the party ID's from the table
  $query = db_select('party_simplenews_subscriber', 'sn');
  $query
    ->leftJoin('party', 'p', 'sn.party_id = p.pid');
  $party_ids = $query
    ->fields('sn', array(
    'snid',
    'party_id',
  ))
    ->fields('p', array(
    'label',
  ))
    ->execute()
    ->fetchAllAssoc('snid', PDO::FETCH_ASSOC);
  foreach ($table['#options'] as $key => $row) {

    //$party = party_load($party_ids[$key]['party_id']);
    if (!empty($party_ids[$key])) {
      $row['party'] = l($party_ids[$key]['label'], 'party/' . $party_ids[$key]['party_id']);
    }
    else {
      $row['party'] = '';
    }
    $table['#options'][$key] = $row;
  }
}

/**
 * Get all the email fields set up on data set entities
 *
 * @param $data_set_name If this is set, the function will return a list of
 *   email fields on that data set.
 *
 * @todo:
 *  - Drupal Cache
 *  - Put in a standard party_mail api.
 */
function party_get_email_fields($data_set_name = NULL) {
  $email_fields =& drupal_static(__FUNCTION__, array());

  // If we have a cached set of fields, return this.
  if (!empty($email_fields)) {
    if (!empty($data_set_name)) {
      return empty($email_fields[$data_set_name]) ? array() : $email_fields[$data_set_name];
    }
    return $email_fields;
  }
  $fields = field_info_fields();
  $data_sets = party_get_data_set_info();
  foreach ($fields as $field_name => $field) {

    // Is it an email field?
    if ($field['type'] != 'email') {
      continue;
    }

    // Is it on an attached entity?
    foreach ($field['bundles'] as $entity_type => $bundles) {
      foreach ($bundles as $bundle) {
        foreach ($data_sets as $name => $def) {
          if ($def['entity type'] == $entity_type && $def['entity bundle'] == $bundle) {

            // Put it in an array keyed by data set name and field name
            $email_fields[$name][] = $field_name;
          }
        }
      }
    }
  }
  if (!empty($data_set_name)) {
    return empty($email_fields[$data_set_name]) ? array() : $email_fields[$data_set_name];
  }
  return $email_fields;
}

/**
 * Get all the emails on a Party
 *
 * @param $party an party object
 *
 * @return
 *   An array of emails keyed by field reference
 *
 * @todo: build in special case for user mail
 */
function party_get_all_emails($party) {
  $fields = party_get_email_fields();
  $emails = array();
  foreach ($fields as $data_set_name => $fields) {
    $data_set_controller = party_get_data_set($party, $data_set_name);
    $data_set_def = party_get_data_set_info($data_set_name);
    $entity_ids = $data_set_controller
      ->getEntityIds();
    foreach ($data_set_controller
      ->getEntities() as $data_set_delta => $entity) {
      foreach ($fields as $field_name) {
        $items = field_get_items($data_set_def['entity type'], $entity, $field_name);
        if (!$items) {
          continue;
        }
        foreach ($items as $delta => $item) {
          $field_ref = $data_set_name . '__' . $entity_ids[$data_set_delta] . '__' . $field_name . '__' . $delta;
          $emails[$field_ref] = $item['email'];
        }
      }
    }
  }
  return $emails;
}

/**
 * Implements hook_field_extra_fields().
 */
function party_simplenews_field_extra_fields() {
  $return['party_subscription_settings']['party_subscription_settings'] = array(
    'display' => array(
      'subscriptions' => array(
        'label' => 'Newsletters',
        'description' => t('Newsletter subscriptions of the party'),
        'weight' => 5,
      ),
    ),
  );
  return $return;
}

/**
 * Implements hook_party_subscription_settings_view()
 */
function party_simplenews_party_subscription_settings_view($entity) {
  $party = party_subscription_settings_get_party($entity);
  $entity->content['subscriptions'] = array(
    '#type' => 'fieldset',
    '#title' => t('Newsletters'),
  );

  // Collect newsletter to which the current user is subscribed.
  // 'hidden' newsletters are not listed.
  $newsletters = simplenews_category_get_visible();
  $subscribers = party_simplenews_subscriber_load_by_pid($party->pid);

  // For each newsletter, ascertain if the party is subscribed to it
  foreach ($newsletters as $newsletter) {
    $subscribed_emails = array();

    // In theory, a Party could be subscribed to a newsletter multiple times,
    // Iterate over all the party's subscribers and check if they're subscribed to
    // the newsletter.
    foreach ($subscribers as $subscriber) {
      if (isset($subscriber->newsletter_subscription[$newsletter->tid]) && $subscriber->newsletter_subscription[$newsletter->tid]->status == TRUE) {
        $subscribed_emails[] = $subscriber->mail;
      }
    }

    // If atleast one of the party's addresses is subscribed to the newsletter
    // add the newsletter to the list of links with a list of subscribed emails
    // next to it.
    if (!empty($subscribed_emails)) {
      $emails = ' <small>(' . implode($subscribed_emails, ',') . ')</small>';
      $links[] = l(_simplenews_newsletter_name($newsletter), 'taxonomy/term/' . $newsletter->tid) . $emails;
    }
  }
  if (empty($links)) {
    $entity->content['subscriptions']['subscriptions'] = array(
      '#title' => t('Subscribed to'),
      '#markup' => t('None'),
    );
  }
  else {
    $entity->content['subscriptions']['subscriptions'] = array(
      '#theme' => 'item_list',
      '#type' => 'item_list',
      '#title' => t('Subscribed to'),
      '#items' => $links,
    );
  }
}
class PartySubscriptionSettingsDataSet extends PartyDefaultDataSet {
  public function getLabel() {
    return 'Newsletters';
  }

}

/**
 * Get email related properties
 */
function party_simplenews_party_get_properties($party, array $options, $name, $entity_type) {
  switch ($name) {
    case 'primary_email':
      return reset(party_get_all_emails($party));
  }
}

Functions

Namesort descending Description
party_get_all_emails Get all the emails on a Party
party_get_email_fields Get all the email fields set up on data set entities
party_simplenews_entity_delete Implements hook_entity_delete()
party_simplenews_entity_info Implements hook_entity_info()
party_simplenews_entity_property_info_alter Implements hook_entity_property_info_alter()
party_simplenews_entity_update Implements hook_entity_update.
party_simplenews_field_extra_fields Implements hook_field_extra_fields().
party_simplenews_form_simplenews_admin_settings_subscription_alter Implements hook_form_FORM_ID_alter()
party_simplenews_form_simplenews_admin_subscription_alter Implements hook_form_FORM_ID_alter.
party_simplenews_party_data_set_info Implements hook_party_data_set_info() {
party_simplenews_party_get_properties Get email related properties
party_simplenews_party_subscription_settings_view Implements hook_party_subscription_settings_view()
party_simplenews_simplenews_subscriber_delete Implements hook_simplenews_subscriber_delete().
party_simplenews_simplenews_subscriber_insert Implements hook_simplenews_subscriber_insert.
party_simplenews_simplenews_subscriber_update Implements hook_simplenews_subscriber_update.
party_simplenews_subscriber_load_by_pid Load a subscriber by party_id
party_simplenews_views_api Implements hook_views_api().

Classes