You are here

CampaignMonitorSubscriptionManager.php in Campaign Monitor 8.2

File

src/CampaignMonitorSubscriptionManager.php
View source
<?php

namespace Drupal\campaignmonitor;

use Drupal\Component\Utility\HTML;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Utility\Token;

/**
 * Manager for Campaignmonitor subscriptions.
 */
class CampaignMonitorSubscriptionManager extends CampaignMonitorManager {
  use StringTranslationTrait;

  /**
   * The campaignmonitor manager.
   *
   * @var \Drupal\campaignmonitor\CampaignMonitorManager
   */
  protected $campaignMonitorManager;

  /**
   * Drupal\Core\Config\ConfigFactoryInterface definition.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * The module manager service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $account;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The token replacement instance.
   *
   * @var \Drupal\Core\Utility\Token
   */
  protected $token;

  /**
   * The constructor.
   *
   * @param \Drupal\campaignmonitor\CampaignMonitorManager $campaignmonitor_manager
   *   The campaign monitor manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module manager service.
   * @param \Drupal\Core\Session\AccountProxyInterface $account
   *   The current user.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   * @param \Drupal\Core\Utility\Token $token
   *   The token replacement instance.
   */
  public function __construct(CampaignMonitorManager $campaignmonitor_manager, ConfigFactoryInterface $config_factory, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, AccountProxyInterface $account, EntityTypeManagerInterface $entity_type_manager, MessengerInterface $messenger, Token $token) {
    $this->campaignMonitorManager = $campaignmonitor_manager;
    $this->languageManager = $language_manager;
    $this->moduleHandler = $module_handler;
    $this->configFactory = $config_factory;

    // Get account information.
    $this->config = $config_factory
      ->get('campaignmonitor.settings');
    $this->account = $account;
    $this->entityTypeManager = $entity_type_manager;
    $this->messenger = $messenger;
    $this->token = $token;
  }

  /**
   * Obtain the form elements required for subscription.
   *
   * This resides here so that it can be used by both:
   * The subscription form and registration form.
   */
  public function singleSubscribeForm($config, $email = '') {
    $list_id = $config['list_id'];
    $list = $this->campaignMonitorManager
      ->getExtendedList($list_id);
    $list_options = $this->campaignMonitorManager
      ->getListSettings($list_id);

    // Set options for the form.
    $form = [
      '#tree' => TRUE,
      '#attributes' => [
        'class' => [
          'campaignmonitor-subscribe-form',
          'campaignmonitor-subscribe-form-' . str_replace(' ', '-', strtolower($list['name'])),
        ],
      ],
    ];
    if ($config['list_id_text'] != '') {
      $text = str_replace('@name', $list['name'], $config['list_id_text']);
      $form['explanation'] = [
        '#type' => 'container',
        '#markup' => $text,
      ];
    }

    // Token replace if the token module is present.
    if (isset($list_options['tokens']['name']) && $this->moduleHandler
      ->moduleExists('token') && $this->account
      ->id() > 0) {
      $name = $this->token
        ->replace($list_options['tokens']['name'], [
        'user' => $this->entityTypeManager
          ->getStorage('user')
          ->load($this->account
          ->id()),
      ], [
        'clear' => TRUE,
      ]);
    }

    // Check if the user is subscribed and get name from Campaign Monitor.
    if (!empty($email) && $this->campaignMonitorManager
      ->isSubscribed($list_id, $email)) {

      // If subscribed, get user name from Campaign Monitor.
      $subscriber = $this->campaignMonitorManager
        ->getSubscriber($list_id, $email);
      $name = isset($subscriber['Name']) ? $subscriber['Name'] : $name;
    }

    // Should the name field be displayed for this user.
    if (isset($list_options['display']['name']) && $list_options['display']['name']) {
      $form['name'] = [
        '#type' => 'textfield',
        '#title' => $this
          ->t('Name'),
        '#required' => TRUE,
        '#maxlength' => 200,
        '#default_value' => isset($name) ? $name : '',
      ];
    }

    // Get the order correct.
    if (isset($list_options['CustomFields'])) {
      $new_list = [];
      foreach ($list_options['CustomFields'] as $key => $values) {
        $new_list['CustomFields'][$key] = $list['CustomFields']['[' . $key . ']'];
      }
      $list = $new_list;
    }
    if (isset($list['CustomFields'])) {
      foreach ($list['CustomFields'] as $key => $field) {

        // Form API can't handle keys with [] in all cases.
        $form_key = str_replace([
          '[',
          ']',
        ], '', $key);

        // Check if field should be displayed.
        if (isset($list_options['CustomFields']) && !$list_options['CustomFields'][$form_key]['selected']) {

          // Field is not selected, so continue.
          continue;
        }

        // Token replace default value, if the token module is present.
        $token = '';
        if ($this->moduleHandler
          ->moduleExists('token') && isset($list_options['tokens'][$form_key])) {
          $token_user = $this->account
            ->id() > 0 ? $this->entityTypeManager
            ->getStorage('user')
            ->load($this->account
            ->id()) : NULL;
          $token = $this->token
            ->replace($list_options['tokens'][$form_key], [
            'user' => $token_user,
          ], [
            'clear' => TRUE,
          ]);
        }
        switch ($field['DataType']) {
          case 'Text':
            $form['CustomFields'][$form_key] = [
              '#type' => 'textfield',
              '#title' => HTML::escape($field['FieldName']),
              '#maxlength' => 200,
              '#default_value' => isset($subscriber['CustomFields'][$field['FieldName']]) ? $subscriber['CustomFields'][$field['FieldName']] : $token,
            ];
            break;
          case 'MultiSelectOne':
            $options = [];
            foreach ($field['FieldOptions'] as $option) {
              $options[$option] = $option;
            }
            $form['CustomFields'][$form_key] = [
              '#type' => 'select',
              '#title' => HTML::escape($field['FieldName']),
              '#options' => $options,
              '#default_value' => isset($subscriber['CustomFields'][$field['FieldName']]) ? $subscriber['CustomFields'][$field['FieldName']] : $token,
            ];
            break;
          case 'MultiSelectMany':
            $options = [];
            foreach ($field['FieldOptions'] as $option) {
              $options[$option] = $option;
            }

            // If one value was selected, default is a string else an array.
            $cm_default = isset($subscriber['CustomFields'][$field['FieldName']]) ? $subscriber['CustomFields'][$field['FieldName']] : [];

            // Expensive.
            $is_array = is_array($cm_default);
            $default = [];
            foreach ($options as $value) {
              if ($is_array) {
                if (in_array($value, $cm_default)) {
                  $default[$value] = $value;
                }
              }
              elseif ($cm_default == $value) {
                $default[$cm_default] = $cm_default;
              }
              else {
                $default[$value] = 0;
              }
            }
            $form['CustomFields'][$form_key] = [
              '#type' => 'checkboxes',
              '#title' => HTML::escape($field['FieldName']),
              '#options' => $options,
              '#default_value' => $default,
            ];
            break;
          case 'Number':
            $form['CustomFields'][$form_key] = [
              '#type' => 'textfield',
              '#title' => HTML::escape($field['FieldName']),
              '#default_value' => isset($subscriber['CustomFields'][$field['FieldName']]) ? $subscriber['CustomFields'][$field['FieldName']] : $token,
            ];
            break;
          case 'Date':
            $form['CustomFields'][$form_key] = [
              '#type' => 'date',
              '#title' => HTML::escape($field['FieldName']),
              '#default_value' => isset($subscriber['CustomFields'][$field['FieldName']]) ? $subscriber['CustomFields'][$field['FieldName']] : $token,
              '#attributes' => [
                'class' => [
                  'campaignmonitor-date',
                ],
                'type' => 'date',
              ],
            ];
            break;
        }
        if ($list_options['CustomFields'][$form_key]['required']) {
          $form['CustomFields'][$form_key]['#required'] = TRUE;
        }
      }
    }
    $form['list_id'] = [
      '#type' => 'hidden',
      '#default_value' => $list_id,
    ];
    return $form;
  }

  /**
   * Shared handler for submitting subscriptions.
   */
  public function subscribeSubmitHandler(array &$form, FormStateInterface $form_state) {
    $lists = $this->campaignMonitorManager
      ->getLists();
    $values = $form_state
      ->getValues();
    $config = $form_state
      ->getValue('config');
    $config = unserialize($config);
    switch ($config['list']) {
      case 'single':
        $selection = [
          $form_state
            ->getValue('list_id'),
        ];
        break;
      default:
        $selection = $form_state
          ->getValue('selection');
    }
    $custom_fields = isset($values['CustomFields']) ? $values['CustomFields'] : NULL;
    $name = isset($values['name']) ? HTML::escape($values['name'])
      ->__toString() : NULL;

    // The key 'mail' corresponds with user registration.
    $email = HTML::escape($values['mail'])
      ->__toString();
    foreach ($selection as $list_id) {
      if ($list_id === 0) {
        continue;
      }
      if ($this
        ->userSubscribe($list_id, $email, $name, $custom_fields)) {
        if (isset($custom_fields['Interests'])) {
          foreach ($custom_fields['Interests'] as $key => $interest) {
            if ($interest === 0) {
              unset($custom_fields['Interests'][$key]);
            }
          }
        }
        $message = $this->config
          ->get('subscription_confirmation_text') ? $this->config
          ->get('subscription_confirmation_text') : 'You are subscribed to the @name list.';
        $this->messenger
          ->addStatus($this
          ->t($message, [
          '@name' => html_entity_decode($lists[$list_id]['name']),
          '@interests' => implode(', ', $custom_fields['Interests']),
        ]));
      }
      else {
        $this->messenger
          ->addStatus($this
          ->t('You were not subscribed to the list, please try again.'));
      }
    }
  }

  /**
   * Returns fields required for subscription form settings.
   *
   * Used by subscribe block, registration form / user form.
   */
  public function subscribeSettingsForm($config) {
    $lists = $this->campaignMonitorManager
      ->getLists();
    $list_options = [];
    foreach ($lists as $list_id => $list) {
      if ($this->campaignMonitorManager
        ->isListEnabled($list_id)) {
        $list_options[$list_id] = $list['name'];
      }
    }

    // A subscribe block can be for a particular list
    // Or can provide a choice of lists.
    $subscription_options = [
      'single' => $this
        ->t('Single List'),
      'user_select' => $this
        ->t('User selects list(s)'),
    ];
    $form['lists'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('List Settings'),
    ];
    $form['lists']['list'] = [
      '#type' => 'radios',
      '#options' => $subscription_options,
      '#title' => $this
        ->t('Subscription type'),
      '#description' => $this
        ->t('Single list provides a block where the user subscribes to the list you nominate.
      User select list provides a block with checkboxes for the user to choose from. Segments enables one list from which segments are available.'),
      '#default_value' => isset($config['list']) ? $config['list'] : [],
      '#attributes' => [
        'class' => [
          'list-radios',
        ],
      ],
      '#required' => TRUE,
    ];
    $form['lists']['list_id'] = [
      '#type' => 'radios',
      '#options' => $list_options,
      '#title' => $this
        ->t('List'),
      '#description' => $this
        ->t('Choose the list for this subscribe block.'),
      '#default_value' => isset($config['list_id']) ? $config['list_id'] : '',
      '#states' => [
        'visible' => [
          '.list-radios' => [
            'value' => 'single',
          ],
        ],
      ],
    ];
    $form['lists']['list_id_text'] = [
      '#type' => 'textarea',
      '#title' => $this
        ->t('Text'),
      '#description' => $this
        ->t('The text to accompany the subscribe block. Leave blank to provide no text. Token
      available: @name = list name.'),
      '#default_value' => isset($config['list_id_text']) ? $config['list_id_text'] : 'Subscribe to the @name list',
      '#states' => [
        'visible' => [
          '.list-radios' => [
            'value' => 'single',
          ],
        ],
      ],
    ];
    return $form;
  }

  /**
   * Subscribe user to CM list in real time or by adding to the queue.
   */
  public function userSubscribe($list_id, $email, $submitted_name, $merge_vars = [], $interests = [], $double_optin = FALSE, $format = 'html') {
    if (empty($submitted_name)) {

      // Load the user object.
      $account = $this->entityTypeManager
        ->getStorage('user')
        ->load($this->account
        ->id());
      $settings = $this->campaignMonitorManager
        ->getListSettings($list_id);
      $fname = $settings['display']['fname_field'];
      $lname = $settings['display']['lname_field'];
      $fields = [
        $fname,
        $lname,
      ];
      $name = [];
      foreach ($fields as $field) {
        if (isset($field) && is_string($field) && $field != '') {
          if ($account
            ->hasField($field)) {
            $value = $account
              ->get($field)
              ->getValue();
            if (isset($value[0]['value']) && $value[0]['value'] != '') {
              $name[] = $account
                ->get($field)
                ->getValue()[0]['value'];
            }
          }
          else {

            // Likely a custom field.
            foreach ($merge_vars as $key => $var) {
              if ($field == $key) {
                $name[] = $var;
              }
            }
          }
        }
      }
      $name = implode(' ', $name);
    }
    else {
      $name = $submitted_name;
    }
    if ($this->config
      ->get('cron')) {
      $args = [
        'list_id' => $list_id,
        'email' => $email,
        'merge_vars' => $merge_vars,
        'interests' => $interests,
        'double_optin' => $double_optin,
        'format' => $format,
      ];
      return $this
        ->addtoQueue('campaignmonitor_subscribe_process', $args);
    }
    return $this
      ->subscribeProcess($list_id, $email, $name, $merge_vars, $interests, $double_optin, $format);
  }

  /**
   * Process to immediately subscribe.
   */
  protected function subscribeProcess($list_id, $email, $name, $customFields = NULL, $interests = [], $double_optin = FALSE, $format = 'html') {
    $result = FALSE;
    try {
      $custom_fields = [];
      if (isset($customFields)) {
        foreach ($customFields as $key => $field) {
          if (is_array($field)) {

            // Filter out non-selected values.
            $field = array_filter($field);

            // Transform two level array into one level.
            foreach ($field as $value) {
              $custom_fields[] = [
                'Key' => $key,
                'Value' => $value,
              ];
            }
          }
          else {

            // Add non-array custom fields.
            $custom_fields[] = [
              'Key' => $key,
              'Value' => $field,
            ];
          }
        }
      }

      // Update subscriber information or add new subscriber to the list.
      if ($this->campaignMonitorManager
        ->subscribe($list_id, $email, $name, $custom_fields)) {
        $this->campaignMonitorManager
          ->removeSubscriberFromCache($list_id, $email);
        $this->moduleHandler
          ->invokeAll('campaignmonitor_subscribe', [
          $list_id,
          $email,
        ]);
        return TRUE;
      }
      else {
        return FALSE;
      }

      /*// Check if the user should be sent to a subscribe page.
        $lists = $cm->getLists();
        if (isset($lists[$list_id]['details']['ConfirmationSuccessPage'])
        && !empty($lists[$list_id]['details']['ConfirmationSuccessPage'])) {
        drupal_goto($lists[$list_id]['details']['ConfirmationSuccessPage']);
        }
        else {
        drupal_set_message(
        $this->t('You are now subscribed to the "@list" list.',
        ['@list' => $lists[$list_id]['name']]), 'status');
        }.*/
    } catch (Exception $e) {
      $this
        ->logger('campaignmonitor')
        ->error('An error occurred subscribing {email} to list {list}. "{message}"', [
        'email' => $email,
        'list' => $list_id,
        'message' => $e
          ->getMessage(),
      ]);
    }
    return $result;
  }

  /**
   * Adds a CampaignMonitor subscription task to the queue.
   *
   * @param string $function
   *   The name of the function the queue runner should call.
   * @param array $args
   *   The list of args to pass to the function.
   *
   * @return mixed
   *   Unique ID if item is successfully added to the queue, FALSE otherwise.
   */
  protected function addtoQueue($function, array $args) {
    $queue = \Drupal::queue(CAMPAIGNMONITOR_QUEUE_CRON);
    $queue
      ->createQueue();
    return $queue
      ->createItem([
      'function' => $function,
      'args' => $args,
    ]);
  }

  /**
   * Unsubscribes a member from a CampaignMonitor list.
   *
   * @see CampaignMonitor_Lists::unsubscribe()
   */
  public function userUnsubscribe($list_id, $email, $delete = FALSE, $goodbye = FALSE, $notify = FALSE) {
    $result = FALSE;
    if ($this->campaignMonitorManager
      ->isSubscribed($list_id, $email)) {
      if ($this->config
        ->get('cron')) {
        $result = campaignmonitor_addto_queue('campaignmonitor_unsubscribe_process', [
          'list_id' => $list_id,
          'email' => $email,
          'delete' => $delete,
          'goodbye' => $goodbye,
          'notify' => $notify,
        ]);
      }
      else {
        $result = $this
          ->unsubscribeProcess($list_id, $email, $delete, $goodbye, $notify);
      }
    }
    return $result;
  }

  /**
   * Unsubscribes a member from a CampaignMonitor list.
   *
   * @see CampaignMonitor_Lists::unsubscribe()
   */
  protected function unsubscribeProcess($list_id, $email, $delete, $goodbye, $notify) {
    $lists = $this->campaignMonitorManager
      ->getLists();
    try {
      if ($this->campaignMonitorManager
        ->unsubscribe($list_id, $email)) {
        $this->messenger
          ->addStatus($this
          ->t('You are now unsubscribed from the "@list" list.', [
          '@list' => html_entity_decode($lists[$list_id]['name']),
        ]));
        $this->moduleHandler
          ->invokeAll('campaignmonitor_unsubscribe', [
          $list_id,
          $email,
        ]);

        // Clear user cache:
        $this->campaignMonitorManager
          ->removeSubscriberFromCache($list_id, $email);
        return TRUE;
      }
      return FALSE;
    } catch (Exception $e) {
      $this
        ->logger('campaignmonitor')
        ->error('An error occurred unsubscribing {email} from list {list}. "{message}"', [
        'email' => $email,
        'list' => $list_id,
        'message' => $e
          ->getMessage(),
      ]);
    }
    return FALSE;
  }

}

Classes

Namesort descending Description
CampaignMonitorSubscriptionManager Manager for Campaignmonitor subscriptions.