$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 (604800). 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, // 'WorkflowTransition' => $workflow_transition, // 'WorkflowState' => $workflow_state, // 'Workflow' => $workflow, ), ); 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; }