public function WorkflowTransition::execute in Workflow 7.2
Same name and namespace in other branches
- 7 includes/Entity/WorkflowTransition.php \WorkflowTransition::execute()
Execute a transition (change state of a node).
Parameters
bool $force: If set to TRUE, workflow permissions will be ignored.
Return value
int New state ID. If execution failed, old state ID is returned,
deprecated workflow_execute_transition() --> WorkflowTransition::execute().
File
- includes/
Entity/ WorkflowTransition.php, line 263 - Contains workflow\includes\Entity\WorkflowTransition. Contains workflow\includes\Entity\WorkflowTransitionController.
Class
- WorkflowTransition
- Implements an actual Transition.
Code
public function execute($force = FALSE) {
$user = $this
->getUser();
$old_sid = $this->old_sid;
$new_sid = $this->new_sid;
// Load the entity, if not already loaded.
// This also sets the (empty) $revision_id in Scheduled Transitions.
$entity = $this
->getEntity();
// Only after getEntity(), the following are surely set.
$entity_type = $this->entity_type;
$entity_id = $this->entity_id;
$field_name = $this->field_name;
// Make sure $force is set in the transition, too.
if ($force) {
$this
->force($force);
}
$force = $this
->isForced();
// Prepare an array of arguments for error messages.
$args = array(
'%user' => isset($user->name) ? $user->name : '',
'%old' => $old_sid,
'%new' => $new_sid,
);
if (!$this
->getOldState()) {
drupal_set_message($message = t('You tried to set a Workflow State, but
the entity is not relevant. Please contact your system administrator.'), 'error');
$message = 'Setting a non-relevant Entity from state %old to %new';
$uri = entity_uri($entity_type, $entity);
watchdog('workflow', $message, $args, WATCHDOG_ERROR, l('view', $uri['path']));
return $old_sid;
}
// Check if the state has changed.
$state_changed = $old_sid != $new_sid;
// If so, check the permissions.
if ($state_changed) {
// State has changed. Do some checks upfront.
if (!$force) {
// Make sure this transition is allowed by workflow module Admin UI.
$roles = array_keys($user->roles);
$roles = array_merge(array(
WORKFLOW_ROLE_AUTHOR_RID,
), $roles);
if (!$this
->isAllowed($roles, $user, $force)) {
watchdog('workflow', 'User %user not allowed to go from state %old to %new', $args, WATCHDOG_NOTICE);
// If incorrect, quit.
return $old_sid;
}
}
if (!$force) {
// Make sure this transition is allowed by custom module.
// @todo D8: remove, or replace by 'transition pre'. See WorkflowState::getOptions().
// @todo D8: replace all parameters that are included in $transition.
$permitted = module_invoke_all('workflow', 'transition permitted', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name, $this, $user);
// Stop if a module says so.
if (in_array(FALSE, $permitted, TRUE)) {
watchdog('workflow', 'Transition vetoed by module.');
return $old_sid;
}
}
// 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.)
$permitted = module_invoke_all('workflow', 'transition pre', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name, $this);
// Stop if a module says so.
if (in_array(FALSE, $permitted, TRUE)) {
watchdog('workflow', 'Transition vetoed by module.');
return $old_sid;
}
}
elseif ($this->comment) {
// No need to ask permission for adding comments.
// Since you should not add actions to a 'transition pre' event, there is
// no need to invoke the event.
}
else {
// There is no state change, and no comment.
// We may need to clean up something.
}
if ($state_changed || $this->comment) {
// Store the transition, so it can be easily fetched later on.
// Store in an array, to prepare for multiple workflow_fields per entity.
// This is a.o. used in hook_entity_update to trigger 'transition post'.
// Only add the Transition once! or you will encounter endless loops in
// hook_entity_update() in workflow_actions_entity_update et all.
if (!isset($entity->workflow_transitions[$field_name])) {
$entity->workflow_transitions[$field_name] =& $this;
}
// The transition is allowed. Let other modules modify the comment.
// @todo D8: remove all but last items from $context.
$context = array(
'node' => $entity,
'sid' => $new_sid,
'old_sid' => $old_sid,
'uid' => $user->uid,
'transition' => $this,
);
drupal_alter('workflow_comment', $this->comment, $context);
}
// Now, change the database.
// Log the new state in {workflow_node}.
if (!$field_name) {
if ($state_changed || $this->comment) {
// If the node does not have an existing 'workflow' property,
// save the $old_sid there, so it can be logged.
if (!isset($entity->workflow)) {
// This is a workflow_node sid.
$entity->workflow = $old_sid;
// This is a workflow_node sid.
}
// Change the state for {workflow_node}.
// The equivalent for Field API is in WorkflowDefaultWidget::submit.
$data = array(
'nid' => $entity_id,
'sid' => $new_sid,
'uid' => isset($entity->workflow_uid) ? $entity->workflow_uid : $user->uid,
'stamp' => REQUEST_TIME,
);
workflow_update_workflow_node($data);
$entity->workflow = $new_sid;
// This is a workflow_node sid.
}
}
else {
// This is a Workflow Field.
// Until now, adding code here (instead of in workflow_execute_transition() )
// doesn't work, creating an endless loop.
// Update 10-dec-2016: the following line, added above, may have resolved that.
// if (!isset($entity->workflow_transitions[$field_name]))
/*
if ($state_changed || $this->comment) {
// Do a separate update to update the field (Workflow Field API)
// This will call hook_field_update() and WorkflowFieldDefaultWidget::submit().
// $entity->{$field_name}[$this->language] = array();
// $entity->{$field_name}[$this->language][0]['workflow']['workflow_sid'] = $new_sid;
// $entity->{$field_name}[$this->language][0]['workflow']['workflow_comment'] = $this->comment;
$entity->{$field_name}[$this->language][0]['transition'] = $this;
// Save the entity, but not through entity_save(),
// since this will check permissions again and trigger rules.
// @TODO: replace below by a workflow_field setter callback.
// The transition was successfully executed, or else a message was raised.
// entity_save($entity_type, $entity);
// or
// field_attach_update($entity_type, $entity);
// Reset the entity cache after update.
entity_get_controller($entity_type)->resetCache(array($entity_id));
$new_sid = workflow_node_current_state($entity, $entity_type, $field_name);
}
*/
}
$this->is_executed = TRUE;
if ($state_changed || $this->comment) {
// Log the transition in {workflow_node_history}.
$this
->save();
// Register state change with watchdog.
if ($state_changed) {
$workflow = $this
->getWorkflow();
// Get the workflow_settings, unified for workflow_node and workflow_field.
// @todo D8: move settings back to Workflow (like workflownode currently is).
// @todo D8: to move settings back, grep for "workflow->options" and "field['settings']".
$field = _workflow_info_field($field_name, $workflow);
if (($new_state = $this
->getNewState()) && !empty($field['settings']['watchdog_log'])) {
$entity_type_info = entity_get_info($entity_type);
$message = $this
->isScheduled() ? 'Scheduled state change of @type %label to %state_name executed' : 'State of @type %label set to %state_name';
$args = array(
'@type' => $entity_type_info['label'],
'%label' => entity_label($entity_type, $entity),
'%state_name' => $new_state
->label(),
);
$uri = entity_uri($entity_type, $entity);
watchdog('workflow', $message, $args, WATCHDOG_NOTICE, l('view', $uri['path']));
}
}
// Remove any scheduled state transitions.
foreach (WorkflowScheduledTransition::load($entity_type, $entity_id, $field_name) as $scheduled_transition) {
/* @var $scheduled_transition WorkflowScheduledTransition */
$scheduled_transition
->delete();
}
// Notify modules that transition has occurred.
// Action triggers should take place in response to this callback, not the 'transaction pre'.
if (!$field_name) {
// Now that workflow data is saved, reset stuff to avoid problems
// when Rules etc want to resave the data.
// Remember, this is only for nodes, and node_save() is not necessarily performed.
unset($entity->workflow_comment);
module_invoke_all('workflow', 'transition post', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name, $this);
entity_get_controller('node')
->resetCache(array(
$entity->nid,
));
// from entity_load(), node_save();
}
else {
// module_invoke_all('workflow', 'transition post', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name, $this);
// 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:
// - First, $entity->workflow_transitions[] is set for easy re-fetching.
// - Then, post_execute() is invoked via workflowfield_entity_insert(), _update().
}
}
return $new_sid;
}