コード例 #1
0
 /**
  * Save a scheduled transition. If the transition is executed, save as logged transition.
  */
 public function save()
 {
     // If executed, save as logged transition.
     if ($this->is_executed) {
         return parent::save();
     }
     // Avoid duplicate entries.
     $this->delete();
     // Save (insert or update) a record to the database based upon the schema.
     drupal_write_record('workflow_scheduled_transition', $this);
     // Get name of state.
     if ($state = WorkflowState::load($this->new_sid)) {
         $message = '@entity_title scheduled for state change to %state_name on %scheduled_date';
         $args = array('@entity_type' => $this->entity_type, '@entity_title' => $this->entity->title, '%state_name' => $state->label(), '%scheduled_date' => format_date($this->scheduled));
         $uri = entity_uri($this->entity_type, $this->entity);
         watchdog('workflow', $message, $args, WATCHDOG_NOTICE, l('view', $uri['path'] . '/workflow'));
         drupal_set_message(t($message, $args));
     }
 }
コード例 #2
0
 /**
  * Implements hook_field_widget_form --> WidgetInterface::formElement().
  *
  * {@inheritdoc}
  *
  * Be careful: this widget may be shown in very different places. Test carefully!!
  *  - On a entity add/edit page
  *  - On a entity preview page
  *  - On a entity view page
  *  - On a entity 'workflow history' tab
  *  - On a comment display, in the comment history
  *  - On a comment form, below the comment history
  * @todo D8: change "array $items" to "FieldInterface $items"
  */
 public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state)
 {
     $field_name = $this->field['field_name'];
     $field = $this->instance;
     $instance = $this->instance;
     $entity = $this->entity;
     $entity_type = $this->entity_type;
     $entity_id = entity_id($entity_type, $entity);
     if (!$entity) {
         // If no entity given, do not show a form. E.g., on the field settings page.
         return $element;
     }
     // Capture settings to format the form/widget.
     $settings_title_as_name = !empty($this->field['settings']['widget']['name_as_title']);
     // The schedule cannot be shown on a Content add page.
     $settings_schedule = !empty($this->field['settings']['widget']['schedule']) && $entity_id;
     $settings_schedule_timezone = !empty($this->field['settings']['widget']['schedule_timezone']);
     // Show comment, when both Field and Instance allow this.
     $settings_comment = $this->field['settings']['widget']['comment'] ? 'textarea' : 'hidden';
     $workflow = Workflow::load($this->field['settings']['wid']);
     $current_sid = workflow_node_current_state($entity, $entity_type, $field_name);
     $current_state = WorkflowState::load($current_sid);
     $options = array();
     $options = $current_state->getOptions($entity_type, $entity);
     // Determine the default value. If we are in CreationState, use a fast alternative for $workflow->getFirstSid().
     $default_value = $current_state->isCreationState() ? key($options) : $current_sid;
     // Get the scheduling info. This may change the $current_sid on the Form.
     $scheduled = '0';
     $timestamp = REQUEST_TIME;
     $comment = NULL;
     if ($settings_schedule) {
         // Read scheduled information.
         // Technically you could have more than one scheduled, but this will only add the soonest one.
         foreach (WorkflowScheduledTransition::load($entity_type, $entity_id, $field_name) as $scheduled_transition) {
             $scheduled = '1';
             $current_sid = $scheduled_transition->sid;
             $timestamp = $scheduled_transition->scheduled;
             $comment = $scheduled_transition->comment;
             break;
         }
     }
     // Fetch the form ID. This is unique for each entity, to allow multiple form per page (Views, etc.).
     $form_id = $form_state['build_info']['form_id'];
     $element_scheduled_name = 'workflow_scheduled_' . $form_id;
     $element_options_name = 'workflow_options_' . $form_id;
     $element_scheduled_name = 'workflow_scheduled';
     $element_options_name = 'workflow_options';
     $elt_state_name = 'workflow_scheduled_' . $form_id;
     $label = $workflow->label();
     // Prepare a wrapper. This might be a fieldset.
     $element['workflow']['#type'] = 'container';
     $element['workflow']['#attributes'] = array('class' => array('workflow-form-container'));
     // Save the current value of the node in the form, for later Workflow-module specific references.
     // We add prefix, since #tree == FALSE.
     $element['workflow']['workflow_entity'] = array('#type' => 'value', '#value' => $this->entity);
     $element['workflow']['workflow_entity_type'] = array('#type' => 'value', '#value' => $this->entity_type);
     $element['workflow']['workflow_field'] = array('#type' => 'value', '#value' => $this->field);
     $element['workflow']['workflow_instance'] = array('#type' => 'value', '#value' => $this->instance);
     // Save the form_id, so the form values can be retrieved in submit function.
     $element['workflow']['form_id'] = array('#type' => 'value', '#value' => $form_id);
     // First of all, we add the default value in the place were normal fields
     // have it. This is to cater for 'preview' of the entity.
     $element['#default_value'] = $default_value;
     // Decide if we show a widget or a formatter.
     // There is no need to a widget when the only choice is the current sid.
     if (!$current_state->showWidget($options)) {
         $element['workflow'][$element_options_name] = workflow_state_formatter($entity_type, $entity, $field, $instance);
         return $element;
     } else {
         $element['workflow'][$element_options_name] = array('#type' => $this->field['settings']['widget']['options'], '#title' => $settings_title_as_name ? t('Change !name state', array('!name' => $label)) : '', '#options' => $options, '#default_value' => $default_value);
     }
     // Display scheduling form, but only if entity is being edited and user has
     // permission. State change cannot be scheduled at entity creation because
     // that leaves the entity in the (creation) state.
     if ($settings_schedule == TRUE && user_access('schedule workflow transitions')) {
         global $user;
         if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
             $timezone = $user->timezone;
         } else {
             $timezone = variable_get('date_default_timezone', 0);
         }
         $timezones = drupal_map_assoc(timezone_identifiers_list());
         $hours = format_date($timestamp, 'custom', 'H:i', $timezone);
         //      $element['workflow']['workflow_scheduled'] = array(
         $element['workflow'][$element_scheduled_name] = array('#type' => 'radios', '#title' => t('Schedule'), '#options' => array('0' => t('Immediately'), '1' => t('Schedule for state change')), '#default_value' => $scheduled, '#attributes' => array('id' => 'scheduled_' . $form_id));
         $element['workflow']['workflow_scheduled_date_time'] = array('#type' => 'fieldset', '#title' => t('At'), '#attributes' => array('class' => array('container-inline')), '#prefix' => '<div style="margin-left: 1em;">', '#suffix' => '</div>', '#states' => array('visible' => array(':input[id="' . 'scheduled_' . $form_id . '"]' => array('value' => '1'))));
         $element['workflow']['workflow_scheduled_date_time']['workflow_scheduled_date'] = array('#type' => 'date', '#default_value' => array('day' => date('j', $timestamp), 'month' => date('n', $timestamp), 'year' => date('Y', $timestamp)));
         $element['workflow']['workflow_scheduled_date_time']['workflow_scheduled_hour'] = array('#type' => 'textfield', '#title' => t('Time'), '#maxlength' => 5, '#size' => 6, '#default_value' => $scheduled ? $hours : '00:00');
         $element['workflow']['workflow_scheduled_date_time']['workflow_scheduled_timezone'] = array('#type' => $settings_schedule_timezone ? 'select' : 'hidden', '#title' => t('Time zone'), '#options' => $timezones, '#default_value' => array($timezone => $timezone));
         $element['workflow']['workflow_scheduled_date_time']['workflow_scheduled_help'] = array('#type' => 'item', '#prefix' => '<br />', '#description' => t('Please enter a time in 24 hour (eg. HH:MM) format.
       If no time is included, the default will be midnight on the specified date.
       The current time is: @time.', array('@time' => format_date(REQUEST_TIME, 'custom', 'H:i', $timezone))));
     }
     $element['workflow']['workflow_comment'] = array('#type' => $settings_comment, '#title' => t('Workflow comment'), '#description' => t('A comment to put in the workflow log.'), '#default_value' => $comment, '#rows' => 2);
     // The 'add submit' can explicitely set by workflowfield_field_formatter_view(),
     // to add the submit button on the Content view page and the Workflow history tab.
     if (!empty($this->instance['widget']['settings']['submit_function'])) {
         // Add a submit button, but only on Entity View and History page.
         $element['workflow']['submit'] = array('#type' => 'submit', '#value' => t('Update workflow'), '#executes_submit_callback' => TRUE, '#submit' => array($this->instance['widget']['settings']['submit_function']));
     }
     return $element;
 }
コード例 #3
0
 /**
  * Implements hook_field_update() -> FieldItemInterface::update().
  *
  * @todo: in course of time, this is not used anymore... 
  * It is called also from hook_field_insert(), since we need $nid to store {workflow_node_history}.
  * We cannot use hook_field_presave(), since $nid is not yet known at that moment.
  *
  * "Contrary to the old D7 hooks, the methods do not receive the parent entity
  * "or the langcode of the field values as parameters. If needed, those can be accessed
  * "by the getEntity() and getLangcode() methods on the Field and FieldItem classes.
  */
 public function update(&$items)
 {
     // ($entity_type, $entity, $field, $instance, $langcode, &$items) {
     // @todo: apparentlly, in course of time, this is not used anymore. Restore or remove.
     $field_name = $this->field['field_name'];
     $wid = $this->field['settings']['wid'];
     $new_state = WorkflowState::load($sid = _workflow_get_sid_by_items($items), $wid);
     // @todo D8: remove below lines.
     $entity = $this->entity;
     $entity_type = $this->entity_type;
     $entity_id = entity_id($entity_type, $entity);
     if (!$entity) {
         // No entity available, we are on the field Settings page - 'default value' field.
         // This is hidden from the admin, because the default value can be different for every user.
     } elseif (!$entity_id && $entity_type == 'comment') {
         // Not possible: a comment on a non-existent node.
     } elseif ($entity_id && $this->entity_type == 'comment') {
         // This happens when we are on an entity's comment.
         $referenced_entity_type = 'node';
         // Comments only exist on nodes.
         $referenced_entity = entity_load_single($referenced_entity_type, $entity_id);
         // Comments only exist on nodes.
         // Submit the data. $items is reset by reference to normal value, and is magically saved by the field itself.
         $form = array();
         $form_state = array();
         $widget = new WorkflowDefaultWidget($this->field, $this->instance, $referenced_entity_type, $referenced_entity);
         $widget->submit($form, $form_state, $items);
         // $items is a proprietary D7 parameter.
         // Remember: we are on a comment form, so the comment is saved automatically, but the referenced entity is not.
         // @todo: probably we'd like to do this form within the Widget, but that does not know
         //        wether we are on a comment or a node form.
         //
         // Widget::submit() returns the new value in a 'sane' state.
         // Save the referenced entity, but only is transition succeeded, and is not scheduled.
         $old_sid = _workflow_get_sid_by_items($referenced_entity->{$field_name}['und']);
         $new_sid = _workflow_get_sid_by_items($items);
         if ($old_sid != $new_sid) {
             $referenced_entity->{$field_name}['und'] = $items;
             entity_save($referenced_entity_type, $referenced_entity);
         }
     } elseif ($this->entity_type != 'comment') {
         if (isset($items[0]['value'])) {
             // A 'normal' options.module-widget is used, and $items[0]['value'] is already properly set.
         } elseif (isset($items[0]['workflow'])) {
             // The WorkflowDefaultWidget is used.
             // Submit the data. $items is reset by reference to normal value, and is magically saved by the field itself.
             $form = array();
             $form_state = array();
             $widget = new WorkflowDefaultWidget($this->field, $this->instance, $entity_type, $entity);
             $widget->submit($form, $form_state, $items);
             // $items is a proprietary D7 parameter.
         } else {
             drupal_set_message('error in WorkfowItem->update()', 'error');
         }
     }
     // A 'normal' node add page.
     // We should not be here, since we only do inserts after $entity_id is known.
     // $current_sid = Workflow::load($wid)->getCreationSid();
 }
コード例 #4
0
 /**
  * Save (update/insert) a Workflow State into table workflow_states.
  *
  * @deprecated: workflow_update_workflow_states() --> WorkflowState->save()
  */
 public function save()
 {
     $sid = $this->sid;
     // Convert all properties to an array, the previous ones, too.
     $data['sid'] = $this->sid;
     $data['wid'] = $this->wid;
     $data['weight'] = $this->weight;
     $data['sysid'] = $this->sysid;
     $data['state'] = $this->state;
     $data['status'] = $this->status;
     if (!empty($this->sid) && count(WorkflowState::load($sid)) > 0) {
         drupal_write_record('workflow_states', $data, 'sid');
     } else {
         drupal_write_record('workflow_states', $data);
     }
     // Update the page cache.
     self::$states[$sid] = $this;
 }
コード例 #5
0
 /**
  * Gets a state for a given workflow.
  *
  * @param $sid
  *   A state ID.
  *
  * @return
  *   A WorkflowState object.
  */
 public function getState($sid)
 {
     return WorkflowState::load($sid, $this->wid);
 }
コード例 #6
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;
 }