You are here

allowed_languages.module in Allowed Languages 8

Same filename and directory in other branches
  1. 2.x allowed_languages.module

File

allowed_languages.module
View source
<?php

/**
 * @file
 * Contains allowed_languages.module.
 */
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\user\UserInterface;
use Drupal\user\Entity\User;
use Drupal\Core\Entity\ContentEntityInterface;

/**
 * Implements hook_help().
 */
function allowed_languages_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the allowed_languages module.
    case 'help.page.allowed_languages':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Lets you limit the languages a user may use when managing content.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_entity_base_field_info().
 */
function allowed_languages_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = [];
  if ($entity_type
    ->id() === 'user') {

    // Add the allowed languages entity reference field to the user entity.
    $fields['allowed_languages'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Allowed languages'))
      ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
      ->setDescription(t('The languages the user is allowed to manage.'))
      ->setSetting('target_type', 'configurable_language');
  }
  return $fields;
}

/**
 * Apply a pre-render function to the language select field widget.
 *
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function allowed_languages_field_widget_language_select_form_alter(&$element, FormStateInterface $form_state, $context) {
  $form_object = $form_state
    ->getFormObject();

  // We're only interested in altering forms for content entities.
  if (!$form_object instanceof ContentEntityFormInterface) {
    return;
  }

  // We can translate all languages.
  if (\Drupal::currentUser()
    ->hasPermission('translate all languages')) {
    return;
  }
  $entity_type = $form_object
    ->getEntity()
    ->getEntityType();

  // Only alter translatable entity types.
  if (!$entity_type
    ->isTranslatable()) {
    return;
  }
  $element['#pre_render'][] = 'allowed_languages_pre_render_language_select';
}

/**
 * Pre-render function for the language select widget.
 *
 * Removes any languages that the user is not allowed to create content for.
 *
 * @param array $element
 *   The element render array.
 *
 * @return array
 *   The modified render array.
 */
function allowed_languages_pre_render_language_select(array $element) {
  $user = allowed_languages_get_current_user();
  $allowed_languages = allowed_languages_get_allowed_languages_for_user($user);

  // Remove any languages that the user is not allowed to add content for.
  foreach ($element['value']['#options'] as $language_code => $language_option) {

    // If the language is allowed then continue.
    if (in_array($language_code, $allowed_languages)) {
      continue;
    }

    // Always allow the not specified and not applicable language options.
    if ($language_code === LanguageInterface::LANGCODE_NOT_SPECIFIED || $language_code === LanguageInterface::LANGCODE_NOT_APPLICABLE) {
      continue;
    }
    unset($element['value']['#options'][$language_code]);
  }
  return $element;
}

/**
 * Add the allowed languages checkboxes to the user form.
 *
 * @param array $form
 *   The user form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The user form state.
 */
function allowed_languages_form_user_form_alter(array &$form, FormStateInterface $form_state) {

  // If user is not allowed to administer settings, return at once.
  if (!\Drupal::currentUser()
    ->hasPermission('administer allowed languages')) {
    return;
  }

  /** @var \Drupal\user\UserInterface $user */
  $user = $form_state
    ->getFormObject()
    ->getEntity();
  $languages = allowed_languages_get_language_options();
  $users_allowed_languages = allowed_languages_get_allowed_languages_for_user($user);

  // Merge the array of languages with the all languages option.
  $language_options = [
    'all' => t('Allow all languages'),
  ] + $languages;

  // Diff the keys from the languages against the users allowed languages to
  // determine if the all languages checkbox should be checked.
  $not_allowed_languages = array_diff(array_keys($languages), $users_allowed_languages);
  if (!$not_allowed_languages) {
    $users_allowed_languages[] = 'all';
  }
  $form['allowed_languages'] = [
    '#tree' => TRUE,
    '#type' => 'details',
    '#title' => t('Allowed languages'),
    '#open' => TRUE,
  ];
  $form['allowed_languages']['languages'] = [
    '#type' => 'checkboxes',
    '#options' => $language_options,
    '#default_value' => $users_allowed_languages,
  ];
  $form['actions']['submit']['#submit'][] = 'allowed_languages_user_form_submit';
  $form['#attached']['library'][] = 'allowed_languages/user';
}

/**
 * Allowed languages user form submit handler.
 *
 * @param array $form
 *   The user form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The user form state.
 */
function allowed_languages_user_form_submit(array &$form, FormStateInterface $form_state) {
  $languages = array_filter($form_state
    ->getValue([
    'allowed_languages',
    'languages',
  ], []));

  // If the al languages checkbox was checked then lets remove it to not have
  // it saved to the allowed languages.
  if (isset($languages['all'])) {
    unset($languages['all']);
  }

  /** @var \Drupal\user\UserInterface $account */
  $account = $form_state
    ->getFormObject()
    ->getEntity();
  if ($account
    ->hasField('allowed_languages')) {
    $account
      ->set('allowed_languages', array_values($languages))
      ->save();
  }
}

/**
 * Implements hook_entity_operation_alter().
 */
function allowed_languages_entity_operation_alter(array &$operations, EntityInterface $entity) {
  $account = \Drupal::currentUser();

  // Keep all operations if it is not the instance of ContentEntityInterface,
  // the entity is not translatable or if the user has permission to translate all languages.
  if ($entity instanceof ContentEntityInterface && $entity
    ->isTranslatable() && !$account
    ->hasPermission('translate all languages')) {
    $user = User::load($account
      ->id());
    $lang = $entity
      ->language();
    $allowed_languages = allowed_languages_get_allowed_languages_for_user($user);

    // If the language is not allowed for the current user.
    if (!in_array($lang
      ->getId(), $allowed_languages)) {
      foreach ($operations as $id => $operation) {

        // Unset operations.
        if (isset($operation['url']) && !$operation['url']
          ->access($account)) {
          unset($operations[$id]);
        }
      }
    }
  }
}

/**
 * Get the current user.
 *
 * This will return a user entity and not the account proxy.
 *
 * @return \Drupal\Core\Entity\EntityInterface|\Drupal\user\UserInterface|null
 *   The current user entity.
 */
function allowed_languages_get_current_user() {
  $account = \Drupal::currentUser();
  return \Drupal::entityTypeManager()
    ->getStorage('user')
    ->load($account
    ->id());
}

/**
 * Get an array of languages to use with the allowed language checkboxes.
 *
 * @return array
 *   An array of languages keyed by id => name.
 */
function allowed_languages_get_language_options() {
  $language_options = [];

  /** @var \Drupal\language\Entity\ConfigurableLanguage[] $languages */
  $languages = \Drupal::entityTypeManager()
    ->getStorage('configurable_language')
    ->loadMultiple();

  // Get only languages that are not locked.
  foreach ($languages as $language) {
    if ($language
      ->isLocked()) {
      continue;
    }
    $language_options[$language
      ->id()] = $language
      ->getName();
  }
  asort($language_options);
  return $language_options;
}

/**
 * Get the allowed languages for the specified user.
 *
 * @param \Drupal\user\UserInterface $user
 *   The user to get allowed languages for.
 *
 * @return array
 *   An array of allowed language ids.
 */
function allowed_languages_get_allowed_languages_for_user(UserInterface $user) {
  $language_values = [];

  // Make sure the field exists before attempting to get languages.
  if (!$user
    ->hasField('allowed_languages')) {
    return $language_values;
  }

  // Get the id of each referenced language.
  foreach ($user
    ->get('allowed_languages')
    ->getValue() as $item) {
    $language_values[] = $item['target_id'];
  }
  return $language_values;
}

Functions

Namesort descending Description
allowed_languages_entity_base_field_info Implements hook_entity_base_field_info().
allowed_languages_entity_operation_alter Implements hook_entity_operation_alter().
allowed_languages_field_widget_language_select_form_alter Apply a pre-render function to the language select field widget.
allowed_languages_form_user_form_alter Add the allowed languages checkboxes to the user form.
allowed_languages_get_allowed_languages_for_user Get the allowed languages for the specified user.
allowed_languages_get_current_user Get the current user.
allowed_languages_get_language_options Get an array of languages to use with the allowed language checkboxes.
allowed_languages_help Implements hook_help().
allowed_languages_pre_render_language_select Pre-render function for the language select widget.
allowed_languages_user_form_submit Allowed languages user form submit handler.