translators-8.x-1.x-dev/modules/translators_content/src/Controller/TranslatorsContentTranslationOverviewController.php

modules/translators_content/src/Controller/TranslatorsContentTranslationOverviewController.php
<?php

namespace Drupal\translators_content\Controller;

use Drupal\content_translation\ContentTranslationManagerInterface;
use Drupal\content_translation\Controller\ContentTranslationController;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\translators\Services\TranslatorSkills;
use Drupal\translators_content\Access\TranslatorsContentManageAccessCheck;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Base class for entity translation controllers.
 */
class TranslatorsContentTranslationOverviewController extends ContentTranslationController {

  /**
   * User skills service.
   *
   * @var \Drupal\translators\Services\TranslatorSkills
   */
  protected $translatorSkills;
  /**
   * Translator access manager.
   *
   * @var \Drupal\translators_content\Access\TranslatorsContentManageAccessCheck
   */
  protected $accessManager;

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

  /**
   * TranslatorsContentTranslationOverviewController constructor.
   *
   * @param \Drupal\content_translation\ContentTranslationManagerInterface $manager
   *   Content translation manager.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\translators_content\Access\TranslatorsContentManageAccessCheck $access_manager
   *   Translator access manager.
   * @param \Drupal\translators\Services\TranslatorSkills $translatorSkills
   *   User skills service.
   */
  public function __construct(
    ContentTranslationManagerInterface $manager,
    EntityFieldManagerInterface $entity_field_manager,
    TranslatorsContentManageAccessCheck $access_manager,
    TranslatorSkills $translatorSkills
  ) {
    parent::__construct($manager, $entity_field_manager);
    $this->translatorSkills = $translatorSkills;
    $this->accessManager    = $access_manager;
  }

  /**
   * Builds the translations overview page.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   * @param string $entity_type_id
   *   (optional) The entity type ID.
   * @param bool $filter
   *   The filter option to filter content translation links or no.
   *
   * @return array
   *   Array of page elements to render.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL, $filter = TRUE) {
    $build = parent::overview($route_match, $entity_type_id);
    // Post processing translation operations links.
    $rows =& $build['content_translation_overview']['#rows'];
    $this->postProcessTranslationsOperations(
      $rows,
      $route_match->getParameter($entity_type_id)
    );
    // Add translators settings to cacheability metadata.
    $cacheability = CacheableMetadata::createFromRenderArray($build);
    $cacheability = $cacheability
      ->merge(CacheableMetadata::createFromObject($this->config('translators.settings')));
    $cacheability->applyTo($build);
    if (!$filter || empty($this->config('translators.settings')->get('enable_filter_translation_overview_to_skills'))) {
      return $build;
    }

    $translator_langcodes = $this->translatorSkills->getAllLangcodes();

    if (empty($translator_langcodes)) {
      $this->translatorSkills->showMissingTranslationSkillsWarning();
    }

    $user_langs_rows = $other_langs_rows = [];
    $extracted = $this->extractLanguagesWithGroups($rows, $translator_langcodes);
    if (isset($extracted[0]) && !empty($extracted[0])) {
      $user_langs_rows = $extracted[0];
    }
    if (isset($extracted[1]) && !empty($extracted[1])) {
      $other_langs_rows = $extracted[1];
    }

    if (!empty($user_langs_rows)) {
      foreach ($user_langs_rows as $key => $row) {
        $user_langs_rows[$key] = $rows[$row];
      }
    }

    $rows = $user_langs_rows;

    if (!empty($other_langs_rows)) {
      $entity_type_id = $route_match->getParameter('entity_type_id');

      $build['more_link'] = [
        '#title' => $this->t('Show all languages'),
        '#type' => 'link',
        '#attributes' => [
          'class' => [
            'use-ajax',
            'button', 'button--small',
            'more-link',
            'more-link-translations',
          ],
          'id' => 'show-more-translations-link',
        ],
        '#url' => Url::fromRoute(
          $route_match->getRouteName() . '.more',
          [
            $entity_type_id => $route_match->getParameter($entity_type_id)->id(),
            'method' => 'ajax',
          ]
        ),
      ];
      $build['content_translation_overview']['#attributes']['id'] = 'content-translations-list';
      $build['#attached']['library'][] = 'core/drupal.ajax';
    }

    return $build;
  }

  /**
   * Get more languages.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   Route match interface.
   * @param string|null $entity_type_id
   *   Entity type ID.
   * @param string $method
   *   Method name. Values allowed - "noajax" and "ajax". Defaults to "ajax".
   *
   * @return array|\Drupal\Core\Ajax\AjaxResponse
   *   Array of languages or AJAX response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getMoreLanguages(RouteMatchInterface $route_match, $entity_type_id = NULL, $method = 'ajax') {
    $build = self::overview($route_match, $entity_type_id, FALSE);

    $rows =& $build['content_translation_overview']['#rows'];
    $translator_langcodes = $this->translatorSkills->getAllLangcodes();

    $user_langs_rows = $other_langs_rows = [];
    $extracted = $this->extractLanguagesWithGroups($rows, $translator_langcodes);
    if (isset($extracted[0]) && !empty($extracted[0])) {
      $user_langs_rows = $extracted[0];
    }
    if (isset($extracted[1]) && !empty($extracted[1])) {
      $other_langs_rows = $extracted[1];
    }

    $other_langs_rows = array_intersect_key($rows, array_flip($other_langs_rows));

    if ($method == 'noajax') {
      $rows = $other_langs_rows;
      return $build;
    }
    elseif ($method == 'ajax') {
      $response = new AjaxResponse();
      foreach ($user_langs_rows as $key => $row) {
        $user_langs_rows[$key] = $rows[$row];
      }

      $rows = array_merge($user_langs_rows, $other_langs_rows);

      $replace = new ReplaceCommand('#content-translations-list', $build['content_translation_overview']);
      $remove  = new RemoveCommand('#show-more-translations-link');

      $response->addCommand($replace);
      $response->addCommand($remove);
      return $response;
    }
    return [];
  }

  /**
   * Extract language from row.
   *
   * @param array &$row
   *   Row array.
   *
   * @return mixed
   *   Extracted language from row.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  private function extractLanguageFromRow(array &$row) {
    $label = reset($row);
    self::extractDefaultLanguageName($label);
    return !is_string($label)
      ? $this->languageManager->getDefaultLanguage()
      : $this->getLanguageByLabel($label);
  }

  /**
   * Extract languages with groups.
   *
   * @param array &$rows
   *   Rows array.
   * @param array $translator_langcodes
   *   User languages array.
   *
   * @return array
   *   Languages array.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function extractLanguagesWithGroups(array &$rows, array $translator_langcodes) {
    $groups = [];
    $original_key = NULL;
    foreach ($rows as $key => $row) {
      $language = $this->extractLanguageFromRow($row);
      $is_original = stripos((string) reset($row), 'original') !== FALSE;

      $delta = $language instanceof LanguageInterface
        && (in_array($language->getId(), $translator_langcodes) || ($is_original && !empty($this->config('translators.settings')->get('always_display_original_language_translation_overview'))))
        ? 0 : 1;

      if ($is_original) {
        $original_key = $key;
      }
      $groups[$delta][] = $key;
    }
    // Move original language to the top of the array if visable.
    if (!is_null($original_key) && !empty($groups[0]) && in_array($original_key, $groups[0])) {
      $original_key = array_search($original_key, $groups[0]);
      $original = $groups[0][$original_key];
      unset($groups[0][$original_key]);
      array_unshift($groups[0], $original);
    }

    return $groups;
  }

  /**
   * Get language config entity.
   *
   * @param string|null $label
   *   Language label.
   *
   * @return \Drupal\Core\Language\LanguageInterface|mixed|null
   *   Language object if exists.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getLanguageByLabel($label = NULL) {
    if (empty($label)) {
      return NULL;
    }
    $languages = $this->entityTypeManager
      ->getStorage('configurable_language')
      ->loadByProperties(['label' => $label]);
    return !empty($languages) ? reset($languages) : NULL;
  }

  /**
   * Additional post processing function.
   *
   * Post processing translation operations links.
   *
   * @param array $lang_rows
   *   Language rows array.
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   Processed entity.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  protected function postProcessTranslationsOperations(array &$lang_rows, ContentEntityInterface $entity) {
    $entity_type_id = $entity->getEntityTypeId();
    $handler = $this->entityTypeManager()->getHandler($entity_type_id, 'translation');

    foreach ($lang_rows as &$langs_row) {
      if (!empty($langs_row) && is_array($langs_row)) {
        $label = reset($langs_row);
        self::extractDefaultLanguageName($label);
        if (!empty($label) && is_string($label)) {
          $key = self::getLastArrayKey($langs_row);
          $operations =& $langs_row[$key]['data']['#links'];
          $language = static::getLanguageByLabel($label);
          $langcode = $language->id();
          $is_default = $entity->getUntranslated()->language()->getId() == $langcode;
          if ($entity->hasTranslation($langcode)) {
            $entity = $entity->getTranslation($langcode);
            // Build Edit links.
            if ($entity->access('update')) {
              $operations['edit'] = $this->buildEntityUrl($entity, 'Edit', $language);
            }
            elseif (!$is_default
              && $handler->getTranslationAccess($entity, 'update', $langcode)->isAllowed()) {
              $operations['edit'] = $this->buildTranslationUrl($entity, 'Edit', $language);
            }
            else {
              unset($operations['edit']);
            }
            // Build Delete links.
            if ($entity->access('delete')) {
              $operations['delete'] = $this->buildEntityUrl($entity, 'Delete', $language);
            }
            elseif (!$is_default
              && $handler->getTranslationAccess($entity, 'delete', $langcode)->isAllowed()) {
              $operations['delete'] = $this->buildTranslationUrl($entity, 'Delete', $language);
            }
            else {
              unset($operations['delete']);
            }
          }
          else {
            $source = $this->translatorSkills->getTranslationSourceLangcode($entity, $langcode);
            if ($handler->getTranslationAccess($entity, 'create', $source, $langcode)->isAllowed()) {
              $operations['add'] = $this->buildAddLink($entity, $source, $language);
            }
            else {
              unset($operations['add']);
            }
          }
        }
      }
    }
  }

  /**
   * Build "Add" translation links.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   Entity object.
   * @param string $source
   *   Source langcode.
   * @param \Drupal\Core\Language\LanguageInterface $language
   *   Language object.
   *
   * @return array
   *   An array representing links.
   */
  private function buildAddLink(ContentEntityInterface $entity, string $source, LanguageInterface $language) {
    $entity_type_id = $entity->getEntityTypeId();
    $route_name     = "entity.$entity_type_id.content_translation_add";
    $add_url        = Url::fromRoute($route_name, [
      'source'        => $source,
      'target'        => $language->id(),
      $entity_type_id => $entity->id(),
    ]);
    return [
      'url'      => $add_url,
      'language' => $language,
      'title'    => $this->t('Add'),
    ];
  }

  /**
   * Build entity operation links.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   Entity object.
   * @param string $label
   *   Operation label.
   * @param \Drupal\Core\Language\LanguageInterface $language
   *   Language object.
   *
   * @return array
   *   An array representing links.
   */
  private function buildEntityUrl(ContentEntityInterface $entity, string $label, LanguageInterface $language) {
    $operation = strtolower($label);
    return [
      'url'      => $entity->toUrl("$operation-form"),
      'language' => $language,
      'title'    => $this->t($label),
    ];
  }

  /**
   * Build translation operation links.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   Entity object.
   * @param string $label
   *   Operation label.
   * @param \Drupal\Core\Language\LanguageInterface $language
   *   Language object.
   *
   * @return array
   *   An array representing links.
   */
  protected function buildTranslationUrl(ContentEntityInterface $entity, string $label, LanguageInterface $language) {
    $operation = strtolower($label);
    $options = ['language' => $language];
    $url = $entity->toUrl("drupal:content-translation-$operation", $options)
      ->setRouteParameter('language', $language->getId());
    return [
      'url'      => $url,
      'title'    => $this->t($label),
    ];
  }

  /**
   * Extracting the default language label.
   *
   * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup &$name
   *   Language name/label.
   */
  private static function extractDefaultLanguageName(&$name) {
    if ($name instanceof TranslatableMarkup) {
      $name = $name->getArguments()['@language_name'];
    }
  }

  /**
   * Get last array key.
   *
   * @param array $array
   *   Array to be processed.
   *
   * @return mixed
   *   Last array key.
   */
  private static function getLastArrayKey(array $array) {
    $keys = array_keys($array);
    return end($keys);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc