View source  
  <?php
namespace Drupal\tmgmt_config;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\tmgmt\SourcePluginUiBase;
use Drupal\tmgmt_config\Plugin\tmgmt\Source\ConfigSource;
class ConfigSourcePluginUi extends SourcePluginUiBase {
  
  public $pagerLimit = 25;
  
  public function overviewSearchFormPart(array $form, FormStateInterface $form_state, $type) {
    $form = parent::overviewSearchFormPart($form, $form_state, $type);
    if ($type == ConfigSource::SIMPLE_CONFIG) {
      $label_key = 'name';
      $label = t('Simple configuration');
    }
    else {
      $entity_type = \Drupal::entityTypeManager()
        ->getDefinition($type);
      $label_key = $entity_type
        ->getKey('label');
      $label = $entity_type
        ->getLabel();
    }
    if (!empty($label_key)) {
      $form['search_wrapper']['search'][$label_key] = array(
        '#type' => 'textfield',
        '#title' => t('@entity_name title', array(
          '@entity_name' => $label,
        )),
        '#size' => 25,
        '#default_value' => isset($_GET[$label_key]) ? $_GET[$label_key] : NULL,
      );
    }
    $form['search_wrapper']['search']['langcode'] = array(
      '#type' => 'language_select',
      '#title' => t('Source Language'),
      '#empty_option' => t('- Any -'),
      '#default_value' => isset($_GET['langcode']) ? $_GET['langcode'] : NULL,
    );
    $form['search_wrapper']['search']['target_language'] = array(
      '#type' => 'language_select',
      '#title' => $this
        ->t('Target language'),
      '#empty_option' => $this
        ->t('- Any -'),
      '#default_value' => isset($_GET['target_language']) ? $_GET['target_language'] : NULL,
    );
    $form['search_wrapper']['search']['target_status'] = array(
      '#type' => 'select',
      '#title' => $this
        ->t('Target status'),
      '#options' => array(
        'untranslated' => $this
          ->t('Untranslated'),
        'translated' => $this
          ->t('Translated'),
      ),
      '#default_value' => isset($_GET['target_status']) ? $_GET['target_status'] : NULL,
      '#states' => array(
        'invisible' => array(
          ':input[name="search[target_language]"]' => array(
            'value' => '',
          ),
        ),
      ),
    );
    return $form;
  }
  
  public function overviewFormHeader($type) {
    $header = array(
      'title' => array(
        'data' => $this
          ->t('Title (in source language)'),
      ),
      'config_id' => array(
        'data' => $this
          ->t('Configuration ID'),
      ),
    );
    $header += $this
      ->getLanguageHeader();
    return $header;
  }
  
  public function overviewRow(ConfigEntityInterface $entity) {
    $label = $entity
      ->label() ?: $this
      ->t('@type: @id', array(
      '@type' => $entity
        ->getEntityTypeId(),
      '@id' => $entity
        ->id(),
    ));
    
    $source_lang = $entity
      ->language()
      ->getId();
    $current_job_items = tmgmt_job_item_load_latest('config', $entity
      ->getEntityTypeId(), $entity
      ->getConfigDependencyName(), $source_lang);
    $row['id'] = $entity
      ->id();
    $definition = \Drupal::entityTypeManager()
      ->getDefinition($entity
      ->bundle());
    $row['config_id'] = $definition
      ->getConfigPrefix() . '.' . $entity
      ->id();
    if ($entity
      ->hasLinkTemplate('edit-form')) {
      $row['title'] = $entity
        ->toLink($label, 'edit-form');
    }
    else {
      
      $row['title'] = $label;
    }
    
    foreach (\Drupal::languageManager()
      ->getLanguages() as $langcode => $language) {
      $translation_status = 'current';
      if ($langcode == $source_lang) {
        $translation_status = 'original';
      }
      elseif (!$this
        ->isTranslated($langcode, $entity
        ->getConfigDependencyName())) {
        $translation_status = 'missing';
      }
      
      $build = $this
        ->buildTranslationStatus($translation_status, isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL);
      $row['langcode-' . $langcode] = [
        'data' => \Drupal::service('renderer')
          ->render($build),
        'class' => array(
          'langstatus-' . $langcode,
        ),
      ];
    }
    return $row;
  }
  
  public function overviewRowSimple(array $definition) {
    
    $config_id = $definition['names'][0];
    $source_lang = \Drupal::config($definition['names'][0])
      ->get('langcode') ?: 'en';
    $current_job_items = tmgmt_job_item_load_latest('config', ConfigSource::SIMPLE_CONFIG, $definition['id'], $source_lang);
    $row = array(
      'id' => $definition['id'],
      'title' => $definition['title'],
    );
    
    foreach (\Drupal::languageManager()
      ->getLanguages() as $langcode => $language) {
      $translation_status = 'current';
      if ($langcode == $source_lang) {
        $translation_status = 'original';
      }
      elseif (!$this
        ->isTranslated($langcode, $config_id)) {
        $translation_status = 'missing';
      }
      
      $build = $this
        ->buildTranslationStatus($translation_status, isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL);
      $row['langcode-' . $langcode] = [
        'data' => \Drupal::service('renderer')
          ->render($build),
        'class' => array(
          'langstatus-' . $langcode,
        ),
      ];
    }
    return $row;
  }
  
  public function isTranslated($langcode, $name) {
    $config = \Drupal::languageManager()
      ->getLanguageConfigOverride($langcode, $name);
    return !$config
      ->isNew();
  }
  
  public function overviewForm(array $form, FormStateInterface $form_state, $type) {
    $form = parent::overviewForm($form, $form_state, $type);
    
    $search_property_params = array();
    $exclude_params = array(
      'q',
      'page',
    );
    foreach (\Drupal::request()->query
      ->all() as $key => $value) {
      
      if (in_array($key, $exclude_params) || $value === '') {
        continue;
      }
      $search_property_params[$key] = $value;
    }
    
    if ($type == ConfigSource::SIMPLE_CONFIG) {
      $definitions = $this
        ->getFilteredSimpleConfigDefinitions($search_property_params);
      foreach ($definitions as $definition_id => $definition) {
        $form['items']['#options'][$definition_id] = $this
          ->overviewRowSimple($definition);
      }
    }
    else {
      foreach ($this
        ->getTranslatableEntities($type, $search_property_params) as $entity) {
        $form['items']['#options'][$entity
          ->getConfigDependencyName()] = $this
          ->overviewRow($entity);
      }
    }
    return $form;
  }
  
  public function overviewFormValidate(array $form, FormStateInterface $form_state, $type) {
    $target_language = $form_state
      ->getValue(array(
      'search',
      'target_language',
    ));
    if (!empty($target_language) && $form_state
      ->getValue(array(
      'search',
      'langcode',
    )) == $target_language) {
      $form_state
        ->setErrorByName('search[target_language]', $this
        ->t('The source and target languages must not be the same.'));
    }
  }
  
  function getTranslatableEntities($entity_type_id, $property_conditions = array()) {
    $target_status = NULL;
    $target_language = NULL;
    
    if (isset($property_conditions['target_status']) && isset($property_conditions['target_language'])) {
      $target_status = $property_conditions['target_status'];
      $target_language = $property_conditions['target_language'];
    }
    unset($property_conditions['target_status']);
    unset($property_conditions['target_language']);
    $search = \Drupal::entityQuery($entity_type_id);
    
    foreach ($property_conditions as $property_name => $property_value) {
      $search
        ->condition($property_name, $property_value, 'CONTAINS');
    }
    $result = $search
      ->execute();
    $entities = array();
    if (!empty($result)) {
      
      $entities = \Drupal::entityTypeManager()
        ->getStorage($entity_type_id)
        ->loadMultiple($result);
      
      if ($target_status == 'untranslated') {
        $entities = array_filter($entities, function (ConfigEntityInterface $entity) use ($target_language) {
          return !$this
            ->isTranslated($target_language, $entity
            ->getConfigDependencyName());
        });
      }
      elseif ($target_status == 'translated') {
        $entities = array_filter($entities, function (ConfigEntityInterface $entity) use ($target_language) {
          return $this
            ->isTranslated($target_language, $entity
            ->getConfigDependencyName());
        });
      }
    }
    return $entities;
  }
  
  public function getFilteredSimpleConfigDefinitions($search_properties = array()) {
    $definitions = \Drupal::service('plugin.manager.config_translation.mapper')
      ->getDefinitions();
    $definitions = array_filter($definitions, function ($definition) use ($search_properties) {
      if (isset($definition['entity_type'])) {
        return FALSE;
      }
      if (isset($search_properties['name']) && strpos(strtolower($definition['title']), strtolower($search_properties['name'])) === FALSE) {
        return FALSE;
      }
      if (isset($search_properties['target_language'])) {
        if ($search_properties['target_status'] == 'translated' && !$this
          ->isTranslated($search_properties['target_language'], $definition['names'][0])) {
          return FALSE;
        }
        if ($search_properties['target_status'] == 'untranslated' && $this
          ->isTranslated($search_properties['target_language'], $definition['names'][0])) {
          return FALSE;
        }
      }
      return TRUE;
    });
    return $definitions;
  }
}