public function WorkflowTransition::execute in Workflow 8
Execute a transition (change state of an entity).
A Scheduled Transition shall only be saved, unless the 'schedule' property is set.
@usage $transition->schedule(FALSE); $to_sid = $transition->execute(TRUE);
Parameters
bool $force: If set to TRUE, workflow permissions will be ignored.
Return value
string New state ID. If execution failed, old state ID is returned,
Overrides WorkflowTransitionInterface::execute
1 call to WorkflowTransition::execute()
- WorkflowTransition::executeAndUpdateEntity in src/
Entity/ WorkflowTransition.php - Executes a transition (change state of an entity), from OUTSIDE the entity.
File
- src/
Entity/ WorkflowTransition.php, line 436
Class
- WorkflowTransition
- Implements an actual, executed, Transition.
Namespace
Drupal\workflow\EntityCode
public function execute($force = FALSE) {
// Load the entity, if not already loaded.
// This also sets the (empty) $revision_id in Scheduled Transitions.
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $this
->getTargetEntity();
// Load explicit User object (not via $transition) for adding Role later.
/** @var \Drupal\user\UserInterface $user */
$user = $this
->getOwner();
$from_sid = $this
->getFromSid();
$to_sid = $this
->getToSid();
$field_name = $this
->getFieldName();
$comment = $this
->getComment();
// Create a label to identify this transition,
// even upon insert, when id() is not set, yet.
$label = $from_sid . '-' . $to_sid;
static $static_info = NULL;
$entity_id = $entity
->id();
// For non-default revisions, there is no way of executing the same transition twice in one call.
// Set a random identifier since we won't be needing to access this variable later.
if ($entity instanceof RevisionableInterface && !$entity
->isDefaultRevision()) {
$entity_id = $entity_id . $entity
->getRevisionId();
}
if (isset($static_info[$entity_id][$field_name][$label]) && !$this
->isEmpty()) {
// Error: this Transition is already executed.
// On the development machine, execute() is called twice, when
// on an Edit Page, the entity has a scheduled transition, and
// user changes it to 'immediately'.
// Why does this happen?? ( BTW. This happens with every submit.)
// Remedies:
// - search root cause of second call.
// - try adapting code of transition->save() to avoid second record.
// - avoid executing twice.
$message = 'Transition is executed twice in a call. The second call for
@entity_type %entity_id is not executed.';
$this
->logError($message);
// Return the result of the last call.
return $static_info[$entity_id][$field_name][$label];
// <-- exit !!!
}
// OK. Prepare for next round. Do not set last_sid!!
$static_info[$entity_id][$field_name][$label] = $from_sid;
// Make sure $force is set in the transition, too.
if ($force) {
$this
->force($force);
}
$force = $this
->isForced();
// Store the transition(s), so it can be easily fetched later on.
// This is a.o. used in:
// - hook_entity_update to trigger 'transition post',
// - hook workflow_access_node_access_records.
$entity->workflow_transitions[$field_name] = $this;
if (!$this
->isValid()) {
return $from_sid;
// <-- exit !!!
}
// @todo Move below code to $this->isAllowed().
// If the state has changed, check the permissions.
// No need to check if Comments or attached fields are filled.
if ($this
->hasStateChange()) {
// Make sure this transition is allowed by workflow module Admin UI.
if (!$force) {
$user
->addRole(WORKFLOW_ROLE_AUTHOR_RID);
}
if (!$this
->isAllowed($user, $force)) {
$message = 'User %user not allowed to go from state %sid1 to %sid2';
$this
->logError($message);
return FALSE;
// <-- exit !!!
}
// Make sure this transition is valid and allowed for the current user.
// Invoke a callback indicating a transition is about to occur.
// Modules may veto the transition by returning FALSE.
// (Even if $force is TRUE, but they shouldn't do that.)
// P.S. The D7 hook_workflow 'transition permitted' is removed, in favour of below hook_workflow 'transition pre'.
$permitted = \Drupal::moduleHandler()
->invokeAll('workflow', [
'transition pre',
$this,
$user,
]);
// Stop if a module says so.
if (in_array(FALSE, $permitted, TRUE)) {
// @todo There is a watchdog error, but no UI-error. Is this OK?
$message = 'Transition vetoed by module.';
$this
->logError($message, 'notice');
return FALSE;
// <-- exit !!!
}
}
/*
* Output: process the transition.
*/
if ($this
->isScheduled()) {
/*
* Log the transition in {workflow_transition_scheduled}.
*/
$this
->save();
}
else {
// The transition is allowed, but not scheduled.
// Let other modules modify the comment.
// The transition (in context) contains all relevant data.
$context = [
'transition' => $this,
];
\Drupal::moduleHandler()
->alter('workflow_comment', $comment, $context);
$this
->setComment($comment);
$this->isExecuted = TRUE;
if (!$this
->isEmpty()) {
/*
* Log the transition in {workflow_transition_history}.
*/
$this
->save();
// Register state change with watchdog.
if ($this
->hasStateChange() && !empty($this
->getWorkflow()
->getSetting('watchdog_log'))) {
if ($this
->getEntityTypeId() == 'workflow_scheduled_transition') {
$message = 'Scheduled state change of @entity_type_label %entity_label to %sid2 executed';
}
else {
$message = 'State of @entity_type_label %entity_label set to %sid2';
}
$this
->logError($message, 'notice');
}
// Notify modules that transition has occurred.
// Action triggers should take place in response to this callback, not the 'transaction pre'.
//
// \Drupal::moduleHandler()->invokeAll('workflow', ['transition post', $this, $user]);
// We have a problem here with Rules, Trigger, etc. when invoking
// 'transition post': the entity has not been saved, yet. we are still
// IN the transition, not AFTER. Alternatives:
// 1. Save the field here explicitly, using field_attach_save;
// 2. Move the invoke to another place: hook_entity_insert(), hook_entity_update();
// 3. Rely on the entity hooks. This works for Rules, not for Trigger.
// --> We choose option 2:
// @todo D8: figure out usage of $entity->workflow_transitions[$field_name].
// - First, $entity->workflow_transitions[] is set for easy re-fetching.
// - Then, post_execute() is invoked via workflow_entity_insert(), _update().
}
}
// Save value in static from top of this function.
$static_info[$entity_id][$field_name][$label] = $to_sid;
return $to_sid;
}