Hello,

I am trying to figure out why $node->taxonomy changes format on how it is indexed. Normally $node->taxonomy an array with the key being the vocabulary id and the value being the term id. It seems that $node->taxonomy can change to being an array with the key being the term id and the value being and term object. I think that is a bug where the array should be keyed off the vocabulary id and the value being the term object.

Below are two var_dumps of the $node and it shows what I am talking about.

----- ids ------
 ["taxonomy"]=>
 array(2) {
   [6]=>
   string(2) "14"
   [3]=>
   string(2) "22"
 }
----- objects ------
 ["taxonomy"]=>
 array(2) {
   [14]=>
   object(stdClass)#12 (5) {
     ["tid"]=>
     string(2) "14"
     ["vid"]=>
     string(1) "6"
     ["name"]=>
     string(8) "<name>"
     ["description"]=>
     string(37) "<desc>"
     ["weight"]=>
     string(1) "1"
   }
   [22]=>
   object(stdClass)#13 (5) {
     ["tid"]=>
     string(2) "22"
     ["vid"]=>
     string(1) "3"
     ["name"]=>
     string(33) "<name>"
     ["description"]=>
     string(33) "<desc>"
     ["weight"]=>
     string(1) "1"
   }
 }
-----

I think the patch below will fix the problem, but I am not sure what it might break, can you give any in sight?

I think this is a big problem if you have a vocabulary id of say 5 that is multiple select and a term id of 5, I am pretty sure bad things will happen.

Thanks,

Brian

--- taxonomy.module.orig        Sat Feb 21 14:16:23 2009
+++ taxonomy.module     Sat Feb 21 14:17:33 2009
@@ -583,13 +583,15 @@
             $taxonomy['tags'] = $term;
           }
           else {
-            $taxonomy[$tid] = taxonomy_get_term($tid);
+            $t = taxonomy_get_term($tid);
+            $taxonomy[$t->vid] = $t;
           }
         }
       }
       // A 'Single select' field returns the term id.
       elseif ($term) {
-        $taxonomy[$term] = taxonomy_get_term($term);
+        $t = taxonomy_get_term($term);
+        $taxonomy[$t->vid] = t;
       }
     }
   }
@@ -599,7 +601,7 @@
 /**
  * Find all terms associated with the given node, within one vocabulary.
  */
-function taxonomy_node_get_terms_by_vocabulary($node, $vid, $key = 'tid') {
+function taxonomy_node_get_terms_by_vocabulary($node, $vid, $key = 'vid') {
   $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.vid = %d ORDER BY weight', 't', 'tid'), $vid, $node->vid);
   $terms = array();
   while ($term = db_fetch_object($result)) {
@@ -611,7 +613,7 @@
 /**
  * Find all terms associated with the given node, ordered by vocabulary and term weight.
  */
-function taxonomy_node_get_terms($node, $key = 'tid') {
+function taxonomy_node_get_terms($node, $key = 'vid') {
   static $terms;
 
   if (!isset($terms[$node->vid][$key])) {
@@ -734,7 +736,7 @@
 /**
  * Find all term objects related to a given term ID.
  */
-function taxonomy_get_related($tid, $key = 'tid') {
+function taxonomy_get_related($tid, $key = 'vid') {
   if ($tid) {
     $result = db_query('SELECT t.*, tid1, tid2 FROM {term_relation}, {term_data} t WHERE (t.tid = tid1 OR t.tid = tid2) AND (tid1 = %d OR tid2 = %d) AND t.tid != %d ORDER BY weight, name', $tid, $tid, $tid);
     $related = array();
@@ -751,7 +753,7 @@
 /**
  * Find all parents of a given term ID.
  */
-function taxonomy_get_parents($tid, $key = 'tid') {
+function taxonomy_get_parents($tid, $key = 'vid') {
   if ($tid) {
     $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.parent = t.tid WHERE h.tid = %d ORDER BY weight, name', 't', 'tid'), $tid);
     $parents = array();
@@ -784,7 +786,7 @@
 /**
  * Find all children of a term ID.
  */
-function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
+function taxonomy_get_children($tid, $vid = 0, $key = 'vid') {
   if ($vid) {
     $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.tid = t.tid WHERE t.vid = %d AND h.parent = %d ORDER BY weight, name', 't', 'tid'), $vid, $tid);
   }

Comments

hawk259’s picture

Here is an example of a problem I am talking about:

 ["taxonomy"]=>
 array(2) {
   [3]=>
   string(2) "23"
   [13]=>
   object(stdClass)#168 (5) {
     ["tid"]=>
     string(2) "13"
     ["vid"]=>
     string(1) "6"
     ["name"]=>
     string(7) "Pending"
     ["description"]=>
     string(0) ""
     ["weight"]=>
     string(1) "0"
   }
 }

What happens if you happen to have a term with an id of 3, since there is already vocabulary with an id of 3? I can't explain why only one item is objectized and the other item isn't.

This is a rules trigger that sends email on new content, in the email I var_dump($node).

Brian

hawk259’s picture

Hmm, that patch doesn't seem to fix things. Something else is happening that is causing this.

Still trying to figure out what. Any ideas?

hawk259’s picture

I think I can explain the mixing of vid -> tid and tid -> term object in the same array from comment #1 by a rule that was assigning a term.

But that still leave us with the issue of vid -> tid vs tid-> term object issues. I notice when I create or edit a node it is vid->tid, but when I add a comment it is tid -> term object.

Can anybody shed any light on this?

I am going to try my patch again tomorrow and see what happens.

damien tournoud’s picture

Category: bug » support

The format of $node->taxonomy during select (or as submit time), is different then the one you will get from node_load(). This is not a bug.

See http://api.drupal.org/api/function/taxonomy_form_alter and http://api.drupal.org/api/function/taxonomy_preview_terms

hawk259’s picture

Install Drupal 6.9 with rules 1.0beta-4.

Enable the following modules:

  PHP filter
  Rules module

Do the following:

Add Vocabulary:

  Name: v1
  Conent Type: page
  Settings: Required

Add Vocabulary:

  Name: v2
  Conent Type: page
  Settings: Required

To Vocabulary v2 Add Term:

   Term Name: v2:t1
   Term Name: v2:t2
   Term Name: v2:t3
   Term Name: v2:t4

To Vocabulary v1 Add Term:

   Term Name: v1:t5
   Term Name: v1:t6
   Term Name: v1:t7
   Term Name: v1:t8

Make sure the following has happened:

  v1 has vid = 1
  v2 has vid = 2

  v2:t1 has tid = 1
  v2:t2 has tid = 2
  v2:t3 has tid = 3
  v2:t4 has tid = 4

  v1:t5 has tid = 5
  v1:t6 has tid = 6
  v1:t7 has tid = 7
  v1:t8 has tid = 8

Add the following Rule Triggers:

  Node -> After saving new content
  Node -> After updating existing content
  Node -> Content is going to be saved
  Comment -> After saving a new comment

Each Trigger should have one action:

  Send a mail to an arbitrary mail address

Use your email address, subject use the above label so you know what each email is for and the body should be this:

  <?PHP var_dump($node); ?>

Create page:

    Title: p1
       v1: v1:t8
       v2: v2:v4
     body: p1
 Comments: Read/Write

You should get two emails:

"Node -> Content is going to be saved"

 ["taxonomy"]=>
 array(2) {
   [1]=>
   string(1) "8"
   [2]=>
   string(1) "4"
 }
 ["nid"]=>
 NULL

"Node -> After saving new content"

 ["taxonomy"]=>
 array(2) {
   [1]=>
   string(1) "8"
   [2]=>
   string(1) "4"
 }
 ["nid"]=>
 string(1) "1"

Now edit the page and set:

    Title: p1:1
       v1: v1:t8
       v2: v2:v4
     body: p1:1
 Comments: Read/Write

You should get two emails:

"Node -> Content is going to be saved"

 ["nid"]=>
 string(1) "1"
 ["taxonomy"]=>
 array(2) {
   [1]=>
   string(1) "8"
   [2]=>
   string(1) "4"
 }

"Node -> After saving new content"

 ["nid"]=>
 string(1) "1"
 ["taxonomy"]=>
 array(2) {
   [1]=>
   string(1) "8"
   [2]=>
   string(1) "4"
 }

Now lets add a comment on p1:1:

  subject: c1
     body: c1

you should get one email:

"Comment -> After saving a new comment"

 ["nid"]=>
 string(1) "1"
 ["taxonomy"]=>
 array(2) {
   [8]=>
   object(stdClass)#6 (5) {
     ["tid"]=>
     string(1) "8"
     ["vid"]=>
     string(1) "1"
     ["name"]=>
     string(5) "v1:t8"
     ["description"]=>
     string(0) ""
     ["weight"]=>
     string(1) "0"
   }
   [4]=>
   object(stdClass)#7 (5) {
     ["tid"]=>
     string(1) "4"
     ["vid"]=>
     string(1) "2"
     ["name"]=>
     string(5) "v2:t4"
     ["description"]=>
     string(0) ""
     ["weight"]=>
     string(1) "0"
   }
 }

Can you explain why both adding and editing a page the taxonomy stays in the format vid => tid, but when adding a comment taxonomy is in the format tid => term object?

I can understand if nid == NULL it would be in the format of vid => tid, but after saving a new page and when updating an existing page shouldn't the taxonomy be in the format of tid => term object?

Is this a problem with node.module adding/editing nodes and not loading the taxonomy right? Is this a problems with rules.module some how loading the taxonomy differently for the node?

hawk259’s picture

Can I assume that if any value in the $node->taxonomy is a object, then it is in tid => term object mode? Something like this:

$tax_preview_mode = 0;

if (is_array($node->taxonomy)) {
  reset($node->taxonomy) 
  if (count($node->taxonomy) != 0 && is_object(current($node->taxonomy)) === FALSE) {
    $tax_preview_mode = 1;
  }
}

Or is there a better way to detect form mode (vid => tid) vs tid => term mode (no idea what to call that, alt mode)?

dpearcefl’s picture

Do you still need help with this issue?

mdupont’s picture

Status: Active » Closed (won't fix)

Old issue, and this is the way taxonomy is intended to work so I'm marking it "won't fix". Node taxonomy can come in 3 flavors: an array of vids containing an array of tids, an array of term objects, and an array of tids.

In all cases, it is easy to check which flavor is used. See http://api.drupal.org/api/drupal/modules--taxonomy--taxonomy.module/func... about how Drupal core handles it.