tmgmt-8.x-1.x-dev/sources/content/src/ContentEntitySourcePluginUi.php

sources/content/src/ContentEntitySourcePluginUi.php
<?php

namespace Drupal\tmgmt_content;

use Drupal\content_translation\ContentTranslationManager;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\tmgmt\JobItemInterface;
use Drupal\tmgmt\SourcePluginUiBase;
use Drupal\tmgmt_content\Plugin\tmgmt\Source\ContentEntitySource;

/**
 * Content entity source plugin UI.
 *
 * Provides getEntity() method to retrieve list of entities of specific type.
 * It also allows to implement alter hook to alter the entity query for a
 * specific type.
 *
 * @ingroup tmgmt_source
 */
class ContentEntitySourcePluginUi extends SourcePluginUiBase {

  /**
   * Entity source list items limit.
   *
   * @var int
   */
  public $pagerLimit = 25;

  /**
   * {@inheritdoc}
   */
  public function overviewSearchFormPart(array $form, FormStateInterface $form_state, $type) {
    $form = parent::overviewSearchFormPart($form, $form_state, $type);

    $entity_type = \Drupal::entityTypeManager()->getDefinition($type);
    $field_definitions = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions($type);

    $label_key = $entity_type->getKey('label');
    if (!empty($label_key)) {
      $label = (string) $field_definitions[$label_key]->getlabel();
      $form['search_wrapper']['search'][$label_key] = array(
        '#type' => 'textfield',
        '#title' => $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,
    );

    $bundle_key = $entity_type->getKey('bundle');
    $bundle_options = $this->getTranslatableBundles($type);

    if (count($bundle_options) > 1) {
      $form['search_wrapper']['search'][$bundle_key] = array(
        '#type' => 'select',
        '#title' => $entity_type->getBundleLabel(),
        '#options' => $bundle_options,
        '#empty_option' => t('- Any -'),
        '#default_value' => isset($_GET[$bundle_key]) ? $_GET[$bundle_key] : NULL,
      );
    }
    // In case entity translation is not enabled for any of bundles
    // display appropriate message.
    elseif (count($bundle_options) == 0) {
      $this->messenger()->addWarning($this->t('Entity translation is not enabled for any of existing content types. To use this functionality go to Content types administration and enable entity translation for desired content types.'));
      unset($form['search_wrapper']);
      return $form;
    }

    $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_or_outdated' => $this->t('Untranslated or outdated'),
        'untranslated' => $this->t('Untranslated'),
        'outdated' => $this->t('Outdated'),
      ),
      '#default_value' => isset($_GET['target_status']) ? $_GET['target_status'] : NULL,
      '#states' => array(
        'invisible' => array(
          ':input[name="search[target_language]"]' => array('value' => ''),
        ),
      ),
    );

    return $form;
  }

  /**
   * Gets overview form header.
   *
   * @return array
   *   Header array definition as expected by theme_tablesort().
   */
  public function overviewFormHeader($type) {
    $entity_type = \Drupal::entityTypeManager()->getDefinition($type);

    $header = array(
      'title' => array('data' => $this->t('Title (in source language)')),
    );

    // Show the bundle if there is more than one for this entity type.
    if (count($this->getTranslatableBundles($type)) > 1) {
      $header['bundle'] = array('data' => $this->t('@entity_name type', array('@entity_name' => $entity_type->getLabel())));
    }

    $header += $this->getLanguageHeader();

    return $header;
  }

  /**
   * Builds a table row for overview form.
   *
   * @param array ContentEntityInterface $entity
   *   Data needed to build the list row.
   * @param array $bundles
   *   The array of bundles.
   *
   * @return array
   */
  public function overviewRow(ContentEntityInterface $entity, array $bundles) {
    $entity_label = $entity->label();

    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
    $use_latest_revisions = $entity->getEntityType()->isRevisionable() && ContentTranslationManager::isPendingRevisionSupportEnabled($entity->getEntityTypeId(), $entity->bundle());

    // Get the default revision.
    $default_revision = $use_latest_revisions ? $storage->load($entity->id()) : $entity;

    // Get existing translations and current job items for the entity
    // to determine translation statuses
    $translations = $entity->getTranslationLanguages();
    $source_lang = $entity->language()->getId();
    $current_job_items = tmgmt_job_item_load_latest('content', $entity->getEntityTypeId(), $entity->id(), $source_lang);

    $row = array(
      'id' => $entity->id(),
    );

    if (count($bundles) > 1) {
      $row['bundle'] = isset($bundles[$entity->bundle()]) ? $bundles[$entity->bundle()] : t('Unknown');
    }

    // Load entity translation specific data.
    $manager = \Drupal::service('content_translation.manager');
    foreach (\Drupal::languageManager()->getLanguages() as $langcode => $language) {
      // @see Drupal\content_translation\Controller\ContentTranslationController::overview()
      // If the entity type is revisionable, we may have pending revisions
      // with translations not available yet in the default revision. Thus we
      // need to load the latest translation-affecting revision for each
      // language to be sure we are listing all available translations.
      if ($use_latest_revisions) {
        $entity = $default_revision;
        $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $langcode);
        if ($latest_revision_id) {
          /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */
          $latest_revision = $storage->loadRevision($latest_revision_id);
          // Make sure we do not list removed translations, i.e. translations
          // that have been part of a default revision but no longer are.
          if (!$latest_revision->wasDefaultRevision() || $default_revision->hasTranslation($langcode)) {
            $entity = $latest_revision;
            // Update the label if we are dealing with the source language.
            if ($langcode === $source_lang) {
              $entity_label = $entity->label();
            }
          }
        }
        $translations = $entity->getTranslationLanguages();
      }

      $translation_status = 'current';

      if ($langcode == $source_lang) {
        $translation_status = 'original';
      }
      elseif (!isset($translations[$langcode])) {
        $translation_status = 'missing';
      }
      elseif ($translation = $entity->getTranslation($langcode)) {
        $metadata = $manager->getTranslationMetadata($translation);
        if ($metadata->isOutdated()) {
          $translation_status = 'outofdate';
        }
      }

      $build = $this->buildTranslationStatus($translation_status, isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL);

      if ($translation_status != 'missing' && $entity->hasLinkTemplate('canonical')) {
        $build['source'] = [
          '#type' => 'link',
          '#url' => $entity->toUrl('canonical', ['language' => $language]),
          '#title' => $build['source'],
          ];
      }

      $row['langcode-' . $langcode] = [
        'data' => \Drupal::service('renderer')->render($build),
        'class' => array('langstatus-' . $langcode),
      ];
    }

    $label = $entity_label ?: $this->t('@type: @id', [
      '@type' => $entity->getEntityTypeId(),
      '@id' => $entity->id(),
    ]);
    $row['title'] = $entity->hasLinkTemplate('canonical') ? $entity->toLink($label, 'canonical')->toString() : ($entity_label ?: $entity->id());
    return $row;
  }

  /**
   * {@inheritdoc}
   */
  public function overviewForm(array $form, FormStateInterface $form_state, $type) {
    $form = parent::overviewForm($form, $form_state, $type);

    // Build a list of allowed search conditions and get their values from the request.
    $entity_type = \Drupal::entityTypeManager()->getDefinition($type);
    $whitelist = array('langcode', 'target_language', 'target_status');
    if ($entity_type->hasKey('bundle')) {
      $whitelist[] = $entity_type->getKey('bundle');
    }
    if ($entity_type->hasKey('label')) {
      $whitelist[] = $entity_type->getKey('label');
    }
    $search_property_params = array_filter(\Drupal::request()->query->all());
    $search_property_params = array_intersect_key($search_property_params, array_flip($whitelist));
    $bundles = $this->getTranslatableBundles($type);

    foreach (static::getTranslatableEntities($type, $search_property_params, TRUE) as $entity) {
      // This occurs on user entity type.
      if ($entity->id()) {
        $form['items']['#options'][$entity->id()] = $this->overviewRow($entity, $bundles);
      }
    }

    $form['pager'] = array('#type' => 'pager');

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  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.'));
    }
  }

  /**
   * Adds selected sources to continuous jobs.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state array.
   * @param string $item_type
   *   Entity type.
   */
  public function overviewSubmitToContinuousJobs(FormStateInterface $form_state, $item_type) {
    if ($form_state->getValue('add_all_to_continuous_jobs')) {
      // Build a list of allowed search conditions and get their values from the request.
      $entity_type = \Drupal::entityTypeManager()->getDefinition($item_type);
      $whitelist = array('langcode', 'target_language', 'target_status');
      $whitelist[] = $entity_type->getKey('bundle');
      $whitelist[] = $entity_type->getKey('label');
      $search_property_params = array_filter(\Drupal::request()->query->all());
      $search_property_params = array_intersect_key($search_property_params, array_flip($whitelist));
      $operations = array(
        array(
          array(ContentEntitySourcePluginUi::class, 'createContinuousJobItemsBatch'),
          array($item_type, $search_property_params),
        ),
      );
      $batch = array(
        'title' => t('Creating continuous job items'),
        'operations' => $operations,
        'finished' => 'tmgmt_content_create_continuous_job_items_batch_finished',
      );
      batch_set($batch);
    }
    else {
      $entities = ContentEntitySource::loadMultiple($item_type, array_filter($form_state->getValue('items')));
      $job_items = 0;
      // Loop through entities and add them to continuous jobs.
      foreach ($entities as $entity) {
        $job_items += tmgmt_content_create_continuous_job_items($entity);
      }

      if ($job_items !== 0) {
        \Drupal::messenger()->addStatus(\Drupal::translation()->formatPlural($job_items, '1 continuous job item has been created.', '@count continuous job items have been created.'));
      }
      else {
        \Drupal::messenger()->addWarning(t('None of the selected sources can be added to continuous jobs.'));
      }
    }
  }

  /**
   * A function to get entity translatable bundles.
   *
   * Note that for comment entity type it will return the same as for node as
   * comment bundles have no use (i.e. in queries).
   *
   * @param string $entity_type
   *   Drupal entity type.
   *
   * @return array
   *   Array of key => values, where key is type and value its label.
   */
  function getTranslatableBundles($entity_type) {

    // If given entity type does not have entity translations enabled, no reason
    // to continue.
    $enabled_types = \Drupal::service('plugin.manager.tmgmt.source')->createInstance('content')->getItemTypes();
    if (!isset($enabled_types[$entity_type])) {
      return array();
    }

    $translatable_bundle_types = array();
    $content_translation_manager = \Drupal::service('content_translation.manager');
    foreach (\Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type) as $bundle_type => $bundle_definition) {
      if ($content_translation_manager->isEnabled($entity_type, $bundle_type)) {
        $translatable_bundle_types[$bundle_type] = $bundle_definition['label'];
      }
    }
    return $translatable_bundle_types;
  }

  /**
   * Gets translatable entities of a given type.
   *
   * Additionally you can specify entity property conditions, pager and limit.
   *
   * @param string $entity_type_id
   *   Drupal entity type.
   * @param array $property_conditions
   *   Entity properties. There is no value processing so caller must make sure
   *   the provided entity property exists for given entity type and its value
   *   is processed.
   * @param bool $pager
   *   Flag to determine if pager will be used.
   * @param int $offset
   *   Query range offset.
   * @param int $limit
   *   Query range limit.
   *
   * @return array ContentEntityInterface[]
   *   Array of translatable entities.
   */
  public static function getTranslatableEntities($entity_type_id, $property_conditions = array(), $pager = FALSE, $offset = 0, $limit = 0) {
    $query = static::buildTranslatableEntitiesQuery($entity_type_id, $property_conditions);

    if ($query) {
      if ($pager) {
        $query = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender')->limit(\Drupal::config('tmgmt.settings')->get('source_list_limit'));
      }
      elseif ($limit) {
        $query->range($offset, $limit);
      }
      else {
        $query->range(0, \Drupal::config('tmgmt.settings')->get('source_list_limit'));
      }

      $result = $query->execute();
      $entity_ids = $result->fetchCol();
      $entities = array();

      if (!empty($entity_ids)) {
        $entities = \Drupal::entityTypeManager()->getStorage($entity_type_id)->loadMultiple($entity_ids);
      }
      return $entities;
    }
    return array();
  }

  /**
   * Returns the query for translatable entities of a given type.
   *
   * Additionally you can specify entity property conditions.
   *
   * @param string $entity_type_id
   *   Drupal entity type.
   * @param array $property_conditions
   *   Entity properties. There is no value processing so caller must make sure
   *   the provided entity property exists for given entity type and its value
   *   is processed.
   *
   * @return \Drupal\Core\Entity\Query\QueryInterface|NULL
   *   The query for translatable entities or NULL if the query can not be
   *   built for this entity type.
   */
  public static function buildTranslatableEntitiesQuery($entity_type_id, $property_conditions = array()) {

    // If given entity type does not have entity translations enabled, no reason
    // to continue.
    $enabled_types = \Drupal::service('plugin.manager.tmgmt.source')->createInstance('content')->getItemTypes();
    if (!isset($enabled_types[$entity_type_id])) {
      return NULL;
    }

    $langcodes = array_keys(\Drupal::languageManager()->getLanguages());
    $languages = array_combine($langcodes, $langcodes);

    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    $label_key = $entity_type->getKey('label');

    $id_key = $entity_type->getKey('id');
    $query = \Drupal::database()->select($entity_type->getBaseTable(), 'e');
    $query->addTag('tmgmt_entity_get_translatable_entities');
    $query->addField('e', $id_key);
    $query->distinct();

    $langcode_table_alias = 'e';
    // @todo: Discuss if search should work on latest, default or all revisions.
    //   See https://www.drupal.org/project/tmgmt/issues/2984554.
    $data_table = $entity_type->isRevisionable() ? $entity_type->getRevisionDataTable() : $entity_type->getDataTable();
    if ($data_table) {
      $langcode_table_alias = $query->innerJoin($data_table, 'data_table', '%alias.' . $id_key . ' = e.' . $id_key . ' AND %alias.default_langcode = 1');
    }

    $property_conditions += array('langcode' => $langcodes);

    // Searching for sources with missing translation.
    if (!empty($property_conditions['target_status']) && !empty($property_conditions['target_language']) && in_array($property_conditions['target_language'], $languages)) {

      $translation_table_alias = \Drupal::database()->escapeTable('translation_' . $property_conditions['target_language']);
      $query->leftJoin($data_table, $translation_table_alias, "%alias.$id_key= e.$id_key AND %alias.langcode = :language",
        array(':language' => $property_conditions['target_language']));

      // Exclude entities with having source language same as the target language
      // we search for.
      $query->condition($langcode_table_alias . '.langcode', $property_conditions['target_language'], '<>');

      if ($property_conditions['target_status'] == 'untranslated_or_outdated') {
        $or = \Drupal::database()->condition('OR');
        $or->isNull("$translation_table_alias.langcode");
        $or->condition("$translation_table_alias.content_translation_outdated", 1);
        $query->condition($or);
      }
      elseif ($property_conditions['target_status'] == 'outdated') {
        $query->condition("$translation_table_alias.content_translation_outdated", 1);
      }
      elseif ($property_conditions['target_status'] == 'untranslated') {
        $query->isNull("$translation_table_alias.langcode");
      }
    }

    // Remove the condition so we do not try to add it again below.
    unset($property_conditions['target_language']);
    unset($property_conditions['target_status']);

    // Searching for the source label.
    if (!empty($label_key) && isset($property_conditions[$label_key])) {
      $search_token = trim($property_conditions[$label_key]);

      if ($search_token !== '') {
        $query->condition('data_table.' . $label_key, '%' . \Drupal::database()->escapeLike($search_token) . '%', 'LIKE');
      }

      unset($property_conditions[$label_key]);
    }

    if ($bundle_key = $entity_type->getKey('bundle')) {
      $bundles = array();
      $content_translation_manager = \Drupal::service('content_translation.manager');
      foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type_id)) as $bundle) {
        if ($content_translation_manager->isEnabled($entity_type_id, $bundle)) {
          $bundles[] = $bundle;
        }
      }
      if (!$bundles) {
        return NULL;
      }

      // If we have type property add condition.
      if (isset($property_conditions[$bundle_key])) {
        $query->condition('e.' . $bundle_key, $property_conditions[$bundle_key]);
        // Remove the condition so we do not try to add it again below.
        unset($property_conditions[$bundle_key]);
      }
      // If not, query db only for translatable node types.
      else {
        $query->condition('e.' . $bundle_key, $bundles, 'IN');
      }
    }

    // Add remaining query conditions which are expected to be handled in a
    // generic way.
    foreach ($property_conditions as $property_name => $property_value) {
      $alias = $property_name == 'langcode' ? $langcode_table_alias : 'e';
      $query->condition($alias . '.' . $property_name, (array) $property_value, 'IN');
    }
    $query->orderBy($entity_type->getKey('id'), 'DESC');

    return $query;
  }

  /**
   * Creates continuous job items for entity.
   *
   * Batch callback function.
   */
  public static function createContinuousJobItemsBatch($item_type, array $search_property_params, &$context) {
    if (empty($context['sandbox'])) {
      $context['sandbox']['offset'] = 0;
      $context['results']['job_items'] = 0;
      $context['sandbox']['progress'] = 0;
      $query = static::buildTranslatableEntitiesQuery($item_type, $search_property_params);
      $context['sandbox']['max'] = $query->countQuery()->execute()->fetchField();
    }
    $limit = \Drupal::config('tmgmt.settings')->get('source_list_limit');
    $entities = static::getTranslatableEntities($item_type, $search_property_params, FALSE, $context['sandbox']['offset'], $limit);
    $context['sandbox']['offset'] += $limit;

    // Loop through entities and add them to continuous jobs.
    foreach ($entities as $entity) {
      $context['results']['job_items'] += tmgmt_content_create_continuous_job_items($entity);
      $context['sandbox']['progress']++;
    }

    $context['message'] = t('Processed @number sources out of @max', array('@number' => $context['sandbox']['progress'], '@max' => $context['sandbox']['max']));
    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
    }
    elseif (count($entities) < $limit) {
      $context['finished'] = 1;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function reviewForm(array $form, FormStateInterface $form_state, JobItemInterface $item) {
    $form = parent::reviewForm($form, $form_state, $item);

    // Only proceed to display the content moderation form if the job item is
    // either active or reviewable.
    if (!$item->isNeedsReview() && !$item->isActive()) {
      return $form;
    }

    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = ContentEntitySource::load($item->getItemType(), $item->getItemId());

    if (!$form_state->isRebuilding() && $entity) {
      // In case the original entity is moderated, allow users to update the
      // content moderation state of the translation.
      if (ContentEntitySource::isModeratedEntity($entity)) {
        $form['moderation_state'] = $this->buildContentModerationElement($item, $entity);
      }
      // For non-moderated publishable entities, build a publish state form.
      elseif ($entity instanceof EntityPublishedInterface) {
        $form['status'] = $this->buildPublishStateElement($item, $entity);
      }
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function reviewFormSubmit(array $form, FormStateInterface $form_state, JobItemInterface $item) {
    // At this point, we don't need to check whether an entity is moderated or
    // publishable. Instead, we look for a specific key that may be set.
    if ($form_state->hasValue(['moderation_state', 'new_state'])) {
      // We are using a special #moderation_state key to carry the information
      // about the new moderation state value.
      // See \Drupal\tmgmt_content\Plugin\tmgmt\Source\ContentEntitySource::doSaveTranslations()
      $moderation_state = (array) $form_state->getValue(['moderation_state', 'new_state']);
      $item->updateData(['#moderation_state'], $moderation_state, TRUE);
    }
    elseif ($form_state->hasValue(['status', 'published'])) {
      $published = (array) (bool) $form_state->getValue(['status', 'published']);
      $item->updateData(['#published'], $published, TRUE);
    }

    parent::reviewFormSubmit($form, $form_state, $item);
  }

  /**
   * Build a publish state element.
   *
   * @param \Drupal\tmgmt\JobItemInterface $item
   *   The job item.
   * @param \Drupal\Core\Entity\EntityPublishedInterface $entity
   *   The source publishable entity.
   *
   * @return array
   *   A publish state form element.
   */
  protected function buildPublishStateElement(JobItemInterface $item, EntityPublishedInterface $entity) {
    $element = [
      '#type' => 'fieldset',
      '#title' => $this->t('Translation publish status'),
      '#tree' => TRUE,
    ];
    $published = $item->getData(['#published'], 0);
    $default_value = isset($published[0]) ? $published[0] : $entity->isPublished();

    $published_title = $this->t('Published');
    $published_field = $entity->getEntityType()->getKey('published');
    if ($entity instanceof FieldableEntityInterface && $entity->hasField($published_field)) {
      $published_field_definition = $entity->get($published_field)->getFieldDefinition();
      $published_title = $published_field_definition->getConfig($entity->bundle())->getLabel();
      if (!$published_field_definition->isTranslatable()) {
        $published_title = $this->t('@published_title (all languages)', [
          '@published_title' => $published_title,
        ]);
      }
    }

    $element['published'] = [
      '#type' => 'checkbox',
      '#default_value' => $default_value,
      '#title' => $published_title,
    ];

    return $element;
  }

  /**
   * Build a content moderation elemenet for the translation.
   *
   * @param \Drupal\tmgmt\JobItemInterface $item
   *   The job item.
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The source moderated entity.
   *
   * @return array
   *   A content moderation form element.
   */
  protected function buildContentModerationElement(JobItemInterface $item, ContentEntityInterface $entity) {
    $element = [];

    /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
    $moderation_info = \Drupal::service('content_moderation.moderation_information');
    $workflow = $moderation_info->getWorkflowForEntity($entity);
    $moderation_validator = \Drupal::service('content_moderation.state_transition_validation');

    // Extract the current moderation state stored within the special key.
    $moderation_state = $item->getData(['#moderation_state'], 0);
    $current_state = isset($moderation_state[0]) ? $moderation_state[0] : $entity->get('moderation_state')->value;
    $default = $workflow->getTypePlugin()->getState($current_state);

    // Get a list of valid transitions.
    /** @var \Drupal\workflows\Transition[] $transitions */
    $transitions = $moderation_validator->getValidTransitions($entity, \Drupal::currentUser());

    $transition_labels = [];
    $default_value = NULL;
    foreach ($transitions as $transition) {
      $transition_to_state = $transition->to();
      $transition_labels[$transition_to_state->id()] = $transition_to_state->label();
      if ($default->id() === $transition_to_state->id()) {
        $default_value = $default->id();
      }
    }
    // Get the state of the new config, if not set fallback to the current one.
    if ($default_moderation_state = \Drupal::config('tmgmt_content.settings')->get('default_moderation_states.' . $workflow->id())) {
      $default_value = $default_moderation_state;
    }

    // See \Drupal\content_moderation\Plugin\Field\FieldWidget\ModerationStateWidget::formElement()
    $element += [
      '#type' => 'container',
      '#tree' => TRUE,
      'current' => [
        '#type' => 'item',
        '#title' => $this->t('Current source state'),
        '#markup' => $default->label(),
        '#wrapper_attributes' => [
          'class' => ['container-inline'],
        ],
      ],
      'new_state' => [
        '#type' => 'select',
        '#title' => $this->t('Translation state'),
        '#options' => $transition_labels,
        '#default_value' => $default_value,
        '#access' => !empty($transition_labels),
        '#wrapper_attributes' => [
          'class' => ['container-inline'],
        ],
      ],
    ];

    $element['#theme'] = ['entity_moderation_form'];
    $element['#attached']['library'][] = 'content_moderation/content_moderation';

    return $element;
  }

}

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

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