You are here

class CasAttributesSettings in CAS Attributes 8

Same name and namespace in other branches
  1. 2.x src/Form/CasAttributesSettings.php \Drupal\cas_attributes\Form\CasAttributesSettings

CAS Attributes settings form.

Hierarchy

Expanded class hierarchy of CasAttributesSettings

2 files declare their use of CasAttributesSettings
CasAttributesSubscriber.php in src/Subscriber/CasAttributesSubscriber.php
CasAttributesSubscriberTest.php in tests/src/Unit/Subscriber/CasAttributesSubscriberTest.php
1 string reference to 'CasAttributesSettings'
cas_attributes.routing.yml in ./cas_attributes.routing.yml
cas_attributes.routing.yml

File

src/Form/CasAttributesSettings.php, line 16

Namespace

Drupal\cas_attributes\Form
View source
class CasAttributesSettings extends ConfigFormBase {
  const SYNC_FREQUENCY_NEVER = 0;
  const SYNC_FREQUENCY_INITIAL_REGISTRATION = 1;
  const SYNC_FREQUENCY_EVERY_LOGIN = 2;

  /**
   * The Entity Field Manager to provide field definitions.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * Constructs a \Drupal\cas\Form\CasSettings object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager
   *   The entity field manager.
   */
  public function __construct(ConfigFactoryInterface $config_factory, EntityFieldManagerInterface $entityFieldManager) {
    parent::__construct($config_factory);
    $this->entityFieldManager = $entityFieldManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('config.factory'), $container
      ->get('entity_field.manager'));
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'cas_attributes_settings';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this
      ->config('cas_attributes.settings');
    $form['general'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('General Settings'),
      '#tree' => TRUE,
    ];
    $form['general']['sitewide_token_support'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Sitewide token support'),
      '#description' => $this
        ->t('When enabled, CAS attributes for the logged in user can be retrieved anywhere on your site using this token format: [cas:attribute:?], where ? is the attribute name in lowercase. This works by storing all CAS attributes in the user session, so if you have many attributes and many users, this may make your session storage size very large. <b>This is not required to use tokens for the user field mappings below.</b>'),
      '#default_value' => $config
        ->get('sitewide_token_support'),
    ];
    $form['field'] = [
      '#type' => 'details',
      '#title' => $this
        ->t('User Field Mappings'),
      '#description' => $this
        ->t('Configure settings for mapping CAS attribute values to user fields during login/registration.'),
      '#tree' => TRUE,
      '#open' => TRUE,
    ];
    $form['field']['sync_frequency'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('When should field mappings be applied to the user?'),
      '#options' => [
        self::SYNC_FREQUENCY_NEVER => $this
          ->t('Never'),
        self::SYNC_FREQUENCY_INITIAL_REGISTRATION => $this
          ->t('Initial registration only (requires "Auto register users" <a href="@link">CAS setting</a> be enabled).', [
          '@link' => Url::fromRoute('cas.settings')
            ->toString(),
        ]),
        self::SYNC_FREQUENCY_EVERY_LOGIN => $this
          ->t('Every login'),
      ],
      '#default_value' => $config
        ->get('field.sync_frequency'),
    ];
    $form['field']['overwrite'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Overwrite existing field values'),
      '#description' => $this
        ->t('When checked, the field mappings below will always overwrite existing data on the user account.'),
      '#default_value' => $config
        ->get('field.overwrite'),
    ];
    $form['field']['mappings'] = [
      '#type' => 'details',
      '#title' => $this
        ->t('Fields'),
      '#description' => $this
        ->t('Optionally provide values for each user field below. To use a CAS attribute, insert a token in the format [cas:attribute:?], where ? is the attribute name in lowercase. <a href="@link">Browse available attribute tokens</a> for the currently logged in user. Note that attribute tokens will still work even if you have the "Sitewide token support" feature disabled (above).', [
        '@link' => Url::fromRoute('cas_attributes.available_attributes')
          ->toString(),
      ]),
      '#tree' => TRUE,
      '#open' => TRUE,
    ];
    $savedFieldMappings = $config
      ->get('field.mappings');
    $form['field']['mappings']['name'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Username'),
      '#description' => $this
        ->t('The CAS module defaults this to the username your CAS server provided. Any value placed here will overwrite what the CAS module provides.'),
      '#size' => 60,
      '#default_value' => isset($savedFieldMappings['name']) ? $savedFieldMappings['name'] : '',
    ];
    $form['field']['mappings']['mail'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('E-mail address'),
      '#description' => $this
        ->t('The <a href="@link">settings page for the main CAS module</a> defines the default value for e-mail. Any value placed here will overwrite what the CAS module provides.', [
        '@link' => Url::fromRoute('cas.settings')
          ->toString(),
      ]),
      '#size' => 60,
      '#default_value' => isset($savedFieldMappings['mail']) ? $savedFieldMappings['mail'] : '',
    ];
    foreach ($this->entityFieldManager
      ->getFieldDefinitions('user', 'user') as $name => $definition) {
      if (!empty($definition
        ->getTargetBundle())) {
        switch ($definition
          ->getType()) {
          case 'string':
          case 'list_string':
          case 'integer':
            $form['field']['mappings'][$name] = [
              '#type' => 'textfield',
              '#title' => $definition
                ->getLabel(),
              '#default_value' => isset($savedFieldMappings[$name]) ? $savedFieldMappings[$name] : '',
              '#size' => 60,
              '#description' => $this
                ->t('The account field with name %field_name.', [
                '%field_name' => $definition
                  ->getName(),
              ]),
            ];
            break;
        }
      }
    }
    $form['role'] = [
      '#type' => 'details',
      '#title' => $this
        ->t('User Role Mappings'),
      '#description' => $this
        ->t('Configure settings for assigning roles to users during login/registration based on CAS attribute values.'),
      '#tree' => TRUE,
      '#open' => TRUE,
    ];
    $form['role']['sync_frequency'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('When should role mappings be applied to the user?'),
      '#options' => [
        self::SYNC_FREQUENCY_NEVER => $this
          ->t('Never'),
        self::SYNC_FREQUENCY_INITIAL_REGISTRATION => $this
          ->t('Initial registration only (requires "Auto register users" <a href="@link">CAS setting</a> be enabled).', [
          '@link' => Url::fromRoute('cas.settings')
            ->toString(),
        ]),
        self::SYNC_FREQUENCY_EVERY_LOGIN => $this
          ->t('Every login'),
      ],
      '#default_value' => $config
        ->get('role.sync_frequency'),
    ];
    $form['role']['deny_login_no_match'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Deny login if no roles are mapped'),
      '#description' => $this
        ->t('If enabled, users will not be able to login via CAS unless at least one role is assigned based on the mappings below.'),
      '#default_value' => $config
        ->get('role.deny_login_no_match'),
    ];
    $form['role']['deny_registration_no_match'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Deny registration if no roles are mapped'),
      '#description' => $this
        ->t('If enabled, users will not be able to auto-register via CAS unless at least one role is assigned based on the mappings below.'),
      '#default_value' => $config
        ->get('role.deny_registration_no_match'),
    ];
    $form['role']['mappings'] = [
      '#type' => 'details',
      '#title' => $this
        ->t('CAS Role Mappings'),
      '#description' => $this
        ->t("Each role mapping is a relationship between a role that is to be granted, an attribute name, an attribute value to match, and a method to use for comparison."),
      '#tree' => TRUE,
      '#open' => TRUE,
    ];
    $existingRoleMappings = $config
      ->get('role.mappings');
    $roles_options = user_role_names(TRUE);
    unset($roles_options[RoleInterface::AUTHENTICATED_ID]);

    // Add existing mappings to the form.
    foreach ($existingRoleMappings as $index => $condition) {
      $form['role']['mappings'][$index] = $this
        ->generateRoleMappingFormElements($roles_options, $condition);
      $form['role']['mappings'][$index]['delete'] = [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Remove this mapping?'),
      ];
    }

    // Always add a empty row to allow adding a new mapping.
    $form['role']['mappings'][] = $this
      ->generateRoleMappingFormElements($roles_options);
    return parent::buildForm($form, $form_state);
  }

  /**
   * Generate a form elements for describing a role mapping.
   *
   * @param array $roleOptions
   *   The available roles to map to.
   * @param array $existingData
   *   Default data for each form element, if available.
   *
   * @return array
   *   The form elements for the mapping.
   */
  protected function generateRoleMappingFormElements(array $roleOptions, array $existingData = []) {
    $elements = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Role Mapping'),
    ];
    $elements['rid'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Role to Assign'),
      '#options' => $roleOptions,
    ];
    $elements['attribute'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Attribute Name'),
      '#description' => $this
        ->t('See a <a href="@link">list of available attributes</a> for the currently logged in user (do not provide a token here, use the actual attribute name).', [
        '@link' => Url::fromRoute('cas_attributes.available_attributes')
          ->toString(),
      ]),
      '#size' => 30,
    ];
    $elements['value'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Attribute Value'),
      '#size' => 30,
    ];
    $elements['method'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Comparison Method'),
      '#options' => [
        'exact_single' => $this
          ->t('Exact (Single)'),
        'exact_any' => $this
          ->t('Exact (Any)'),
        'contains_any' => $this
          ->t('Contains'),
        'regex_any' => $this
          ->t('Regex'),
      ],
      '#description' => $this
        ->t("\n        The 'Exact (Single)' method passes if the attribute value has one value only and it matches the given string exactly.\n        The 'Exact (Any)' method passes if any item in the attribute value array matches the given string exactly.\n        The 'Contains' method passes if any item in the attribute value array contains the given string within it anywhere.\n        The 'Regex' method passes if any item in the attribute value array passes the regular expression provided.\n      "),
    ];
    $elements['negate'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Negate'),
      '#description' => $this
        ->t('When checked, the specified role will be applied to the user if the attribute comparison fails to match. This can be useful if you want to assign a role based on the lack of some attribute value.'),
    ];
    $elements['remove_without_match'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Remove role from user if match fails?'),
      '#description' => $this
        ->t('IMPORTANT! If enabled, this will also remove the role if it was manually assigned to the user.'),
    ];
    if (!empty($existingData)) {
      foreach ($existingData as $key => $val) {
        $elements[$key]['#default_value'] = $val;
      }
    }
    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $this
      ->config('cas_attributes.settings');
    $config
      ->set('sitewide_token_support', $form_state
      ->getValue([
      'general',
      'sitewide_token_support',
    ]));
    $field_data = $form_state
      ->getValue('field');
    $field_mappings = array_filter(array_map('trim', $field_data['mappings']));
    $config
      ->set('field.sync_frequency', $field_data['sync_frequency'])
      ->set('field.overwrite', $field_data['overwrite']);
    $config
      ->set('field.mappings', $field_mappings);
    $role_data = $form_state
      ->getValue('role');
    $role_map = [];

    // Filter out invalid mappings before saving.
    foreach ($role_data['mappings'] as $mapping) {

      // Ignore any mappings that have the delete flag.
      if (isset($mapping['delete']) && $mapping['delete']) {
        continue;
      }

      // Ignore any mappings that have incomplete data.
      if (empty($mapping['attribute']) || empty($mapping['value'])) {
        continue;
      }

      // Don't save a value for the delete checkbox. It's not important.
      unset($mapping['delete']);
      $role_map[] = $mapping;
    }
    $config
      ->set('role.sync_frequency', $role_data['sync_frequency'])
      ->set('role.deny_login_no_match', $role_data['deny_login_no_match'])
      ->set('role.deny_registration_no_match', $role_data['deny_registration_no_match'])
      ->set('role.mappings', $role_map);
    $config
      ->save();
    parent::submitForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function getEditableConfigNames() {
    return [
      'cas_attributes.settings',
    ];
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CasAttributesSettings::$entityFieldManager protected property The Entity Field Manager to provide field definitions.
CasAttributesSettings::buildForm public function Form constructor. Overrides ConfigFormBase::buildForm
CasAttributesSettings::create public static function Instantiates a new instance of this class. Overrides ConfigFormBase::create
CasAttributesSettings::generateRoleMappingFormElements protected function Generate a form elements for describing a role mapping.
CasAttributesSettings::getEditableConfigNames public function Gets the configuration names that will be editable. Overrides ConfigFormBaseTrait::getEditableConfigNames
CasAttributesSettings::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
CasAttributesSettings::submitForm public function Form submission handler. Overrides ConfigFormBase::submitForm
CasAttributesSettings::SYNC_FREQUENCY_EVERY_LOGIN constant
CasAttributesSettings::SYNC_FREQUENCY_INITIAL_REGISTRATION constant
CasAttributesSettings::SYNC_FREQUENCY_NEVER constant
CasAttributesSettings::__construct public function Constructs a \Drupal\cas\Form\CasSettings object. Overrides ConfigFormBase::__construct
ConfigFormBaseTrait::config protected function Retrieves a configuration object.
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
FormBase::$configFactory protected property The config factory. 1
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::configFactory protected function Gets the config factory for this form. 1
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
FormBase::validateForm public function Form validation handler. Overrides FormInterface::validateForm 62
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
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.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.