You are here

class MailchimpListsSubscription in Mailchimp 8

Same name and namespace in other branches
  1. 2.x modules/mailchimp_lists/src/Plugin/Field/FieldType/MailchimpListsSubscription.php \Drupal\mailchimp_lists\Plugin\Field\FieldType\MailchimpListsSubscription

Plugin implementation of the 'mailchimp_lists_subscription' field type.

@FieldType ( id = "mailchimp_lists_subscription", label =

Plugin annotation


@Translation("Mailchimp Subscription"),
  description = @Translation("Allows an entity to be subscribed to a Mailchimp audience."),
  default_widget = "mailchimp_lists_select",
  default_formatter = "mailchimp_lists_subscribe_default"
)

Hierarchy

Expanded class hierarchy of MailchimpListsSubscription

2 files declare their use of MailchimpListsSubscription
MailchimpListsSubscribeForm.php in modules/mailchimp_lists/src/Form/MailchimpListsSubscribeForm.php
mailchimp_lists.module in modules/mailchimp_lists/mailchimp_lists.module
Mailchimp lists/audiences module.

File

modules/mailchimp_lists/src/Plugin/Field/FieldType/MailchimpListsSubscription.php, line 27

Namespace

Drupal\mailchimp_lists\Plugin\Field\FieldType
View source
class MailchimpListsSubscription extends FieldItemBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultStorageSettings() {
    return [
      'mc_list_id' => '',
      'double_opt_in' => 0,
      'send_welcome' => 0,
    ] + parent::defaultStorageSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultFieldSettings() {
    return [
      'subscribe_checkbox_label' => 'Subscribe',
      'show_interest_groups' => 0,
      'hide_subscribe_checkbox' => 0,
      'interest_groups_hidden' => 0,
      'interest_groups_label' => '',
      'merge_fields' => [],
      'unsubscribe_on_delete' => 0,
    ] + parent::defaultFieldSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    $columns = [
      'subscribe' => [
        'type' => 'int',
        'size' => 'tiny',
        'not null' => TRUE,
        'default' => 0,
      ],
      'interest_groups' => [
        'type' => 'text',
        'size' => 'normal',
        'not null' => TRUE,
        'serialize' => TRUE,
      ],
    ];
    return [
      'columns' => $columns,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['subscribe'] = DataDefinition::create('boolean')
      ->setLabel(t('Subscribe'))
      ->setDescription(t('True when an entity is subscribed to a audience.'));
    $properties['interest_groups'] = DataDefinition::create('any')
      ->setLabel(t('Interest groups'))
      ->setDescription(t('Interest groups selected for a audience.'));
    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
    $element = parent::storageSettingsForm($form, $form_state, $has_data);
    $lists = mailchimp_get_lists();
    $options = [
      '' => $this
        ->t('-- Select --'),
    ];
    foreach ($lists as $mc_list) {
      $options[$mc_list->id] = $mc_list->name;
    }
    $field_map = \Drupal::service('entity_field.manager')
      ->getFieldMap();
    $field_definitions = [];
    foreach ($field_map as $entity_type => $fields) {
      $field_definitions[$entity_type] = \Drupal::service('entity_field.manager')
        ->getFieldStorageDefinitions($entity_type);
    }

    // Prevent Mailchimp lists/audiences that have already been assigned to a
    // field appearing as field options.
    foreach ($field_map as $entity_type => $fields) {
      foreach ($fields as $field_name => $field_properties) {
        if ($field_properties['type'] == 'mailchimp_lists_subscription') {

          /* @var $field \Drupal\field\Entity\FieldStorageConfig */
          $field = $field_definitions[$entity_type][$field_name];
          $field_settings = $field
            ->getSettings();
          if ($field_name != $this
            ->getFieldDefinition()
            ->getName() && isset($field_settings['mc_list_id'])) {
            unset($options[$field_settings['mc_list_id']]);
          }
        }
      }
    }
    $refresh_lists_url = Url::fromRoute('mailchimp_lists.refresh');
    $mailchimp_url = Url::fromUri('https://admin.mailchimp.com', [
      'attributes' => [
        'target' => '_blank',
      ],
    ]);
    $element['mc_list_id'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Mailchimp Audience'),
      '#multiple' => FALSE,
      '#description' => $this
        ->t('Available Mailchimp audiences which are not already
        attached to Mailchimp Subscription Fields. If there are no options,
        make sure you have created an audience at @Mailchimp first, then @cacheclear.', [
        '@Mailchimp' => Link::fromTextAndUrl('Mailchimp', $mailchimp_url)
          ->toString(),
        '@cacheclear' => Link::fromTextAndUrl('clear your audience cache', $refresh_lists_url)
          ->toString(),
      ]),
      '#options' => $options,
      '#default_value' => $this
        ->getSetting('mc_list_id'),
      '#required' => TRUE,
      '#disabled' => $has_data,
    ];
    $element['double_opt_in'] = [
      '#type' => 'checkbox',
      '#title' => 'Require subscribers to Double Opt-in',
      '#description' => 'New subscribers will be sent a link with an email they must follow to confirm their subscription.',
      '#default_value' => $this
        ->getSetting('double_opt_in'),
      '#disabled' => $has_data,
    ];
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
    $element = parent::fieldSettingsForm($form, $form_state);
    $mc_list_id = $this
      ->getFieldDefinition()
      ->getSetting('mc_list_id');
    if (empty($mc_list_id)) {
      \Drupal::messenger()
        ->addError($this
        ->t('Select an audience to sync with on the Field Settings tab before configuring the field instance.'));
      return $element;
    }
    $this->definition;
    $instance_settings = $this->definition
      ->getSettings();
    $element['subscribe_checkbox_label'] = [
      '#title' => 'Subscribe Checkbox Label',
      '#type' => 'textfield',
      '#default_value' => isset($instance_settings['subscribe_checkbox_label']) ? $instance_settings['subscribe_checkbox_label'] : 'Subscribe',
    ];
    $element['show_interest_groups'] = [
      '#title' => "Enable Interest Groups",
      '#type' => "checkbox",
      '#default_value' => $instance_settings['show_interest_groups'],
    ];
    $element['hide_subscribe_checkbox'] = [
      '#title' => $this
        ->t('Hide Subscribe Checkbox'),
      '#type' => 'checkbox',
      '#default_value' => $instance_settings['hide_subscribe_checkbox'],
      '#description' => $this
        ->t('When Interest Groups are enabled, the "subscribe" checkbox is hidden and selecting any interest group will subscribe a user to the audience.'),
      '#states' => [
        'visible' => [
          'input[name="settings[show_interest_groups]"]' => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];
    $element['interest_groups_hidden'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Hide Interest Groups.'),
      '#description' => $this
        ->t('If checked, the Interest Groups will not be displayed, but the default values will be used.'),
      '#default_value' => $instance_settings['interest_groups_hidden'],
      '#states' => [
        'visible' => [
          'input[name="settings[show_interest_groups]"]' => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];
    $element['interest_groups_label'] = [
      '#title' => "Interest Groups Label",
      '#type' => "textfield",
      '#default_value' => !empty($instance_settings['interest_groups_label']) ? $instance_settings['interest_groups_label'] : 'Interest Groups',
    ];
    $element['merge_fields'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Merge Fields'),
      '#description' => $this
        ->t('Multi-value fields will only sync their first value to Mailchimp, as Mailchimp does not support multi-value fields.'),
      '#tree' => TRUE,
    ];
    $element['unsubscribe_on_delete'] = [
      '#title' => "Unsubscribe on deletion",
      '#type' => "checkbox",
      '#description' => $this
        ->t('Unsubscribe entities from this audience when they are deleted.'),
      '#default_value' => $instance_settings['unsubscribe_on_delete'],
    ];
    $mv_defaults = $instance_settings['merge_fields'];
    $mergevars = mailchimp_get_mergevars([
      $mc_list_id,
    ]);
    $field_config = $this
      ->getFieldDefinition();
    $fields = $this
      ->getFieldmapOptions($field_config
      ->get('entity_type'), $field_config
      ->get('bundle'));
    $required_fields = $this
      ->getFieldmapOptions($field_config
      ->get('entity_type'), $field_config
      ->get('bundle'), TRUE);

    // Prevent this subscription field appearing as a merge field option.
    $field_name = $this
      ->getFieldDefinition()
      ->getName();
    unset($fields[$field_name]);
    $fields_flat = OptGroup::flattenOptions($fields);
    foreach ($mergevars[$mc_list_id] as $mergevar) {
      $default_value = isset($mv_defaults[$mergevar->tag]) ? $mv_defaults[$mergevar->tag] : -1;
      $element['merge_fields'][$mergevar->tag] = [
        '#type' => 'select',
        '#title' => Html::escape($mergevar->name),
        '#default_value' => array_key_exists($default_value, $fields_flat) ? $default_value : '',
        '#required' => $mergevar->required,
      ];
      if (!$mergevar->required || $mergevar->tag === 'EMAIL') {
        $element['merge_fields'][$mergevar->tag]['#options'] = $fields;
        if ($mergevar->tag === 'EMAIL') {
          $element['merge_fields'][$mergevar->tag]['#description'] = $this
            ->t('Any entity with an empty or invalid email address field value will simply be ignored by the Mailchimp subscription system. <em>This is why the Email field is the only required merge field which can sync to non-required fields.</em>');
        }
      }
      else {
        $element['merge_fields'][$mergevar->tag]['#options'] = $required_fields;
        $element['merge_fields'][$mergevar->tag]['#description'] = $this
          ->t("Only 'required' and 'calculated' fields are allowed to be synced with Mailchimp 'required' merge fields.");
      }
    }
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function isEmpty() {
    $value = $this
      ->getValue();
    return $value === NULL || $value === '';
  }

  /**
   * {@inheritdoc}
   */
  public function postSave($update) {
    parent::postSave($update);
    $choices = $this->values;

    // Only act if the field has a value to prevent unintended unsubscription.
    if (!empty($choices)) {
      $field_settings = $this->definition
        ->getSettings();

      // Automatically subscribe if the field is configured to hide the
      // Subscribe checkbox and at least one interest group checkbox is checked.
      if ($field_settings['show_interest_groups'] && $field_settings['hide_subscribe_checkbox']) {
        if (!empty($choices['interest_groups'])) {
          $subscribe_from_interest_groups = FALSE;
          foreach ($choices['interest_groups'] as $group_id => $interests) {
            foreach ($interests as $interest_id => $value) {
              if (!empty($value)) {
                $subscribe_from_interest_groups = TRUE;
                continue;
              }
            }
          }
          $choices['subscribe'] = $subscribe_from_interest_groups;
        }
      }
      mailchimp_lists_process_subscribe_form_choices($choices, $this, $this
        ->getEntity());
    }
  }

  /**
   * Returns the field 'subscribe' value.
   *
   * @return bool
   *   The field 'subscribe' value.
   */
  public function getSubscribe() {
    if (isset($this->values['subscribe'])) {
      return $this->values['subscribe'] == 1;
    }
    return NULL;
  }

  /**
   * Returns the field 'interest_groups' value.
   *
   * @return array
   *   The field 'interest_groups' value.
   */
  public function getInterestGroups() {
    if (isset($this->values['interest_groups'])) {
      return $this->values['interest_groups'];
    }
    return NULL;
  }

  /**
   * Get an array with all possible Drupal properties for a given entity type.
   *
   * @param string $entity_type
   *   Name of entity whose properties to list/audience.
   * @param string $entity_bundle
   *   Optional bundle to limit available properties.
   * @param bool $required
   *   Set to TRUE if properties are required.
   * @param string $prefix
   *   Optional prefix for option IDs in the options list/audience.
   * @param string $tree
   *   Optional name of the parent element if the options are part of a tree.
   *
   * @return array
   *   List of properties that can be used as an #options list/audience.
   */
  private function getFieldmapOptions($entity_type, $entity_bundle = NULL, $required = FALSE, $prefix = NULL, $tree = NULL) {
    $options = [];
    if (!$prefix) {
      $options[''] = $this
        ->t('-- Select --');
    }

    /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $field_definitions */
    $field_definitions = \Drupal::service('entity_field.manager')
      ->getFieldDefinitions($entity_type, $entity_bundle);
    foreach ($field_definitions as $field_name => $field_definition) {
      $keypath = $prefix ? $prefix . ':' . $field_name : $field_name;
      $label = $field_definition
        ->getLabel();
      if ($field_definition
        ->getSetting('target_type')) {
        $target_type = $field_definition
          ->getSetting('target_type');
        $target_definition = \Drupal::entityTypeManager()
          ->getDefinition($target_type);

        // We offer fields on related fieldable entities (useful for field
        // collections).
        // But we only offer 1 level of depth to avoid loops.
        if ($target_definition
          ->entityClassImplements(FieldableEntityInterface::class) && !$prefix) {
          $handler_settings = $field_definition
            ->getSetting('handler_settings');
          $bundle = NULL;
          if ($target_definition
            ->hasKey('bundle')) {

            // @todo Support multiple target bundles?
            if (!empty($handler_settings['target_bundles']) && count($handler_settings['target_bundles']) == 1) {
              $bundle = reset($handler_settings['target_bundles']);
            }
          }
          else {
            $bundle = $target_type;
          }
          if ($bundle) {
            $options[(string) $label] = $this
              ->getFieldmapOptions($field_definition
              ->getSetting('target_type'), $bundle, $required, $keypath . ':entity', $label);
          }
        }
      }
      elseif (!$required || $field_definition
        ->isRequired() || $field_definition
        ->isComputed()) {

        // Get a list of non-computed property definitions.
        $property_definitions = $field_definition
          ->getFieldStorageDefinition()
          ->getPropertyDefinitions();
        $property_definitions = array_filter($property_definitions, function (DataDefinitionInterface $property_definition) {
          return !$property_definition
            ->isComputed();
        });
        if (count($property_definitions) > 1) {
          foreach ($property_definitions as $property => $property_definition) {
            $options[(string) $label][$keypath . ':' . $property] = $property_definition
              ->getLabel();
          }
        }
        else {
          $options[$keypath] = $label;
        }
      }
    }
    return $options;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FieldItemBase::calculateDependencies public static function Calculates dependencies for field items. Overrides FieldItemInterface::calculateDependencies 2
FieldItemBase::calculateStorageDependencies public static function Calculates dependencies for field items on the storage level. Overrides FieldItemInterface::calculateStorageDependencies 1
FieldItemBase::delete public function Defines custom delete behavior for field values. Overrides FieldItemInterface::delete 2
FieldItemBase::deleteRevision public function Defines custom revision delete behavior for field values. Overrides FieldItemInterface::deleteRevision
FieldItemBase::fieldSettingsFromConfigData public static function Returns a settings array in the field type's canonical representation. Overrides FieldItemInterface::fieldSettingsFromConfigData 1
FieldItemBase::fieldSettingsToConfigData public static function Returns a settings array that can be stored as a configuration value. Overrides FieldItemInterface::fieldSettingsToConfigData 1
FieldItemBase::generateSampleValue public static function Generates placeholder field values. Overrides FieldItemInterface::generateSampleValue 18
FieldItemBase::getEntity public function Gets the entity that field belongs to. Overrides FieldItemInterface::getEntity
FieldItemBase::getFieldDefinition public function Gets the field definition. Overrides FieldItemInterface::getFieldDefinition
FieldItemBase::getLangcode public function Gets the langcode of the field values held in the object. Overrides FieldItemInterface::getLangcode
FieldItemBase::getSetting protected function Returns the value of a field setting.
FieldItemBase::getSettings protected function Returns the array of field settings.
FieldItemBase::mainPropertyName public static function Returns the name of the main property, if any. Overrides FieldItemInterface::mainPropertyName 8
FieldItemBase::onDependencyRemoval public static function Informs the plugin that a dependency of the field will be deleted. Overrides FieldItemInterface::onDependencyRemoval 1
FieldItemBase::preSave public function Defines custom presave behavior for field values. Overrides FieldItemInterface::preSave 7
FieldItemBase::setValue public function Sets the data value. Overrides Map::setValue 4
FieldItemBase::storageSettingsFromConfigData public static function Returns a settings array in the field type's canonical representation. Overrides FieldItemInterface::storageSettingsFromConfigData 2
FieldItemBase::storageSettingsToConfigData public static function Returns a settings array that can be stored as a configuration value. Overrides FieldItemInterface::storageSettingsToConfigData 2
FieldItemBase::view public function Returns a renderable array for a single field item. Overrides FieldItemInterface::view
FieldItemBase::writePropertyValue protected function Different to the parent Map class, we avoid creating property objects as far as possible in order to optimize performance. Thus we just update $this->values if no property object has been created yet. Overrides Map::writePropertyValue
FieldItemBase::__construct public function Constructs a TypedData object given its definition and context. Overrides TypedData::__construct 1
FieldItemBase::__get public function Magic method: Gets a property value. Overrides FieldItemInterface::__get 2
FieldItemBase::__isset public function Magic method: Determines whether a property is set. Overrides FieldItemInterface::__isset
FieldItemBase::__set public function Magic method: Sets a property value. Overrides FieldItemInterface::__set 1
FieldItemBase::__unset public function Magic method: Unsets a property. Overrides FieldItemInterface::__unset
MailchimpListsSubscription::defaultFieldSettings public static function Defines the field-level settings for this plugin. Overrides FieldItemBase::defaultFieldSettings
MailchimpListsSubscription::defaultStorageSettings public static function Defines the storage-level settings for this plugin. Overrides FieldItemBase::defaultStorageSettings
MailchimpListsSubscription::fieldSettingsForm public function Returns a form for the field-level settings. Overrides FieldItemBase::fieldSettingsForm
MailchimpListsSubscription::getFieldmapOptions private function Get an array with all possible Drupal properties for a given entity type.
MailchimpListsSubscription::getInterestGroups public function Returns the field 'interest_groups' value.
MailchimpListsSubscription::getSubscribe public function Returns the field 'subscribe' value.
MailchimpListsSubscription::isEmpty public function Determines whether the data structure is empty. Overrides Map::isEmpty
MailchimpListsSubscription::postSave public function Defines custom post-save behavior for field values. Overrides FieldItemBase::postSave
MailchimpListsSubscription::propertyDefinitions public static function Defines field item properties. Overrides FieldItemInterface::propertyDefinitions
MailchimpListsSubscription::schema public static function Returns the schema for the field. Overrides FieldItemInterface::schema
MailchimpListsSubscription::storageSettingsForm public function Returns a form for the storage-level settings. Overrides FieldItemBase::storageSettingsForm
Map::$definition protected property The data definition. Overrides TypedData::$definition
Map::$properties protected property The array of properties.
Map::$values protected property An array of values for the contained properties.
Map::applyDefaultValue public function Applies the default value. Overrides TypedData::applyDefaultValue 4
Map::get public function Gets a property object. Overrides ComplexDataInterface::get
Map::getIterator public function
Map::getProperties public function Gets an array of property objects. Overrides ComplexDataInterface::getProperties
Map::getString public function Returns a string representation of the data. Overrides TypedData::getString
Map::getValue public function Gets the data value. Overrides TypedData::getValue 1
Map::onChange public function Overrides TraversableTypedDataInterface::onChange 4
Map::set public function Sets a property value. Overrides ComplexDataInterface::set
Map::toArray public function Returns an array of all property values. Overrides ComplexDataInterface::toArray 1
Map::__clone public function Magic method: Implements a deep clone.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TypedData::$name protected property The property name.
TypedData::$parent protected property The parent typed data object.
TypedData::createInstance public static function Constructs a TypedData object given its definition and context. Overrides TypedDataInterface::createInstance
TypedData::getConstraints public function Gets a list of validation constraints. Overrides TypedDataInterface::getConstraints 9
TypedData::getDataDefinition public function Gets the data definition. Overrides TypedDataInterface::getDataDefinition
TypedData::getName public function Returns the name of a property or item. Overrides TypedDataInterface::getName
TypedData::getParent public function Returns the parent data structure; i.e. either complex data or a list. Overrides TypedDataInterface::getParent
TypedData::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition
TypedData::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
TypedData::getPropertyPath public function Returns the property path of the data. Overrides TypedDataInterface::getPropertyPath
TypedData::getRoot public function Returns the root of the typed data tree. Overrides TypedDataInterface::getRoot
TypedData::setContext public function Sets the context of a property or item via a context aware parent. Overrides TypedDataInterface::setContext
TypedData::validate public function Validates the currently set data value. Overrides TypedDataInterface::validate
TypedDataTrait::$typedDataManager protected property The typed data manager used for creating the data types.
TypedDataTrait::getTypedDataManager public function Gets the typed data manager. 2
TypedDataTrait::setTypedDataManager public function Sets the typed data manager. 2