コード例 #1
0
 /**
  * Execute a transition (change state of a node).
  *
  * @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,
  *
  * deprecated workflow_execute_transition() --> WorkflowTransition::execute().
  */
 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);
     }
     // 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'.
     $entity->workflow_transitions[$field_name] = $this;
     // 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.
     }
     // 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.
         /*
              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' => check_plain(t($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;
 }
コード例 #2
0
 /**
  * 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;
 }