From 9f07e8984d76fdde757b07e67f230ba5022d6482 Mon Sep 17 00:00:00 2001
From: Dave Reid <dave@davereid.net>
Date: Tue, 6 Sep 2011 10:45:32 -0500
Subject: [PATCH] Issue #1266928: Added [menu-link:parents] and [term:parents] array tokens.

---
 token.inc        |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 token.info       |    1 +
 token.module     |   39 +++++++++++++++++++++++++++++++
 token.tokens.inc |   37 ++++++++++++++++++++++++++++++
 4 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 token.inc

diff --git a/token.inc b/token.inc
new file mode 100644
index 0000000..0d95adc
--- /dev/null
+++ b/token.inc
@@ -0,0 +1,66 @@
+<?php
+
+class TokenObject {
+  protected $data = NULL;
+
+  function __construct($data) {
+    $this->data = $data;
+  }
+
+  public function __get($name) {
+    if (isset($this->{$name})) {
+      if (is_array($this->data)) {
+        return $this->data[$name];
+      }
+      elseif (is_object($this->data) && property_exists($this->data, $name)) {
+        return $this->data->{$name};
+      }
+    }
+  }
+
+  public function __set($name, $value) {
+    if (is_array($this->data)) {
+      return $this->data[$name];
+    }
+    elseif (is_object($this->data)) {
+      return $this->data->{$name};
+    }
+  }
+
+  public function __isset($name) {
+    if (is_array($this->data)) {
+      return array_key_exists($name, $this->data);
+    }
+    elseif (is_object($this->data)) {
+      return property_exists($this->data, $name);
+    }
+  }
+
+  public function __unset($name) {
+    if (is_array($this->data)) {
+      unset($this->data[$name]);
+    }
+    elseif (is_object($this->data)) {
+      unset($this->data->{$name});
+    }
+  }
+}
+
+class EntityTokenObject extends TokenObject {
+  private $entity_type;
+
+  function __construct($entity_type, $entity) {
+    $this->entity_type = $entity_type;
+    $this->data = $entity;
+  }
+
+  public function __toString() {
+    return entity_label($this->entity_type, $this->data);
+  }
+}
+
+class MenuTokenObject extends TokenObject {
+  public function __toString() {
+    return $this->data['title'];
+  }
+}
diff --git a/token.info b/token.info
index b65e29f..ce68804 100644
--- a/token.info
+++ b/token.info
@@ -6,3 +6,4 @@ files[] = token.install
 files[] = token.tokens.inc
 files[] = token.pages.inc
 files[] = token.test
+files[] = token.inc
diff --git a/token.module b/token.module
index 2e16d3d..ca73f95 100644
--- a/token.module
+++ b/token.module
@@ -919,6 +919,45 @@ function token_menu_link_load($mlid) {
   return $cache[$mlid];
 }
 
+function token_menu_link_load_all_parents($mlid) {
+  $cache = &drupal_static(__FUNCTION__, array());
+
+  if (!is_numeric($mlid)) {
+    return array();
+  }
+
+  if (!isset($cache[$mlid])) {
+    $cache[$mlid] = array();
+    $plid = db_query("SELECT plid FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $mlid))->fetchField();
+    while ($plid && $parent = token_menu_link_load($plid)) {
+      $cache[$mlid] = array($plid => new MenuTokenObject($parent)) + $cache[$mlid];
+      $plid = $parent['plid'];
+    }
+  }
+
+  return $cache[$mlid];
+}
+
+function token_taxonomy_term_load_all_parents($tid) {
+  $cache = &drupal_static(__FUNCTION__, array());
+
+  if (!is_numeric($tid)) {
+    return array();
+  }
+
+  if (!isset($cache[$tid])) {
+    $cache[$tid] = array();
+    $parents = taxonomy_get_parents_all($tid);
+    array_shift($parents); // Remove this term from the array.
+    $parents = array_reverse($parents);
+    foreach ($parents as $term) {
+      $cache[$tid][$term->tid] = new EntityTokenObject('taxonomy_term', $term);
+    }
+  }
+
+  return $cache[$tid];
+}
+
 /**
  * Get a translated book menu link by its mlid, without access checking.
  *
diff --git a/token.tokens.inc b/token.tokens.inc
index f9b89fc..288f36f 100644
--- a/token.tokens.inc
+++ b/token.tokens.inc
@@ -138,6 +138,12 @@ function token_token_info() {
       'description' => t("The root term of the taxonomy term."),
       'type' => 'term',
     );
+    $info['tokens']['term']['parents'] = array(
+      'name' => t('Parents'),
+      'description' => t("An array of all the term's parents, starting with the root."),
+      'type' => 'array',
+      'sub-type' => 'term',
+    );
 
     $info['tokens']['vocabulary']['machine-name'] = array(
       'name' => t('Machine-readable name'),
@@ -222,6 +228,12 @@ function token_token_info() {
     'description' => t("The menu link's root."),
     'type' => 'menu-link',
   );
+  $info['tokens']['menu-link']['parents'] = array(
+    'name' => t('Parents'),
+    'description' => t("An array of all the menu link's parents, starting with the root."),
+    'type' => 'array',
+    'sub-type' => 'menu-link',
+  );
 
   // Current page tokens.
   $info['types']['current-page'] = array(
@@ -464,6 +476,12 @@ function token_tokens($type, $tokens, array $data = array(), array $options = ar
             $replacements[$original] = $sanitize ? check_plain($root_term->name) : $root_term->name;
           }
           break;
+
+        case 'parents':
+          if ($parents = token_taxonomy_term_load_all_parents($term->tid)) {
+            $replacements[$original] = token_render_array($parents, $options);
+          }
+          break;
       }
     }
 
@@ -478,6 +496,13 @@ function token_tokens($type, $tokens, array $data = array(), array $options = ar
         $replacements += token_generate('term', $root_tokens, array('term' => $root_term), $options);
       }
     }
+
+    // [term:parents:*] chained tokens.
+    if ($parents_tokens = token_find_with_prefix($tokens, 'parents')) {
+      if ($parents = token_taxonomy_term_load_all_parents($term->tid)) {
+        $replacements += token_generate('array', $parents_tokens, array('array' => $parents), $options);
+      }
+    }
   }
 
   // Vocabulary tokens.
@@ -587,6 +612,11 @@ function token_tokens($type, $tokens, array $data = array(), array $options = ar
             $replacements[$original] = $sanitize ? check_plain($root['title']) : $root['title'];
           }
           break;
+        case 'parents':
+          if ($parents = token_menu_link_load_all_parents($link['mlid'])) {
+            $replacements[$original] = token_render_array($parents, $options);
+          }
+          break;
       }
     }
 
@@ -600,6 +630,13 @@ function token_tokens($type, $tokens, array $data = array(), array $options = ar
     if ($url_tokens = token_find_with_prefix($tokens, 'url')) {
       $replacements += token_generate('url', $url_tokens, array('path' => $link['href']), $options);
     }
+
+    // [menu-link:parents:*] chained tokens.
+    if ($parents_tokens = token_find_with_prefix($tokens, 'parents')) {
+      if ($parents = token_menu_link_load_all_parents($link['mlid'])) {
+        $replacements += token_generate('array', $parents_tokens, array('array' => $parents), $options);
+      }
+    }
   }
 
   // Current page tokens.
-- 
1.7.1

