WorkflowItem.php in Workflow 7
Same filename and directory in other branches
Contains workflow\includes\Field\WorkflowItem.
See also
https://drupal.org/node/2064123 for 'Field Type Plugin' change record D7->D8.
File
includes/Field/WorkflowItem.phpView source
<?php
/**
* @file
* Contains workflow\includes\Field\WorkflowItem.
* @see https://drupal.org/node/2064123 for 'Field Type Plugin' change record D7->D8.
*/
/**
* Plugin implementation of the 'workflow' field type.
*
* @FieldType(
* id = "workflow",
* label = @Translation("Workflow"),
* description = @Translation("This field stores Workflow values for a certain Workflow type from a list of allowed 'value => label' pairs, i.e. 'Publishing': 1 => unpublished, 2 => draft, 3 => published."),
* default_widget = "options_select",
* default_formatter = "list_formatter",
* property_type' = WORKFLOW_FIELD_PROPERTY_TYPE,
* )
*/
class WorkflowItem extends WorkflowD7Base {
// D8: extends ConfigFieldItemBase implements PrepareCacheInterface {
/*
* Function, that gets replaced by the 'annotations' in D8. (@see comments above this class)
*/
public static function getInfo() {
return array(
'workflow' => array(
'label' => t('Workflow'),
'description' => t("This field stores Workflow values for a certain Workflow type from a list of allowed 'value => label' pairs, i.e. 'Publishing': 1 => unpublished, 2 => draft, 3 => published."),
'settings' => array(
'allowed_values_function' => 'workflowfield_allowed_values',
// For the list.module formatter
// 'allowed_values_function' => 'WorkflowItem::getAllowedValues', // For the list.module formatter
'wid' => '',
// 'history' => 1,
// 'schedule' => 0,
// 'comment' => 0,
'widget' => array(
'options' => 'select',
'name_as_title' => 1,
'schedule' => 1,
'schedule_timezone' => 1,
'comment' => 1,
),
'watchdog_log' => 1,
'history' => array(
'show' => 1,
'roles' => array(),
),
),
'default_widget' => 'options_select',
'default_formatter' => 'list_default',
'property_type' => WORKFLOW_FIELD_PROPERTY_TYPE,
),
);
}
/*
* Implements hook_field_settings_form() -> ConfigFieldItemInterface::settingsForm()
*/
public function settingsForm(array $form, array &$form_state, $has_data) {
$field_info = self::getInfo();
$settings = $this->field['settings'];
$settings += $field_info['workflow']['settings'];
$settings['widget'] += $field_info['workflow']['settings']['widget'];
$wid = $this->field['settings']['wid'];
// Create list of all Workflow types. Include an initial empty value.
// Validate each workflow, and generate a message if not complete.
$workflows = array();
$workflows[''] = t('- Select a value -');
foreach (Workflow::getWorkflows() as $workflow) {
if ($workflow
->validate()) {
$workflows[$workflow->wid] = $workflow->name;
}
}
if (count($workflows) == 1) {
drupal_set_message(t('You must create at least one workflow before content can be assigned to a workflow.'));
}
// The allowed_values_functions is used in the formatter from list.module.
$element['allowed_values_function'] = array(
'#type' => 'value',
'#value' => $settings['allowed_values_function'],
);
// Let the user choose between the available workflow types.
$element['wid'] = array(
'#type' => 'select',
'#title' => t('Workflow type'),
'#options' => $workflows,
'#default_value' => $wid,
'#required' => TRUE,
'#disabled' => $has_data,
'#description' => t('Choose the Workflow type.') . ' ' . t('Maintain workflows ') . l('here', 'admin/config/workflow/workflow') . '.',
);
// Inform the user of possible states.
// If no Workflow type is selected yet, do not show anything.
if ($wid) {
// Get a string representation to show all options.
$allowed_values_string = $this
->_allowed_values_string($wid);
$element['allowed_values_string'] = array(
'#type' => 'textarea',
'#title' => t('Allowed values for the selected Workflow type'),
'#default_value' => $allowed_values_string,
'#rows' => 10,
'#access' => TRUE,
// user can see the data,
'#disabled' => TRUE,
);
}
$element['widget'] = array(
'#type' => 'fieldset',
'#title' => t('Workflow widget'),
'#description' => 'Set some global properties of the widgets for this workflow. Some can be altered per widget instance.',
);
$element['widget']['options'] = array(
'#type' => 'select',
'#title' => t('How to show the available states'),
'#required' => FALSE,
'#default_value' => $settings['widget']['options'],
// '#multiple' => TRUE / FALSE,
'#options' => array(
// These options are taken from options.module
'select' => 'Select list',
'radios' => 'Radio buttons',
),
'#description' => t('The Widget shows all available states. Decide which is the best way to show them.'),
);
$element['widget']['name_as_title'] = array(
'#type' => 'checkbox',
'#attributes' => array(
'class' => array(
'container-inline',
),
),
'#title' => t('Use the workflow name as the title of the workflow form'),
'#default_value' => $settings['widget']['name_as_title'],
'#description' => t('The workflow section of the editing form is in its own fieldset. Checking the box will add the workflow ' . 'name as the title of workflow section of the editing form.'),
);
$element['widget']['schedule'] = array(
'#type' => 'checkbox',
'#title' => t('Allow scheduling of workflow transitions.'),
'#required' => FALSE,
'#default_value' => $settings['widget']['schedule'],
'#description' => t('Workflow transitions may be scheduled to a moment in the future. ' . 'Soon after the desired moment, the transition is executed by Cron. ' . 'This may be hidden by settings in widgets, formatters or permissions.'),
);
$element['widget']['schedule_timezone'] = array(
'#type' => 'checkbox',
'#title' => t('Show a timezone when scheduling a transition.'),
'#required' => FALSE,
'#default_value' => $settings['widget']['schedule_timezone'],
);
$element['widget']['comment'] = array(
'#type' => 'checkbox',
'#title' => t('Allow adding a comment to workflow transitions.'),
'#required' => FALSE,
'#default_value' => $settings['widget']['comment'],
'#description' => t('On the Workflow form, a Comment form can be included so that the person making the state change can record ' . 'reasons for doing so. The comment is then included in the node\'s workflow history. ' . 'This may be hidden by settings in widgets, formatters or permissions.'),
);
$element['watchdog_log'] = array(
'#type' => 'checkbox',
'#attributes' => array(
'class' => array(
'container-inline',
),
),
'#title' => t('Log informational watchdog messages when a transition is executed (a state value is changed)'),
'#default_value' => $settings['watchdog_log'],
'#description' => t('Optionally log transition state changes to watchdog.'),
);
$element['history'] = array(
'#type' => 'fieldset',
'#title' => t('Workflow history'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$element['history']['show'] = array(
'#type' => 'checkbox',
'#title' => t('Use the workflow history, and show it on a separate tab.'),
'#required' => FALSE,
'#default_value' => $settings['history']['show'],
'#description' => t('If checked, the state change is recorded in table {workflow_node_history}, ' . "and a tab 'Workflow' is shown on the node page, which gives access to the History of the workflow."),
);
$element['history']['roles'] = array(
'#type' => 'checkboxes',
'#options' => workflow_admin_ui_get_roles(),
'#title' => t('Workflow history permissions'),
'#default_value' => $settings['history']['roles'],
'#description' => t('Select any roles that should have access to the workflow tab on nodes that have a workflow.'),
);
return $element;
}
/*
* Currently, there are no instance Settings.
* hook_field_instance_settings_form() -> ConfigFieldItemInterface::instanceSettingsForm()
*/
// public function instanceSettingsForm(array $form, array &$form_state, $has_data) {
// }
/**
* Do not implement hook_field_presave(),
* since $nid is needed, but not yet known at this moment.
* hook_field_presave() -> FieldItemInterface::preSave()
*/
//function workflowfield_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
//}
/**
* Implements hook_field_insert() -> FieldItemInterface::insert()
*/
public function insert() {
return $this
->update();
}
/**
* Implements hook_field_update() -> FieldItemInterface::update()
*
* 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) {
$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 = _workflow_get_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.
// todo: for now, if nid is set, then it is a node. What happens with other entities?
$referenced_entity_type = 'node';
// Comments only exist on nodes.
$referenced_entities = entity_load($referenced_entity_type, array(
$nid,
));
$referenced_entity = $referenced_entities[$nid];
// 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;
$this
->entitySave($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();
}
/**
* Implements hook_field_delete() -> FieldItemInterface::delete()
*/
// public function delete() {
// }
public function getCurrentState() {
$field_name = $this->field['field_name'];
$wid = $this->field['settings']['wid'];
$workflow = Workflow::load($wid);
$options = array();
$entity = $this->entity;
$entity_type = $this->entity_type;
$entity_id = _workflow_get_entity_id($entity_type, $entity);
if ($entity_id && $this->entity_type == 'comment') {
// This happens when we are on an entity's comment.
// We need to fetch the field value of the original node, and show it on the comment.
$entity_type = 'node';
// Comments only exist on nodes.
$referenced_entities = entity_load($entity_type, array(
$entity_id,
));
$entity = $referenced_entities[$entity_id];
$items = field_get_items($entity_type, $entity, $field_name, $langcode = NULL);
$state = WorkflowState::load($sid = _workflow_get_sid_by_items($items), $wid);
if (!$state) {
// E.g., the node was created before the field was added: do the same as 'Node Add' page.
$state = $workflow
->getCreationState();
}
}
elseif ($entity_id && $this->entity_type != 'comment') {
// A 'normal' node edit page.
$items = field_get_items($entity_type, $entity, $field_name, $langcode = NULL);
$state = WorkflowState::load($sid = _workflow_get_sid_by_items($items), $wid);
if (!$state) {
// E.g., the node was created before the field was added: do the same as 'Node Add' page.
$state = $workflow
->getCreationState();
}
}
elseif (!$entity_id && $entity_type == 'comment') {
// not possible: a comment on a non-existent node.
$state = NULL;
}
elseif (!$entity_id && $entity_type != 'comment') {
if ($entity) {
// A 'normal' node add page.
$state = $workflow
->getCreationState();
}
else {
// 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.
$state = NULL;
}
}
return $state;
}
/*
* Helper functions for the Field Settings page.
* Generates a string representation of an array of 'allowed values'.
* This is a copy from list.module's list_allowed_values_string().
*
* This string format is suitable for edition in a textarea.
*
* @param $values
* An array of values, where array keys are values and array values are
* labels.
*
* @return
* The string representation of the $values array:
* - Values are separated by a carriage return.
* - Each value is in the format "value|label" or "value".
*/
private function _allowed_values_string($wid = 0) {
$lines = array();
$states = WorkflowState::getStates(0, $wid);
$previous_wid = -1;
foreach ($states as $state) {
// Only show enabled states.
if ($state->status) {
// Show a Workflow name between Workflows, if more then 1 in the list.
if ($wid == 0 && $previous_wid != $state->wid) {
$previous_wid = $state->wid;
$lines[] = $state->name . "'s states: ";
}
$label = t($state
->label());
$states[$state->sid] = check_plain($label);
$lines[] = $state->sid . ' | ' . check_plain($label);
}
}
return implode("\n", $lines);
}
/*
* Helper function for list.module formatter.
*
* Callback function for the list module formatter.
* @see list_allowed_values() :
* "The strings are not safe for output. Keys and values of the array should be
* "sanitized through field_filter_xss() before being displayed.
*
* @return
* The array of allowed values. Keys of the array are the raw stored values
* (number or text), values of the array are the display labels.
* It contains all possible values, beause the result is cached, and used for all nodes on a page.
*
* @todo: this function getAllowedValues() needs to read the correct state. It is incorrect when showing comments on a node page.
*/
public function getAllowedValues() {
$options = array();
// Get all state names, including inactive states.
foreach (Workflow::getWorkflows() as $workflow) {
$options += $workflow
->getOptions($grouped = FALSE);
}
return $options;
}
/**
* Callback function for the default Options widgets.
*/
public function getOptions() {
$state = $this
->getCurrentState();
$options = $state
->getOptions($this->entity_type, $this->entity, $force = FALSE);
return $options;
}
}
Classes
Name | Description |
---|---|
WorkflowItem | Plugin implementation of the 'workflow' field type. |