/**
  * @return WorkflowTransitionInterface
  */
 protected function getTransitionForExecution(EntityInterface $entity)
 {
     $user = workflow_current_user();
     if (!$entity) {
         \Drupal::logger('workflow_action')->notice('Unable to get current entity - entity is not defined.', []);
         return NULL;
     }
     // Get the entity type and numeric ID.
     $entity_id = $entity->id();
     if (!$entity_id) {
         \Drupal::logger('workflow_action')->notice('Unable to get current entity ID - entity is not yet saved.', []);
         return NULL;
     }
     // In 'after saving new content', the node is already saved. Avoid second insert.
     // Todo: clone?
     $entity->enforceIsNew(FALSE);
     $config = $this->configuration;
     $field_name = workflow_get_field_name($entity, $config['field_name']);
     $current_sid = workflow_node_current_state($entity, $field_name);
     if (!$current_sid) {
         \Drupal::logger('workflow_action')->notice('Unable to get current workflow state of entity %id.', array('%id' => $entity_id));
         return NULL;
     }
     $to_sid = isset($config['to_sid']) ? $config['to_sid'] : '';
     // Get the Comment. Parse the $comment variables.
     $comment_string = $this->configuration['comment'];
     $comment = t($comment_string, array('%title' => $entity->label(), '%state' => workflow_get_sid_name($to_sid), '%user' => $user->getUsername()));
     $force = $this->configuration['force'];
     $transition = WorkflowTransition::create([$current_sid, 'field_name' => $field_name]);
     $transition->setTargetEntity($entity);
     $transition->setValues($to_sid, $user->id(), REQUEST_TIME, $comment);
     $transition->force($force);
     return $transition;
 }
 /**
  * {@inheritdoc}
  */
 public function access(EntityInterface $entity, $operation, AccountInterface $account = NULL, $return_as_object = FALSE)
 {
     $result = AccessResult::neutral();
     $account = $user = workflow_current_user($account);
     // This is only for Edit/Delete transition. For Add/create, use createAccess.
     switch ($entity->getEntityTypeId()) {
         case 'workflow_transition':
         case 'workflow_scheduled_transition':
             /* @var $transition WorkflowTransitionInterface */
             $transition = $entity;
             switch ($operation) {
                 case 'revert':
                     $is_owner = WorkflowManager::isOwner($user, $transition);
                     $type_id = $transition->getWorkflowId();
                     if ($transition->getFromSid() == $transition->getToSid()) {
                         // No access for same state transitions.
                         $result = AccessResult::forbidden();
                     } elseif ($user->hasPermission("revert any {$type_id} workflow_transition")) {
                         // OK, add operation.
                         $result = AccessResult::allowed();
                     } elseif ($is_owner && $user->hasPermission("revert own {$type_id} workflow_transition")) {
                         // OK, add operation.
                         $result = AccessResult::allowed();
                     } else {
                         // No access.
                         $result = AccessResult::forbidden();
                     }
                     break;
                 default:
                     $result = parent::access($entity, $operation, $account, $return_as_object)->cachePerPermissions();
                     break;
             }
             // End of switch ($operation).
             break;
             // case
         // case
         default:
             // $entity_type
             $result = AccessResult::forbidden();
     }
     // End of  switch($entity->getEntityTypeId()).
     return $return_as_object ? $result : $result->isAllowed();
 }
Exemplo n.º 3
0
 /**
  * {@inheritdoc}
  */
 public function setValues($to_sid, $uid = NULL, $timestamp = REQUEST_TIME, $comment = '', $force_create = FALSE)
 {
     // Normally, the values are passed in an array, and set in parent::__construct, but we do it ourselves.
     $uid = $uid === NULL ? workflow_current_user()->id() : $uid;
     $from_sid = $this->getFromSid();
     $this->set('to_sid', $to_sid);
     $this->setOwnerId($uid);
     $this->setTimestamp($timestamp);
     $this->setComment($comment);
     // If constructor is called with new() and arguments.
     if (!$from_sid && !$to_sid && !$this->getTargetEntity()) {
         // If constructor is called without arguments, e.g., loading from db.
     } elseif ($from_sid && $this->getTargetEntity()) {
         // Caveat: upon entity_delete, $to_sid is '0'.
         // If constructor is called with new() and arguments.
     } elseif (!$from_sid) {
         // Not all parameters are passed programmatically.
         if (!$force_create) {
             drupal_set_message(t('Wrong call to constructor Workflow*Transition(%from_sid to %to_sid)', array('%from_sid' => $from_sid, '%to_sid' => $to_sid)), 'error');
         }
     }
     return $this;
 }
Exemplo n.º 4
0
 /**
  * Returns the allowed transitions for the current state.
  *
  * @param \Drupal\Core\Entity\EntityInterface|NULL $entity
  *   The entity at hand. May be NULL (E.g., on a Field settings page).
  * @param string $field_name
  * @param \Drupal\Core\Session\AccountInterface|NULL $account
  * @param bool|FALSE $force
  *
  * @return \Drupal\workflow\Entity\WorkflowConfigTransition[]
  *   An array of id=>transition pairs with allowed transitions for State.
  */
 public function getTransitions(EntityInterface $entity = NULL, $field_name = '', AccountInterface $account = NULL, $force = FALSE)
 {
     $transitions = array();
     if (!($workflow = $this->getWorkflow())) {
         // No workflow, no options ;-)
         return $transitions;
     }
     // @todo: Keep below code aligned between WorkflowState, ~Transition, ~TransitionListController
     /**
      * Get permissions of user, adding a Role to user, depending on situation.
      */
     // Load a User object, since we cannot add Roles to AccountInterface.
     /* @var $user \Drupal\user\UserInterface */
     $user = workflow_current_user($account);
     // Determine if user is owner of the entity.
     $is_owner = WorkflowManager::isOwner($user, $entity);
     // Check allow-ability of state change if user is not superuser (might be cron)
     $type_id = $this->getWorkflowId();
     if ($user->hasPermission("bypass {$type_id} workflow_transition access")) {
         // Superuser is special. And $force allows Rules to cause transition.
         $force = TRUE;
     } elseif ($is_owner) {
         $user->addRole(WORKFLOW_ROLE_AUTHOR_RID);
     }
     /**
      * Get the object and its permissions.
      */
     /* @var $transitions WorkflowConfigTransition[] */
     $transitions = $workflow->getTransitionsByStateId($this->id(), '');
     /**
      * Determine if user has Access.
      */
     // Use default module permissions.
     foreach ($transitions as $key => $transition) {
         if (!$transition->isAllowed($user, $force)) {
             unset($transitions[$key]);
         }
     }
     // Let custom code add/remove/alter the available transitions,
     // using the new drupal_alter.
     // Modules may veto a choice by removing a transition from the list.
     // Lots of data can be fetched via the $transition object.
     $context = array('user' => $user, 'workflow' => $workflow, 'state' => $this, 'force' => $force);
     \Drupal::moduleHandler()->alter('workflow_permitted_state_transitions', $transitions, $context);
     /**
      * Determine if user has Access.
      */
     // As of 8.x-1.x, below hook() is removed, in favour of above alter().
     // Let custom code change the options, using old_style hook.
     // Above drupal_alter() calls hook_workflow_permitted_state_transitions_alter() only once.
     //    foreach ($transitions as $transition) {
     //      $to_sid = $transition->to_sid;
     //      $permitted = array();
     //
     //      // We now have a list of config_transitions. Check each against the Entity.
     //      // Invoke a callback indicating that we are collecting state choices.
     //      // Modules may veto a choice by returning FALSE.
     //      // In this case, the choice is never presented to the user.
     //      if (!$force) {
     //        // TODO: D8-port: simplify interface for workflow_hook. Remove redundant context.
     //        $permitted = \Drupal::moduleHandler()->invokeAll('workflow', ['transition permitted', $transition, $user]);
     //      }
     //
     //      // If vetoed by a module, remove from list.
     //      if (in_array(FALSE, $permitted, TRUE)) {
     //        unset($transitions[$transition->id()]);
     //      }
     //    }
     return $transitions;
 }
 /**
  * Implements ContentEntityForm::copyFormValuesToEntity(), and is called from:
  * - WorkflowTransitionForm::buildEntity()
  * - WorkflowDefaultWidget
  *
  * N.B. in contrary to ContentEntityForm::copyFormValuesToEntity(),
  * - parameter 1 is returned as result, to be able to create a new Transition object.
  * - parameter 3 is not $form_state (from Form), but an $item array (from Widget).
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  * @param array $form
  * @param array $item
  *
  * @return \Drupal\workflow\Entity\WorkflowTransitionInterface
  */
 public static function copyFormItemValuesToEntity(EntityInterface $entity, array $form, array $item)
 {
     /**
      * Input
      */
     $user = workflow_current_user();
     // @todo #2287057: verify if submit() really is only used for UI. If not, $user must be passed.
     /* @var $transition WorkflowTransitionInterface */
     $transition = $entity;
     /**
      * Derived input
      */
     // Make sure we have subset ['workflow_scheduled_date_time']
     if (isset($item['to_sid'])) {
         // In WorkflowTransitionForm, we receive the complete $form_state.
         // Remember, the workflow_scheduled element is not set on 'add' page.
         $scheduled = !empty($item['workflow_scheduling']['scheduled']);
         $schedule_values = $scheduled ? $item['workflow_scheduling']['date_time'] : [];
     } else {
         $entity_id = $transition->getTargetEntityId();
         drupal_set_message(t('Error: content !id has no workflow attached. The data is not saved.', array('!id' => $entity_id)), 'error');
         // The new state is still the previous state.
         return $transition;
     }
     // Get user input from element.
     $to_sid = $item['to_sid'];
     $comment = $item['comment'];
     $force = FALSE;
     // @todo D8: add the VBO use case.
     //    // Determine if the transition is forced.
     //    // This can be set by a 'workflow_vbo action' in an additional form element.
     //     $force = isset($form_state['input']['workflow_force']) ? $form_state['input']['workflow_force'] : FALSE;
     //    if (!$entity) {
     //      // E.g., on VBO form.
     //    }
     // @todo D8-port: add below exception.
     /*
         // Extract the data from $items, depending on the type of widget.
         // @todo D8: use MassageFormValues($item, $form, $form_state).
         $old_sid = workflow_node_previous_state($entity, $entity_type, $field_name);
         if (!$old_sid) {
           // At this moment, $old_sid should have a value. If the content does not
           // have a state yet, old_sid contains '(creation)' state. But if the
           // content is not associated to a workflow, old_sid is now 0. This may
           // happen in workflow_vbo, if you assign a state to non-relevant nodes.
           $entity_id = entity_id($entity_type, $entity);
           drupal_set_message(t('Error: content !id has no workflow attached. The data is not saved.', array('!id' => $entity_id)), 'error');
           // The new state is still the previous state.
           $new_sid = $old_sid;
           return $new_sid;
         }
     */
     $timestamp = REQUEST_TIME;
     if ($scheduled) {
         // Fetch the (scheduled) timestamp to change the state.
         // Override $timestamp.
         $scheduled_date_time = implode(' ', array($schedule_values['workflow_scheduled_date'], $schedule_values['workflow_scheduled_hour']));
         $timezone = $schedule_values['workflow_scheduled_timezone'];
         $old_timezone = date_default_timezone_get();
         date_default_timezone_set($timezone);
         $timestamp = strtotime($scheduled_date_time);
         date_default_timezone_set($old_timezone);
         if (!$timestamp) {
             // Time should have been validated in form/widget.
             $timestamp = REQUEST_TIME;
         }
     }
     /**
      * Process
      */
     /*
      * Create a new ScheduledTransition.
      */
     if ($scheduled) {
         $transition_entity = $transition->getTargetEntity();
         $field_name = $transition->getFieldName();
         $from_sid = $transition->getFromSid();
         /* @var $transition WorkflowTransitionInterface */
         $transition = WorkflowScheduledTransition::create([$from_sid, 'field_name' => $field_name]);
         $transition->setTargetEntity($transition_entity);
         $transition->setValues($to_sid, $user->id(), $timestamp, $comment);
     }
     if (!$transition->isExecuted()) {
         // Set new values.
         // When editing an existing Transition, only comments may change.
         $transition->set('to_sid', $to_sid);
         $transition->setOwner($user);
         $transition->setTimestamp($timestamp);
         $transition->schedule($scheduled);
         $transition->force($force);
     }
     $transition->setComment($comment);
     // Explicitely set $entity in case of ScheduleTransition. It is now returned as parameter, not result.
     $entity = $transition;
     return $transition;
 }
Exemplo n.º 6
0
 /**
  * {@inheritdoc}
  *
  * Implements workflow_transition() -> WorkflowDefaultWidget::submit().
  *
  * Overrides submit(array $form, array &$form_state).
  * Contains 2 extra parameters for D7
  *
  * @param array $form
  * @param array $form_state
  * @param array $items
  *   The value of the field.
  * @param bool $force
  *   TRUE if all access must be overridden, e.g., for Rules.
  *
  * @return int
  *   If update succeeded, the new State Id. Else, the old Id is returned.
  *
  * This is called from function _workflowfield_form_submit($form, &$form_state)
  * It is a replacement of function workflow_transition($entity, $to_sid, $force, $field)
  * It performs the following actions;
  * - save a scheduled action
  * - update history
  * - restore the normal $items for the field.
  * @todo: remove update of {node_form} table. (separate task, because it has features, too)
  */
 public function massageFormValues(array $values, array $form, FormStateInterface $form_state)
 {
     $user = workflow_current_user();
     // @todo #2287057: verify if submit() really is only used for UI. If not, $user must be passed.
     // Set the new value.
     // Beware: We presume cardinality = 1 !!
     // The widget form element type has transformed the value to a
     // WorkflowTransition object at this point. We need to convert it
     // back to the regular 'value' string format.
     foreach ($values as &$item) {
         if (!empty($item)) {
             // } && $item['value'] instanceof DrupalDateTime) {
             // The following can NOT be retrieved from the WorkflowTransition.
             /* @var $entity EntityInterface */
             $entity = $form_state->getFormObject()->getEntity();
             /* @var $transition \Drupal\workflow\Entity\WorkflowTransitionInterface */
             $transition = $item['workflow_transition'];
             $field_name = $transition->getFieldName();
             // N.B. Use a proprietary version of copyFormValuesToEntity,
             // where $entity/$transition is passed by reference.
             // $this->copyFormValuesToEntity($entity, $form, $form_state);
             /* @var $transition \Drupal\workflow\Entity\WorkflowTransitionInterface */
             $transition = WorkflowTransitionElement::copyFormItemValuesToEntity($transition, $form, $item);
             // Try to execute the transition. Return $from_sid when error.
             if (!$transition) {
                 // This should not be possible (perhaps when testing/developing).
                 drupal_set_message(t('Error: the transition from %from_sid to %to_sid could not be generated.'), 'error');
                 // The current value is still the previous state.
                 $to_sid = $from_sid;
             } else {
                 // The transition may be scheduled or not. Save the result, and
                 // rely upon hook workflow_entity_insert/update($entity) in
                 // file workflow.module to save/execute the transition.
                 // - validate option; add hook to let other modules change comment.
                 // - add to history; add to watchdog
                 // Return the new State ID. (Execution may fail and return the old Sid.)
                 // Get the new value from an action button if set in the workflow settings.
                 $action_info = _workflow_transition_form_get_triggering_button($form_state);
                 if ($field_name == $action_info['field_name']) {
                     $transition->to_sid->value = $action_info['to_sid'];
                 }
                 $force = FALSE;
                 // @TODO D8-port: add to form for usage in VBO.
                 // Now, save/execute the transition.
                 $from_sid = $transition->getFromSid();
                 $force = $force || $transition->isForced();
                 if (!$transition->isAllowed($user, $force)) {
                     // Transition is not allowed.
                     $to_sid = $from_sid;
                 } elseif (!$entity || !$entity->id()) {
                     // Entity is inserted. The Id is not yet known.
                     // So we can't yet save the transition right now, but must rely on
                     // function/hook workflow_entity_insert($entity) in file workflow.module.
                     // $to_sid = $transition->execute($force);
                     $to_sid = $transition->getToSid();
                 } else {
                     // Entity is updated. To stay in sync with insert, we rely on
                     // function/hook workflow_entity_update($entity) in file workflow.module.
                     // $to_sid = $transition->execute($force);
                     $to_sid = $transition->getToSid();
                 }
             }
             // Now the data is captured in the Transition, and before calling the
             // Execution, restore the default values for Workflow Field.
             // For instance, workflow_rules evaluates this.
             //
             // Set the transition back, to be used in hook_entity_update().
             $item['workflow_transition'] = $transition;
             //
             // Set the value at the proper location.
             $item['value'] = $to_sid;
         }
     }
     return $values;
 }