/**
  * Deactivate a Workflow State, moving existing nodes to a given State.
  *
  * @param $new_sid
  *  the state ID, to which all affected entities must be moved. 
  *
  * @deprecated workflow_delete_workflow_states_by_sid() --> WorkflowState->deactivate() + delete()
  */
 public function deactivate($new_sid)
 {
     $current_sid = $this->sid;
     $force = TRUE;
     // Notify interested modules. We notify first to allow access to data before we zap it.
     // E.g., Node API (@todo Field API):
     // - re-parents any nodes that we don't want to orphan, whilst deactivating a State.
     // - delete any lingering node to state values.
     module_invoke_all('workflow', 'state delete', $current_sid, $new_sid, NULL, $force);
     // Re-parent any nodes that we don't want to orphan, whilst deactivating a State.
     // This is called in WorkflowState::deactivate().
     // @todo: reparent Workflow Field, whilst deactivating a state.
     if ($new_sid) {
         global $user;
         // A candidate for the batch API.
         // @TODO: Future updates should seriously consider setting this with batch.
         $comment = t('Previous state deleted');
         foreach (workflow_get_workflow_node_by_sid($current_sid) as $workflow_node) {
             // @todo: add Field support in 'state delete', by using workflow_node_history or reading current field.
             $entity_type = 'node';
             $entity = entity_load_single('node', $workflow_node->nid);
             $field_name = '';
             $transition = new WorkflowTransition($entity_type, $entity, $field_name, $current_sid, $new_sid, $user->uid, REQUEST_TIME, $comment);
             $transition->force($force);
             // Excute Transition, invoke 'pre' and 'post' events, save new state in workflow_node, save also in workflow_node_history.
             // For Workflow Node, only {workflow_node} and {workflow_node_history} are updated. For Field, also the Entity itself.
             $new_sid = workflow_execute_transition($entity_type, $entity, $field_name, $transition, $force);
         }
     }
     // Delete any lingering node to state values.
     workflow_delete_workflow_node_by_sid($current_sid);
     // Find out which transitions this state is involved in.
     $preexisting = array();
     foreach (workflow_get_workflow_transitions_by_sid_involved($current_sid) as $data) {
         $preexisting[$data->sid][$data->target_sid] = TRUE;
     }
     // Delete the transitions.
     foreach ($preexisting as $from => $array) {
         foreach (array_keys($array) as $target_id) {
             if ($transition = workflow_get_workflow_transitions_by_sid_target_sid($from, $target_id)) {
                 workflow_delete_workflow_transitions_by_tid($transition->tid);
             }
         }
     }
     // Delete the state. -- We don't actually delete, just deactivate.
     // This is a matter up for some debate, to delete or not to delete, since this
     // causes name conflicts for states. In the meantime, we just stick with what we know.
     // If you really want to delete the states, use workflow_cleanup module, or delete().
     $this->status = FALSE;
     $this->save();
     // Clear the cache.
     self::$states = array();
 }
 /**
  * Execute a transition (change state of a node).
  * @deprecated: workflow_execute_transition() --> WorkflowTransition::execute().
  *
  * @param bool $force
  *   If set to TRUE, workflow permissions will be ignored.
  *
  * @return int
  *  new state ID. If execution failed, old state ID is returned,
  */
 public function execute($force = FALSE)
 {
     global $user;
     $old_sid = $this->old_sid;
     $new_sid = $this->new_sid;
     $entity_type = $this->entity_type;
     $entity_id = $this->entity_id;
     $entity = $this->getEntity();
     // Entity may not be loaded, yet.
     $field_name = $this->field_name;
     if ($old_sid == $new_sid) {
         // Stop if not going to a different state.
         // Write comment into history though.
         if ($this->comment) {
             $this->stamp = REQUEST_TIME;
             if (!$field_name) {
                 // @todo D8: remove; this is only for Node API.
                 $entity->workflow_stamp = REQUEST_TIME;
                 workflow_update_workflow_node_stamp($entity_id, $this->stamp);
             }
             $result = module_invoke_all('workflow', 'transition pre', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name);
             $this->save();
             if (!$field_name) {
                 // @todo D8: remove; this is only for Node API.
                 unset($entity->workflow_comment);
                 // @todo D8: remove; this line is only for Node API.
             }
             $result = module_invoke_all('workflow', 'transition post', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name);
         }
         // Clear any references in the scheduled listing.
         foreach (WorkflowScheduledTransition::load($entity_type, $entity_id, $field_name) as $scheduled_transition) {
             $scheduled_transition->delete();
         }
         return $new_sid;
     }
     if (!$force) {
         // Make sure this transition is allowed.
         $result = module_invoke_all('workflow', 'transition permitted', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name);
         // Did anybody veto this choice?
         if (in_array(FALSE, $result)) {
             // If vetoed, quit.
             return $old_sid;
         }
     }
     // 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' => $this->uid, 'transition' => $this);
     drupal_alter('workflow_comment', $this->comment, $context);
     $args = array('%user' => $user->name, '%old' => $old_sid, '%new' => $new_sid);
     $transition = workflow_get_workflow_transitions_by_sid_target_sid($old_sid, $new_sid);
     if (!$transition && !$force) {
         watchdog('workflow', 'Attempt to go to nonexistent transition (from %old to %new)', $args, WATCHDOG_ERROR);
         return $old_sid;
     }
     // Make sure this transition is valid and allowed for the current user.
     // Check allow-ability of state change if user is not superuser (might be cron).
     if ($user->uid != 1 && !$force) {
         if (!workflow_transition_allowed($transition->tid, array_merge(array_keys($user->roles), array('author')))) {
             watchdog('workflow', 'User %user not allowed to go from state %old to %new', $args, WATCHDOG_NOTICE);
             return $old_sid;
         }
     }
     // Invoke a callback indicating a transition is about to occur.
     // Modules may veto the transition by returning FALSE.
     $result = module_invoke_all('workflow', 'transition pre', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name);
     // Stop if a module says so.
     if (in_array(FALSE, $result)) {
         watchdog('workflow', 'Transition vetoed by module.');
         return $old_sid;
     }
     // Log the new state in {workflow_node_history}.
     // This is only valid for Node API.
     if (!$field_name) {
         // If the node does not have an existing 'workflow' property, save the $old_sid there, so it can be logged.
         if (!isset($entity->workflow)) {
             $entity->workflow = $old_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;
     }
     // Log the transition in {workflow_node_history}.
     $this->is_executed = TRUE;
     $this->save();
     // Register state change with watchdog.
     if ($state = WorkflowState::load($new_sid)) {
         $workflow = $state->getWorkflow();
         if (!empty($workflow->options['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' => $state->label());
             $uri = entity_uri($entity_type, $entity);
             watchdog('workflow', $message, $args, WATCHDOG_NOTICE, l('view', $uri['path']));
         }
     }
     // Notify modules that transition has occurred.
     // Action triggers should take place in response to this callback, not the previous one.
     module_invoke_all('workflow', 'transition post', $old_sid, $new_sid, $entity, $force, $entity_type, $field_name);
     // Clear any references in the scheduled listing.
     foreach (WorkflowScheduledTransition::load($entity_type, $entity_id, $field_name) as $scheduled_transition) {
         $scheduled_transition->delete();
     }
     return $new_sid;
 }