Index: token.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/token/token.module,v retrieving revision 1.62 diff -u -p -r1.62 token.module --- token.module 31 Jan 2011 21:10:02 -0000 1.62 +++ token.module 14 Feb 2011 23:12:49 -0000 @@ -770,6 +770,23 @@ function _token_build_tree($token_type, return $tree; } +function token_render_array($array, array $options = array()) { + $rendered = array_map('render', $array); + if (!empty($options['sanitize'])) { + $rendered = array_map('check_plain', $rendered); + } + $join = isset($options['join']) ? $options['join'] : ', '; + return implode($join, $rendered); +} + +function token_render_array_value($value, array $options = array()) { + $rendered = render($value); + if (!empty($options['sanitize'])) { + $rendered = check_plina($rendered); + } + return $rendered; +} + /** * Find tokens that have been declared twice by different modules. */ Index: token.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/token/token.test,v retrieving revision 1.32 diff -u -p -r1.32 token.test --- token.test 12 Jan 2011 03:26:59 -0000 1.32 +++ token.test 14 Feb 2011 23:12:49 -0000 @@ -739,3 +739,36 @@ class TokenCurrentPageTestCase extends T $this->assertPageTokens("node/{$node->nid}", $tokens); } } + +class TokenArrayTestCase extends TokenTestHelper { + public static function getInfo() { + return array( + 'name' => 'Array token tests', + 'description' => 'Test the array tokens.', + 'group' => 'Token', + ); + } + + function testArrayTokens() { + $array = array(0 => 'a', 1 => 'b', 2 => 'c', 4 => 'd'); + + // Test the profile token values. + $tokens = array( + 'first' => 'a', + 'last' => 'd', + 'value:0' => 'a', + 'value:2' => 'c', + 'count' => 4, + 'keys' => '0, 1, 2, 4', + 'keys:value:3' => 4, + 'keys:join' => '0124', + 'reversed' => 'd, c, b, a', + 'reversed:keys' => '4, 2, 1, 0', + 'join:/' => 'a/b/c/d', + 'join' => 'abcd', + 'join:, ' => 'a, b, c, d', + 'join: ' => 'a b c d', + ); + $this->assertTokens('array', $array, $tokens); + } +} Index: token.tokens.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/token/token.tokens.inc,v retrieving revision 1.39 diff -u -p -r1.39 token.tokens.inc --- token.tokens.inc 31 Jan 2011 21:10:02 -0000 1.39 +++ token.tokens.inc 14 Feb 2011 23:12:50 -0000 @@ -149,6 +149,11 @@ function token_token_info() { 'type' => 'file', ); } + $info['tokens']['user']['roles'] = array( + 'name' => t('Roles'), + 'description' => t('The user roles associated with the user account.'), + 'type' => 'array', + ); // Current user tokens. $info['tokens']['current-user']['ip-address'] = array( @@ -210,6 +215,7 @@ function token_token_info() { 'dynamic' => TRUE, ); + // URL tokens. $info['types']['url'] = array( 'name' => t('URL'), 'description' => t('Tokens related to URLs.'), @@ -232,6 +238,40 @@ function token_token_info() { 'description' => t('The absolute URL.'), ); + // Array tokens. + $info['types']['array'] = array( + 'name' => t('Array'), + 'description' => t('Tokens related to arrays of strings.'), + 'needs-data' => 'array', + ); + $info['tokens']['array']['first'] = array( + 'name' => t('First'), + 'description' => t('The first element of the array.'), + ); + $info['tokens']['array']['last'] = array( + 'name' => t('Last'), + 'description' => t('The last element of the array.'), + ); + $info['tokens']['array']['count'] = array( + 'name' => t('Count'), + 'description' => t('The number of elements in the array.'), + ); + $info['tokens']['array']['reversed'] = array( + 'name' => t('Reversed'), + 'description' => t('The array reversed.'), + 'type' => 'array', + ); + $info['tokens']['array']['keys'] = array( + 'name' => t('Keys'), + 'description' => t('The array of keys of the array.'), + 'type' => 'array', + ); + $info['tokens']['array']['join'] = array( + 'name' => t('Imploded'), + 'description' => t('The values of the array joined together with a custom string in-between each value.'), + 'dynamic' => TRUE, + ); + return $info; } @@ -392,6 +432,9 @@ function token_tokens($type, $tokens, ar $replacements[$original] = theme('user_picture', array('account' => $account)); } break; + case 'roles': + $replacements[$original] = token_render_array($account->roles, $options); + break; } } @@ -401,9 +444,12 @@ function token_tokens($type, $tokens, ar $account->picture->description = ''; $replacements += token_generate('file', $picture_tokens, array('file' => $account->picture), $options); } - if (($url_tokens = token_find_with_prefix($tokens, 'url'))) { + if ($url_tokens = token_find_with_prefix($tokens, 'url')) { $replacements += token_generate('url', $url_tokens, entity_uri('user', $account), $options); } + if ($role_tokens = token_find_with_prefix($tokens, 'roles')) { + $replacements += token_generate('array', $role_tokens, array('array' => $account->roles), $options); + } } // Current user tokens. @@ -555,6 +601,64 @@ function token_tokens($type, $tokens, ar } } + // Array tokens. + if ($type == 'array' && !empty($data['array']) && is_array($data['array'])) { + $array = $data['array']; + + foreach ($tokens as $name => $original) { + switch ($name) { + case 'first': + $first = reset($array); + $replacements[$original] = token_render_array_value($first, $options); + reset($array); + break; + case 'last': + $last = end($array); + $replacements[$original] = token_render_array_value($last, $options); + reset($array); + break; + case 'count': + $replacements[$original] = count($array); + break; + case 'keys': + $keys = array_keys($array); + $replacements[$original] = token_render_array($keys, $options); + break; + case 'reversed': + $reversed = array_reverse($array); + $replacements[$original] = token_render_array($reversed, $options); + break; + case 'join': + $replacements[$original] = token_render_array($array, array('join' => '') + $options); + break; + } + } + + // Dynamic tokens. + if ($value_tokens = token_find_with_prefix($tokens, 'value')) { + foreach ($value_tokens as $key => $original) { + if (isset($array[$key])) { + $replacements[$original] = token_render_array_value($array[$key], $options); + } + } + } + if ($join_tokens = token_find_with_prefix($tokens, 'join')) { + foreach ($join_tokens as $join => $original) { + $replacements[$original] = token_render_array($array, array('join' => $join) + $options); + } + } + + // Chained token relationships. + if ($key_tokens = token_find_with_prefix($tokens, 'keys')) { + $replacements += token_generate('array', $key_tokens, array('array' => array_keys($array)), $options); + } + if ($reversed_tokens = token_find_with_prefix($tokens, 'reversed')) { + $replacements += token_generate('array', $reversed_tokens, array('array' => array_reverse($array)), $options); + } + + // @todo Handle if the array values are not strings and could be chained. + } + // If $type is a token type, $data[$type] is empty but $data[$entity_type] is // not, re-run token replacements. if (empty($data[$type]) && ($entity_type = token_get_entity_mapping('token', $type)) && $entity_type != $type && !empty($data[$entity_type]) && empty($options['recursive'])) {