workflow.tokens.inc in Workflow 7.2
Same filename and directory in other branches
Tokens hooks for Workflow module.
To every entity type, a default Workflow token tree is added. To support multiple tokens per entity bundle, an extra token tree 'Workflows' is created.
How to test?
- Enable module 'Token'; use page admin/help/token;
- Enable module 'Token example'; use page examples/token;
- Enable module Automatic Entity Label, set a label, and save entity.
File
workflow.tokens.incView source
<?php
/**
* @file
* Tokens hooks for Workflow module.
*
* To every entity type, a default Workflow token tree is added. To support
* multiple tokens per entity bundle, an extra token tree 'Workflows' is
* created.
*
* How to test?
* - Enable module 'Token'; use page admin/help/token;
* - Enable module 'Token example'; use page examples/token;
* - Enable module Automatic Entity Label, set a label, and save entity.
*/
/**
* Implements drupal_alter('token_field_info', $info) from token.tokens.inc.
*
* It would be nice if this would work! But it doesn't...
*/
/*
// function workflow_token_field_info_alter(&$info) {
// $workflow_field_info = _workflow_info_fields();
// foreach($workflow_field_info as $field_name => $field_info) {
// if (array_key_exists($field_name, $info)) {
// $info[$field_name]['type'] = 'WorkflowLastTransition';
// $info[$field_name]['module'] = 'workflow';
// }
// }
// }
*/
/**
* Adds a subtree to each WorkflowField.
*
* ATM we only generate tokens for the last transition of a field.
*/
function workflow_token_info_alter(&$data) {
foreach ($data['tokens'] as $object => &$tokens) {
// Add a token for scheduling, in 'seconds ago' format.
if ($object == 'date' && !isset($tokens['seconds'])) {
$tokens['seconds'] = array(
'name' => 'Seconds-since',
'description' => "A date in 'seconds ago' format (<i>604800</i>). Use it for easy scheduling workflow transitions.",
'module' => 'workflow',
);
}
// High-jack the fields (they do not have sub-tokens, yet).
foreach ($tokens as &$token) {
// Caveat: the following algorithm is just a guess.
if (isset($token['module']) && $token['module'] == 'token') {
if (isset($token['description']) && 0 == substr_compare($token['description'], 'Workflow', 0, 8)) {
$token['type'] = 'WorkflowTransition';
$token['module'] = 'workflow';
}
}
}
}
}
/**
* Implements hook_token_info().
*
* Adds tokens and token types, for Field, Workflow, State and Transition,
* using the names of the entities from Workflow module.
* Lots of tokens are already defined via entity_properties.
* D7: a dependency on entity_token exists.
*
* @see workflow_entity_property_info_alter()
*/
function workflow_token_info() {
if (!module_exists('entity_token')) {
return array();
}
/*
* Token types.
*/
$types['WorkflowField'] = array(
'name' => t('Workflows'),
'description' => t('Tokens related to workflows.'),
'needs-data' => 'entity',
);
$types['WorkflowTransition'] = array(
'name' => t('Workflow Transition'),
'description' => t('Tokens related to workflow transitions.'),
// 'needs-data' => 'entity',
'needs-data' => 'WorkflowField',
);
$types['WorkflowState'] = array(
'name' => t('Workflow State'),
'description' => t('Tokens related to workflow state.'),
'needs-data' => 'WorkflowTransition',
);
$types['Workflow'] = array(
'name' => t('Workflow'),
'description' => t('Tokens related to workflows.'),
'needs-data' => 'WorkflowTransition',
);
/*
* Chained tokens for nodes.
*/
$last_transition = array(
'name' => t('Workflow last transition'),
'description' => t('Last workflow state transition of content.'),
'type' => 'WorkflowTransition',
'module' => 'workflow',
);
// Add a token tree to each core entity type. This allows easy reference
// in the majority of cases.
$workflow_field['last-transition'] = $last_transition;
$entity['last-transition'] = $last_transition;
$user['last-transition'] = $last_transition;
$node['last-transition'] = $last_transition;
$term['last-transition'] = $last_transition;
$return = array(
'types' => $types,
'tokens' => array(
// 'entity' => $entity, // #2272121
'user' => $user,
'node' => $node,
'term' => $term,
'WorkflowField' => $workflow_field,
),
);
return $return;
}
/**
* Implements hook_tokens().
*
* N.B. Keep the following functions aligned when changing properties:
* - workflow_tokens()
* - workflow_entity_property_info_alter()
* - workflow_views_views_data_alter()
*/
function workflow_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
$sanitize = !empty($options['sanitize']);
$langcode = isset($options['language']) ? $options['language']->language : NULL;
// The 'node' tokens have already been replaced with 'entity'.
// Skip for easier debugging.
// @todo: is this always the case, or only if Entity Tokens is enabled?
if ($type == 'node' || $type == 'user' || $type == 'term') {
return $replacements;
}
if ($type == 'date' && !empty($data['date'])) {
foreach ($tokens as $name => $original) {
switch ($name) {
case 'seconds':
// This is our custom date token in 'seconds ago' format.
$seconds = REQUEST_TIME - $data['date'];
$replacements[$original] = $seconds;
// Avoid reporcessing in the remainder of this function.
break;
}
}
return $replacements;
}
elseif ($type == 'entity' && !empty($data['entity'])) {
// new, chained tokens, as of version 7.x-2.3.
$entity = $data['entity'];
$entity_type = $data['entity_type'];
// $token_type = $data['token_type'];
foreach ($tokens as $name => $original) {
if (FALSE !== strpos($name, ':')) {
// This is a chained property (contains ':').
$name_parts = explode(':', $name);
switch (end($name_parts)) {
case 'comment':
if (isset($entity->workflow_transitions) && isset($entity->workflow_transitions[$name_parts[0]])) {
$replacements[$original] = $entity->workflow_transitions[$name_parts[0]]->{$name_parts[1]};
}
break;
}
}
elseif (isset($data['workflow_token_type'])) {
// This part taken from entity_token_tokens().
$wrapper = entity_metadata_wrapper($data['workflow_token_type'], $data[$data['workflow_token_type']]);
$property_name = str_replace('-', '_', $name);
try {
if ($name == 'workflow' || $name == 'states' || $name == 'transitions') {
$replacement = _workflow_token_get_token($wrapper->{$property_name}, $options);
}
else {
$replacement = _entity_token_get_token($wrapper->{$property_name}, $options);
}
if (isset($replacement)) {
$replacements[$original] = $replacement;
}
} catch (EntityMetadataWrapperException $e) {
// dpm('token not found: ' . $name);
// If tokens for not existing values are requested, just do nothing.
}
}
}
// If this is a Last Transition, get subtokens for it.
if ($sub_tokens = token_find_with_prefix($tokens, 'last-transition')) {
// Get the workflow tokens from the transition of this entity.
$transition = _workflow_tokens_get_transition($entity_type, $entity, NULL);
$sub_data = array(
'WorkflowTransition' => $transition,
'workflow_token_type' => 'WorkflowTransition',
);
$sub_data += $data;
$replacements += token_generate('entity', $sub_tokens, $sub_data, $options);
}
if (isset($data['WorkflowTransition'])) {
// If this is a WorkflowField, get subtokens for it.
$name_parts = explode(':', $name, 2);
$field_name = reset($name_parts);
if ($field_name != 'created' && isset($entity->{$field_name}) && ($sub_tokens = token_find_with_prefix($tokens, $field_name))) {
$transition = _workflow_tokens_get_transition($entity_type, $entity, $field_name);
$sub_data = array(
'WorkflowTransition' => $transition,
'workflow_token_type' => 'WorkflowTransition',
);
$sub_data += $data;
$replacements += token_generate('entity', $sub_tokens, $sub_data, $options);
}
$transition = $data['WorkflowTransition'];
$field_name = $transition->field_name;
if ($sub_tokens = token_find_with_prefix($tokens, 'Workflow')) {
$sub_data = array(
'Workflow' => $transition
->getWorkflow(),
'workflow_token_type' => 'Workflow',
);
$sub_data += $data;
$replacements += token_generate('entity', $sub_tokens, $sub_data, $options);
}
// Unify to old-state, new-state.
// Do not use underscores, or workflow_tokens will not work!
if ($sub_tokens = token_find_with_prefix($tokens, 'old-state')) {
$sub_data = array(
'WorkflowState' => $transition
->getOldState(),
'workflow_token_type' => 'WorkflowState',
);
$sub_data += $data;
$replacements += token_generate('entity', $sub_tokens, $sub_data, $options);
}
if ($sub_tokens = token_find_with_prefix($tokens, 'new-state')) {
$sub_data = array(
'WorkflowState' => $transition
->getNewState(),
'workflow_token_type' => 'WorkflowState',
);
$sub_data += $data;
$replacements += token_generate('entity', $sub_tokens, $sub_data, $options);
}
if ($sub_tokens = token_find_with_prefix($tokens, 'user')) {
if (isset($data['WorkflowTransition'])) {
$sub_entity = $data['WorkflowTransition'];
}
$sub_data = array(
'entity_type' => 'user',
'user' => user_load($sub_entity->uid),
'token_type' => 'user',
);
$replacements += token_generate('user', $sub_tokens, $sub_data, $options);
}
if ($sub_tokens = token_find_with_prefix($tokens, 'created')) {
$sub_data = array(
'entity_type' => 'date',
'date' => $data['WorkflowTransition']->stamp,
'token_type' => 'date',
);
$replacements += token_generate('date', $sub_tokens, $sub_data, $options);
}
}
}
return $replacements;
}
/**
* Gets the token replacement by correctly obeying the options.
*
* Taken from _entity_token_get_token().
*/
function _workflow_token_get_token($wrapper, $options) {
// if ($wrapper->value() === NULL) {
// // Do not provide a replacement if there is no value.
// return NULL;
// }
if (empty($options['sanitize'])) {
// When we don't need sanitized tokens decode already sanitizied texts.
$options['decode'] = TRUE;
}
$langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
// If there is a label for a property, e.g., defined by an options list or an
// entity label, make use of it.
if ($label = $wrapper
->label()) {
return $label;
}
switch ($wrapper
->type()) {
case 'Workflow':
case 'WorkflowState':
case 'WorkflowTransition':
return $wrapper
->value();
}
// Care for outputing list values.
if ($wrapper instanceof EntityListWrapper) {
$output = array();
foreach ($wrapper as $item) {
$output[] = _workflow_token_get_token($item, $options);
}
return implode(', ', $output);
}
// Else we do not have a good string to output, e.g., for struct values. Just
// output the string representation of the wrapper.
return (string) $wrapper;
}
/**
* Helper function to get the Transition.
*
* If the node is being created or updated (using the NUMERIC id),
* do not read from db, since the field widget has not been processed yet.
* @todo: solve this with module weight?
*/
function _workflow_tokens_get_transition($entity_type, $entity, $field_name) {
global $user;
$transitions = array();
list($entity_id, , $entity_bundle) = entity_extract_ids($entity_type, $entity);
$langcode = _workflow_metadata_workflow_get_properties($entity, array(), 'langcode', $entity_type, $field_name);
if (!empty($entity_id) && !isset($entity->original)) {
$transition = workflow_transition_load_single($entity_type, $entity_id, $field_name);
return $transition;
}
// Get transition data from online-data.
// Create dummy transitions, just to set $node->workflow_transitions[].
foreach (_workflow_info_fields($entity, $entity_type, $entity_bundle) as $found_name => $field) {
// If $field_name = NULL, any workflow_field/node is OK.
if ($field_name != NULL && $found_name != $field_name) {
continue;
}
$old_sid = FALSE;
$new_sid = $found_name ? _workflow_get_sid_by_items($entity->{$found_name}[$langcode]) : $entity->workflow_sid;
if (!isset($entity_id)) {
// Creating an entity.
// When creating a node, and only 1 valid sid is available, then the
// widget is not shown. This generates a problem, since the new/old
// sid isn't yet loaded in the Entity.
if ($new_state = workflow_state_load_single($new_sid)) {
$workflow = $new_state
->getWorkflow();
$old_sid = $workflow
->getCreationSid();
}
else {
// $field['settings']['wid'] can be numeric or named.
$workflow = workflow_load_single($field['settings']['wid']);
$old_sid = $workflow
->getCreationSid();
$new_sid = $workflow
->getFirstSid($entity_type, $entity, $field_name, $user, FALSE);
}
}
elseif (isset($entity->original)) {
if ($field_name && !isset($entity->original->{$found_name}[$langcode])) {
// When updating a node, that did not have a workflow attached before.
// (Happens when you add workflows to existing Entity types.)
$old_sid = workflow_node_previous_state($entity, $entity_type, $found_name);
}
elseif ($field_name) {
// Updating an entity.
$old_sid = _workflow_get_sid_by_items($entity->original->{$found_name}[$langcode]);
}
else {
$old_sid = workflow_node_previous_state($entity, $entity_type, $found_name);
}
}
$transition = new WorkflowTransition();
$transition
->setValues($entity_type, $entity, $field_name, $old_sid, $new_sid, $user->uid, REQUEST_TIME, '');
// 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'.
$transitions[$field_name] = $transition;
}
$transition = $field_name && isset($transitions[$field_name]) ? $transitions[$field_name] : reset($transitions);
return $transition;
}
Functions
Name | Description |
---|---|
workflow_tokens | Implements hook_tokens(). |
workflow_token_info | Implements hook_token_info(). |
workflow_token_info_alter | Adds a subtree to each WorkflowField. |
_workflow_tokens_get_transition | Helper function to get the Transition. |
_workflow_token_get_token | Gets the token replacement by correctly obeying the options. |