lightning_scheduler-8.x-1.x-dev/src/Plugin/Field/FieldWidget/ModerationStateWidget.php

src/Plugin/Field/FieldWidget/ModerationStateWidget.php
<?php

namespace Drupal\lightning_scheduler\Plugin\Field\FieldWidget;

use Drupal\Component\Serialization\Json;
use Drupal\content_moderation\Plugin\Field\FieldWidget\ModerationStateWidget as BaseModerationStateWidget;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\lightning_scheduler\TransitionManager;
use Drupal\lightning_scheduler\TransitionSet;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Scheduler extension of Content Moderation's widget.
 *
 * @internal
 *   This is an internal part of Lightning Scheduler and may be changed or
 *   removed at any time without warning. It should not be used by external
 *   code in any way.
 */
final class ModerationStateWidget extends BaseModerationStateWidget {

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $configuration['third_party_settings'] += [
      'lightning_scheduler' => [
        'time_step' => $container->get('config.factory')->get('lightning_scheduler.settings')->get('time_step'),
      ],
    ];
    return parent::create($container, $configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element = parent::formElement($items, $delta, $element, $form, $form_state);

    $entity = $items->getEntity();
    assert($entity instanceof ContentEntityInterface);

    // The entity must have the proper fields.
    $has_fields = $entity->hasField('scheduled_transition_date') && $entity->hasField('scheduled_transition_state');
    if (! $has_fields) {
      return $element;
    }

    $states = $this->getStates($entity);

    // The latest revision, if there is one, is the canonical source of truth
    // regarding scheduled transitions.
    /** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
    $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId());
    if (!$entity->isNew() && $storage->getEntityType()->isRevisionable() && $latest_revision_id = $storage->getLatestRevisionId($entity->id())) {
      $latest_revision = $storage->loadRevision($latest_revision_id) ?: $entity;
    }
    else {
      $latest_revision = $entity;
    }

    $transition_set = new TransitionSet(
      $latest_revision->get('scheduled_transition_date'),
      $latest_revision->get('scheduled_transition_state')
    );

    // Get the allow_past_dates configuration setting.
    $allow_past_dates = \Drupal::configFactory()
      ->get('lightning_scheduler.settings')
      ->get('allow_past_dates');

    $element['scheduled_transitions'] = [
      '#type' => 'html_tag',
      '#tag' => 'TransitionSet',
      '#attributes' => [
        'states' => Json::encode($states),
        'step' => $this->getThirdPartySetting('lightning_scheduler', 'time_step', 60),
      ],
      '#attached' => [
        'library' => ['lightning_scheduler/widget'],
        'drupalSettings' => [
          'lightning_scheduler' => [
            'allow_past_dates' => $allow_past_dates,
          ],
        ],
      ],
      'data' => [
        '#type' => 'hidden',
        '#entity_uuid' => $entity->uuid(),
        '#element_validate' => [
          [
            TransitionManager::class,
            'validate',
          ],
          [$this, 'storeValue'],
        ],
        '#default_value' => $transition_set->toJSON(),
        '#process' => [
          [$this, 'processComponentInput'],
        ],
      ],
    ];

    return $element;
  }

  /**
   * #process callback for the scheduler component's input element.
   *
   * @param array $element
   *   The unprocessed element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current form state.
   *
   * @return array
   *   The processed element.
   */
  public function processComponentInput(array $element, FormStateInterface $form_state) {
    $key = $element['#parents'];
    if ($form_state->hasValue($key)) {
      $element['#default_value'] = $form_state->getValue($key);
    }
    return $element;
  }

  /**
   * Validation method that accesses the hidden input element, and stores its
   * value in the form state.
   *
   * @param array $element
   *   The hidden input.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state to update.
   */
  public function storeValue(array $element, FormStateInterface $form_state) {
    if ($form_state->getErrors()) {
      return;
    }
    assert(! empty($element['#entity_uuid']));

    $decoded = Json::decode($element['#value']);
    assert(is_array($decoded));
    $transition_storage = $form_state->getValue('transition_storage') ?: [];
    // Support multiple widgets on one form (e.g. Inline Entity Form).
    $uuid = $element['#entity_uuid'];
    $transition_storage[$uuid] = $decoded;
    $form_state->setValue('transition_storage', $transition_storage);
  }

  /**
   * {@inheritdoc}
   */
  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
    parent::extractFormValues($items, $form, $form_state);

    $transitions = $form_state->getValue('transition_storage');
    $entity = $items->getEntity();
    $uuid = $entity->uuid();

    // Do not use empty() here, because it's possible that the user is trying to
    // clear all scheduled transitions, which means $transitions[$uuid] will
    // be an empty array.
    if (! isset($transitions[$uuid])) {
      return;
    }

    $states = array_map(function (array $transition) {
      assert(!empty($transition['state']) && is_string($transition['state']));

      return [
        'value' => $transition['state'],
      ];
    }, $transitions[$uuid]);

    $dates = array_map(function (array $transition) {
      return [
        'value' => gmdate(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $transition['when']),
      ];
    }, $transitions[$uuid]);

    assert(count($states) === count($dates));

    $entity
      ->set('scheduled_transition_state', $states)
      ->set('scheduled_transition_date', $dates);
  }

  /**
   * Returns an array of available workflow states for an entity.
   *
   * A workflow state is considered "available" if the current user has
   * permission to use or schedule it.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The entity which has the workflow.
   *
   * @return array
   *   An associative array where the keys are the workflow state IDs, and the
   *   values are the states' human-readable labels.
   */
  private function getStates(ContentEntityInterface $entity) {
    $states = [];

    $workflow = $this->moderationInformation->getWorkflowForEntity($entity);

    foreach ($workflow->getTypePlugin()->getTransitions() as $transition) {
      $base_permission = $workflow->id() . ' transition ' . $transition->id();

      if ($this->currentUser->hasPermission("schedule $base_permission") || $this->currentUser->hasPermission("use $base_permission")) {
        $to_state = $transition->to();
        $states[ $to_state->id() ] = $to_state->label();
      }
    }
    return $states;
  }

}

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

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