class ContentEntitySourcePluginUi

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.

Hierarchy

Expanded class hierarchy of ContentEntitySourcePluginUi

Related topics

File

sources/content/src/ContentEntitySourcePluginUi.php, line 24

Namespace

Drupal\tmgmt_content
View 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,
      );
    }
    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]);
      }
      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);
      }
      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;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ContentEntitySourcePluginUi::$pagerLimit public property Entity source list items limit.
ContentEntitySourcePluginUi::buildContentModerationElement protected function Build a content moderation elemenet for the translation.
ContentEntitySourcePluginUi::buildPublishStateElement protected function Build a publish state element.
ContentEntitySourcePluginUi::buildTranslatableEntitiesQuery public static function Returns the query for translatable entities of a given type.
ContentEntitySourcePluginUi::createContinuousJobItemsBatch public static function Creates continuous job items for entity.
ContentEntitySourcePluginUi::getTranslatableBundles function A function to get entity translatable bundles.
ContentEntitySourcePluginUi::getTranslatableEntities public static function Gets translatable entities of a given type.
ContentEntitySourcePluginUi::overviewForm public function Builds the overview form for the source entities. Overrides SourcePluginUiBase::overviewForm
ContentEntitySourcePluginUi::overviewFormHeader public function Gets overview form header.
ContentEntitySourcePluginUi::overviewFormValidate public function Overrides SourcePluginUiBase::overviewFormValidate
ContentEntitySourcePluginUi::overviewRow public function Builds a table row for overview form.
ContentEntitySourcePluginUi::overviewSearchFormPart public function Builds search form for entity sources overview. Overrides SourcePluginUiBase::overviewSearchFormPart
ContentEntitySourcePluginUi::overviewSubmitToContinuousJobs public function Adds selected sources to continuous jobs.
ContentEntitySourcePluginUi::reviewForm public function Form callback for the job item review form. Overrides SourcePluginUiBase::reviewForm
ContentEntitySourcePluginUi::reviewFormSubmit public function Submit callback for the job item review form. Overrides SourcePluginUiBase::reviewFormSubmit
SourcePluginUiBase::buildTranslationStatus function Builds the translation status render array with source and job item status.
SourcePluginUiBase::getLanguageHeader protected function Gets languages form header.
SourcePluginUiBase::hook_views_default_views public function Overrides SourcePluginUiInterface::hook_views_default_views
SourcePluginUiBase::overviewFormSubmit public function Submit handler for the source entities overview form.
SourcePluginUiBase::overviewSearchFormRedirect public function Performs redirect with search params appended to the uri.
SourcePluginUiBase::reviewDataItemElement public function Form callback for the data item element form. Overrides SourcePluginUiInterface::reviewDataItemElement
SourcePluginUiBase::reviewFormValidate public function Validation callback for the job item review form. Overrides SourcePluginUiInterface::reviewFormValidate