workflow-8.x-1.x-dev/src/Entity/WorkflowConfigTransition.php

src/Entity/WorkflowConfigTransition.php
<?php

namespace Drupal\workflow\Entity;

use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Serialization\Attribute\JsonSchema;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\user\UserInterface;
use Drupal\workflow\WorkflowTypeAttributeTrait;
use Drupal\workflow\WorkflowURLRouteParametersTrait;

/**
 * Workflow configuration entity to persistently store configuration.
 *
 * @ConfigEntityType(
 *   id = "workflow_config_transition",
 *   label = @Translation("Workflow config transition"),
 *   label_singular = @Translation("Workflow config transition"),
 *   label_plural = @Translation("Workflow config transitions"),
 *   label_count = @PluralTranslation(
 *     singular = "@count Workflow config transition",
 *     plural = "@count Workflow config transitions",
 *   ),
 *   module = "workflow",
 *   translatable = FALSE,
 *   handlers = {
 *     "form" = {
 *        "delete" = "\Drupal\Core\Entity\EntityDeleteForm",
 *      }
 *   },
 *   admin_permission = "administer workflow",
 *   config_prefix = "transition",
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "label",
 *   },
 *   config_export = {
 *     "id",
 *     "label",
 *     "module",
 *     "from_sid",
 *     "to_sid",
 *     "roles",
 *   },
 *   links = {
 *     "collection" = "/admin/config/workflow/workflow/{workflow_type}/transitions",
 *   },
 * )
 */
class WorkflowConfigTransition extends ConfigEntityBase implements WorkflowConfigTransitionInterface, MarkupInterface {
  /*
   * Add variables and get/set methods for Workflow property.
   */
  use WorkflowTypeAttributeTrait;
  /*
   * Provide URL route parameters for entity links.
   */
  use WorkflowURLRouteParametersTrait;
  /*
   * Provide string translation capabilities.
   */
  use StringTranslationTrait;

  /**
   * Transition data.
   */

  /**
   * The Transition ID.
   *
   * @var string
   */
  public $id;

  /**
   * The From state ID.
   *
   * @var string
   */
  public $from_sid = '';

  /**
   * The From state Object. Used to fetch data faster.
   *
   * @var \Drupal\workflow\Entity\WorkflowState
   */
  private $from_state = NULL;

  /**
   * The To state ID.
   *
   * @var string
   */
  public $to_sid = '';

  /**
   * The To state Object. Used to fetch data faster.
   *
   * @var \Drupal\workflow\Entity\WorkflowState
   */
  private $to_state = NULL;

  /**
   * The list of roles that are allowed to use this Transition.
   *
   * @var array
   */
  public $roles = [];

  /**
   * The module implementing this object, for config_export.
   *
   * @var string
   */
  protected $module = 'workflow';

  /*
   * Entity class functions.
   */

  /**
   * {@inheritdoc}
   *
   * @return \Drupal\workflow\Entity\WorkflowConfigTransition[]
   *   The Config Transition.
   */
  public static function loadMultiple(?array $ids = NULL) {
    if ($transitions = parent::loadMultiple($ids)) {
      // Sort the configTransitions on state weight.
      // @todo Sort configTransitions via 'orderby: weight' in schema file.
      uasort($transitions, [
        'Drupal\workflow\Entity\WorkflowConfigTransition',
        'sort',
      ]);
    }
    return $transitions;
  }

  /**
   * {@inheritdoc}
   *
   * Calls static::label() and is used in workflow_state_allowed_values().
   */
  #[JsonSchema(['type' => 'string', 'description' => 'Workflow Transition label'])]
  public function __toString() {
    // Get the label of the transition, and if empty of the target state.
    // Beware: the target state may not exist, since it can be invented
    // by custom code in the above drupal_alter() hook.
    if (!$label = $this->label()) {
      $label = $this->getToState()?->label() ?? '';
    }
    return (string) $this->t('@label', ['@label' => $label]);
  }

  /**
   * {@inheritdoc}
   *
   * Required for check on MarkupInterface in views\filter\WorkflowState.
   */
  public function jsonSerialize(): mixed {
    return $this->__toString();
  }

  /**
   * Helper function for __construct.
   *
   * Used for WorkflowTransition ánd WorkflowScheduledTransition.
   */
  public function setValues() {
    $state = WorkflowState::load($this->to_sid ? $this->to_sid : $this->from_sid);
    if ($state) {
      $this->setWorkflow($state->getWorkflow());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    parent::calculateDependencies();
    $this->addDependency('config', $this->getFromState()->getConfigDependencyName());
    $this->addDependency('config', $this->getToState()->getConfigDependencyName());
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function save() {
    /** @var \Drupal\workflow\Entity\Workflow $workflow */
    $workflow = $this->getWorkflow();

    if (!$workflow) {
      return parent::save();
    }

    // To avoid double posting, check if this (new) transition already exist.
    if ($this->isNew()) {
      $config_transitions = $workflow->getTransitionsByStateId($this->from_sid, $this->to_sid);
      $config_transition = reset($config_transitions);
      if ($config_transition) {
        // Copy the machine_name.
        $tid = $config_transition->id();
      }
      else {
        // Create the machine_name.
        $wid = $workflow->id();
        $tid = implode('', [
          $wid,
          substr($this->from_sid, strlen($wid)),
          substr($this->to_sid, strlen($wid)),
        ]);
        $tid = substr($tid, 0, ConfigEntityStorage::MAX_ID_LENGTH);
      }
      $this->set('id', $tid);

    }

    $status = parent::save();
    if ($status) {
      // Save in current workflow for the remainder of this page request.
      // Keep in sync with Workflow::getTransitions() !
      $workflow->transitions[$this->id()] = $this;
    }

    return $status;
  }

  /**
   * {@inheritdoc}
   */
  public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) {
    // Sort the entities using the entity class's sort() method.
    // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
    /** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $a */
    /** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $b */
    if (!$a->getFromSid() || !$b->getFromSid()) {
      return 0;
    }

    // First sort on From-State.
    $from_state_a = $a->getFromState();
    $from_state_b = $b->getFromState();
    $sort_order = $from_state_a->weight <=> $from_state_b->weight;

    if ($sort_order == 0) {
      // Then sort on To-State.
      $to_state_a = $a->getToState();
      $to_state_b = $b->getToState();
      $sort_order = $to_state_a->weight <=> $to_state_b->weight;
    }
    return $sort_order;
  }

  /**
   * Property functions.
   */

  /**
   * {@inheritdoc}
   */
  public function getFromState(): ?WorkflowState {
    // @todo return $this->getWorkflow()->getState($this->getFromSid());
    // return WorkflowState::load($this->getFromSid());
    $sid = $this->getFromSid();
    if ($this->from_state?->id() !== $sid) {
      // $sid may have been changed without us knowing.
      $this->from_state = WorkflowState::load($sid);
    }
    return $this->from_state;
  }

  /**
   * {@inheritdoc}
   */
  public function getToState(): ?WorkflowState {
    // @todo return $this->getWorkflow()->getState($this->getToSid());
    // return WorkflowState::load($this->getToSid());
    $sid = $this->getToSid();
    $this->to_state ??= WorkflowState::load($sid);
    if ($this->to_state?->id() !== $sid) {
      // $sid may have been changed without us knowing.
      $this->to_state = WorkflowState::load($sid);
    }
    return $this->to_state;
  }

  /**
   * {@inheritdoc}
   */
  public function getFromSid(): string {
    return $this->from_sid;
  }

  /**
   * {@inheritdoc}
   */
  public function getToSid(): string {
    return $this->to_sid;
  }

  /**
   * {@inheritdoc}
   */
  public function getWorkflowId(): ?string {
    // Get the Workflow ID, accommodating WorkflowTypeAttributeTrait.
    if (!empty($this->wid)) {
      return $this->wid;
    }

    $wid = $this->getFromState()->getWorkflowId();
    $this->setWorkflowId($wid);
    return $wid;
  }

  /**
   * {@inheritdoc}
   */
  public function isAllowed(UserInterface $user, $force = FALSE): bool {

    // N.B. Keep aligned between WorkflowState, ~Transition, ~HistoryAccess.
    if ($force) {
      return TRUE;
    }

    if (!$this->hasStateChange()) {
      // Anyone may save an entity without changing state.
      return TRUE;
    }

    // Get permission from admin/people/permissions page.
    if (workflow_current_user($user)->isSuperUser($this)) {
      // Get permission from admin/people/permissions page.
      // Superuser is special (might be cron).
      // And $force allows Rules to cause transition.
      return TRUE;
    }

    // Get permission from admin/config/workflow/workflow/TYPE/transition_roles.
    return TRUE == array_intersect($user->getRoles(), $this->roles);
  }

  /**
   * {@inheritdoc}
   */
  public function hasStateChange(): bool {
    return $this->getFromSid() !== $this->getToSid();
  }

}

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

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