/** * 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; }