Index: modules/forum/forum-topic-list.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum-topic-list.tpl.php,v
retrieving revision 1.7
diff -u -p -r1.7 forum-topic-list.tpl.php
--- modules/forum/forum-topic-list.tpl.php 28 Jul 2009 10:41:20 -0000 1.7
+++ modules/forum/forum-topic-list.tpl.php 8 Oct 2009 07:29:02 -0000
@@ -20,7 +20,7 @@
* - $topic->message: If the topic has been moved, this contains an
* explanation and a link.
* - $topic->zebra: 'even' or 'odd' string used for row class.
- * - $topic->num_comments: The number of replies on this topic.
+ * - $topic->comment_count: The number of replies on this topic.
* - $topic->new_replies: A flag to indicate whether there are unread comments.
* - $topic->new_url: If there are unread replies, this is a link to them.
* - $topic->new_text: Text containing the translated, properly pluralized count.
@@ -53,7 +53,7 @@
message; ?> |
- num_comments; ?>
+ comment_count; ?>
new_replies): ?>
new_text; ?>
Index: modules/forum/forum.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.admin.inc,v
retrieving revision 1.25
diff -u -p -r1.25 forum.admin.inc
--- modules/forum/forum.admin.inc 18 Sep 2009 00:12:46 -0000 1.25
+++ modules/forum/forum.admin.inc 8 Oct 2009 07:29:02 -0000
@@ -5,8 +5,8 @@
* @file
* Administrative page callbacks for the forum module.
*/
-
function forum_form_main($type, $edit = array()) {
+ $edit = (array) $edit;
if ((isset($_POST['op']) && $_POST['op'] == t('Delete')) || !empty($_POST['confirm'])) {
return drupal_get_form('forum_confirm_delete', $edit['tid']);
}
Index: modules/forum/forum.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.install,v
retrieving revision 1.35
diff -u -p -r1.35 forum.install
--- modules/forum/forum.install 29 Sep 2009 15:13:55 -0000 1.35
+++ modules/forum/forum.install 8 Oct 2009 07:29:02 -0000
@@ -22,9 +22,7 @@ function forum_install() {
function forum_enable() {
if ($vocabulary = taxonomy_vocabulary_load(variable_get('forum_nav_vocabulary', 0))) {
- // Existing install. Add back forum node type, if the forums
- // vocabulary still exists. Keep all other node types intact there.
- $vocabulary->nodes['forum'] = 1;
+ // Save the vocabulary to create the default field instance.
taxonomy_vocabulary_save($vocabulary);
}
else {
@@ -33,17 +31,26 @@ function forum_enable() {
// forms.
$edit = array(
'name' => t('Forums'),
- 'multiple' => 0,
- 'required' => 0,
+ 'machine_name' => 'forums',
+ 'description' => t('Forum navigation vocabulary'),
'hierarchy' => 1,
'relations' => 0,
'module' => 'forum',
'weight' => -10,
- 'nodes' => array('forum' => 1),
);
$vocabulary = (object) $edit;
taxonomy_vocabulary_save($vocabulary);
+ $instance = array(
+ 'field_name' => 'taxonomy_' . $vocabulary->machine_name,
+ 'label' => $vocabulary->name,
+ 'bundle' => 'forum',
+ 'widget' => array(
+ 'type' => 'options_select',
+ ),
+ );
+ field_create_instance($instance);
+
variable_set('forum_nav_vocabulary', $vocabulary->vid);
}
}
@@ -109,6 +116,68 @@ function forum_schema() {
),
);
+ $schema['forum_index'] = array(
+ 'description' => 'Maintains denormalized information about node/term relationships.',
+ 'fields' => array(
+ 'nid' => array(
+ 'description' => 'The {node}.nid this record tracks.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'title' => array(
+ 'description' => 'The title of this node, always treated as non-markup plain text.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'tid' => array(
+ 'description' => 'The term ID.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'sticky' => array(
+ 'description' => 'Boolean indicating whether the node is sticky.',
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'default' => 0,
+ 'size' => 'tiny',
+ ),
+ 'created' => array(
+ 'description' => 'The Unix timestamp when the node was created.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default'=> 0,
+ ),
+ 'last_comment_timestamp' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The Unix timestamp of the last comment that was posted within this node, from {comment}.timestamp.',
+ ),
+ 'comment_count' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The total number of comments on this node.',
+ ),
+ ),
+ 'indexes' => array(
+ 'forum_topics' => array('tid', 'sticky', 'last_comment_timestamp'),
+ ),
+ 'foreign keys' => array(
+ 'node' => 'nid',
+ 'taxonomy_term_data' => 'tid',
+ ),
+ );
+
+
return $schema;
}
@@ -119,3 +188,74 @@ function forum_update_7000() {
db_drop_index('forum', 'nid');
db_add_index('forum', 'forum_topic', array('nid', 'tid'));
}
+
+/**
+ * Create new {forum_index} table.
+ */
+function forum_update_7001() {
+ $forum_index = array(
+ 'description' => 'Maintains denormalized information about node/term relationships.',
+ 'fields' => array(
+ 'nid' => array(
+ 'description' => 'The {node}.nid this record tracks.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'title' => array(
+ 'description' => 'The title of this node, always treated as non-markup plain text.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'tid' => array(
+ 'description' => 'The term ID.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'sticky' => array(
+ 'description' => 'Boolean indicating whether the node is sticky.',
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'default' => 0,
+ 'size' => 'tiny',
+ ),
+ 'created' => array(
+ 'description' => 'The Unix timestamp when the node was created.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default'=> 0,
+ ),
+ 'last_comment_timestamp' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The Unix timestamp of the last comment that was posted within this node, from {comment}.timestamp.',
+ ),
+ 'comment_count' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The total number of comments on this node.',
+ ),
+ ),
+ 'indexes' => array(
+ 'forum_topics' => array('tid', 'sticky', 'last_comment_timestamp'),
+ ),
+ 'foreign keys' => array(
+ 'node' => 'nid',
+ 'taxonomy_term_data' => 'tid',
+ ),
+ );
+ db_create_table($ret, 'forum_index', $forum_index);
+
+ db_query('INSERT INTO {forum_index} (SELECT n.nid, n.title, f.tid, n.sticky, n.created, ncs.last_comment_timestamp, ncs.comment_count FROM {node} n INNER JOIN {forum} f on n.vid = f.vid INNER JOIN {node_comment_statistics} ncs ON n.nid = ncs.nid)');
+
+ return $ret;
+}
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.519
diff -u -p -r1.519 forum.module
--- modules/forum/forum.module 18 Sep 2009 00:04:22 -0000 1.519
+++ modules/forum/forum.module 8 Oct 2009 07:29:02 -0000
@@ -61,25 +61,6 @@ function forum_theme() {
}
/**
- * Fetch a forum term.
- *
- * @param $tid
- * The ID of the term which should be loaded.
- *
- * @return
- * An associative array containing the term data or FALSE if the term cannot be loaded, or is not part of the forum vocabulary.
- */
-function forum_term_load($tid) {
- return db_select('taxonomy_term_data', 't')
- ->fields('t', array('tid', 'vid', 'name', 'description', 'weight'))
- ->condition('tid', $tid)
- ->condition('vid', variable_get('forum_nav_vocabulary', 0))
- ->addTag('term_access')
- ->execute()
- ->fetchAssoc();
-}
-
-/**
* Implement hook_menu().
*/
function forum_menu() {
@@ -130,13 +111,13 @@ function forum_menu() {
'parent' => 'admin/structure/forum',
'file' => 'forum.admin.inc',
);
- $items['admin/structure/forum/edit/%forum_term'] = array(
+ $items['admin/structure/forum/edit/%taxonomy_term'] = array(
'page callback' => 'forum_form_main',
'access arguments' => array('administer forums'),
'type' => MENU_CALLBACK,
'file' => 'forum.admin.inc',
);
- $items['admin/structure/forum/edit/container/%forum_term'] = array(
+ $items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
'title' => 'Edit container',
'page callback' => 'forum_form_main',
'page arguments' => array('container', 5),
@@ -144,7 +125,7 @@ function forum_menu() {
'type' => MENU_CALLBACK,
'file' => 'forum.admin.inc',
);
- $items['admin/structure/forum/edit/forum/%forum_term'] = array(
+ $items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
'title' => 'Edit forum',
'page callback' => 'forum_form_main',
'page arguments' => array('forum', 5),
@@ -164,28 +145,19 @@ function forum_init() {
}
/**
- * _forum_node_check_node_type
+ * Check whether a content type can be used in a forum.
*
- * @param mixed $node
- * @param mixed $vocabulary
- * @access protected
- * @return bool
+ * @param $node
+ * A node object.
+ *
+ * @return
+ * Boolean indicating if the node can be assigned to a forum.
*/
-function _forum_node_check_node_type($node, $vocabulary) {
- // We are going to return if $node->type is not one of the node
- // types assigned to the forum vocabulary. If forum_nav_vocabulary
- // is undefined or the vocabulary does not exist, it clearly cannot
- // be assigned to $node->type, so return to avoid E_ALL warnings.
- if (empty($vocabulary)) {
- return FALSE;
- }
+function _forum_node_check_node_type($node) {
+ // Fetch information about the forum field.
+ $field = field_info_instance('taxonomy_forums', $node->type);
- // Operate only on node types assigned for the forum vocabulary.
- if (!in_array($node->type, $vocabulary->nodes)) {
- return FALSE;
- }
-
- return TRUE;
+ return is_array($field);
}
/**
@@ -194,24 +166,15 @@ function _forum_node_check_node_type($no
function forum_node_view($node, $build_mode) {
$vid = variable_get('forum_nav_vocabulary', 0);
$vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
- if ((bool)menu_get_object() && taxonomy_node_get_terms_by_vocabulary($node, $vid) && $tree = taxonomy_get_tree($vid)) {
- // Get the forum terms from the (cached) tree
- foreach ($tree as $term) {
- $forum_terms[] = $term->tid;
- }
- foreach ($node->taxonomy as $term_id => $term) {
- if (in_array($term_id, $forum_terms)) {
- $node->tid = $term_id;
- }
- }
+ if (_forum_node_check_node_type($node)) {
+ if ((bool)menu_get_object()) {
// Breadcrumb navigation
$breadcrumb[] = l(t('Home'), NULL);
$breadcrumb[] = l($vocabulary->name, 'forum');
- if ($parents = taxonomy_get_parents_all($node->tid)) {
+ if ($parents = taxonomy_get_parents_all($node->forum_tid)) {
$parents = array_reverse($parents);
- foreach ($parents as $p) {
- $breadcrumb[] = l($p->name, 'forum/' . $p->tid);
+ foreach ($parents as $parent) {
+ $breadcrumb[] = l($parent->name, 'forum/' . $parent->tid);
}
}
drupal_set_breadcrumb($breadcrumb);
@@ -224,15 +187,10 @@ function forum_node_view($node, $build_m
* Implement hook_node_prepare().
*/
function forum_node_prepare($node) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
+ if (_forum_node_check_node_type($node)) {
if (empty($node->nid)) {
// New topic
- $node->taxonomy[arg(3)] = (object) array(
- 'vid' => $vid,
- 'tid' => arg(3),
- );
+ $node->taxonomy_forums[0]['value'] = arg(3);
}
}
}
@@ -243,22 +201,20 @@ function forum_node_prepare($node) {
* Check in particular that only a "leaf" term in the associated taxonomy.
*/
function forum_node_validate($node, $form) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
+ if (_forum_node_check_node_type($node)) {
+ $langcode = $form['taxonomy_forums']['#language'];
// vocabulary is selected, not a "container" term.
- if ($node->taxonomy) {
+ if (!empty($node->taxonomy_forums[$langcode])) {
// Extract the node's proper topic ID.
- $vocabulary = $vid;
$containers = variable_get('forum_containers', array());
- foreach ($node->taxonomy as $term) {
- $used = db_query_range('SELECT 1 FROM {taxonomy_term_data} WHERE tid = :tid AND vid = :vid', 0, 1, array(
- ':tid' => $term,
- ':vid' => $vocabulary,
+ foreach ($node->taxonomy_forums[$langcode] as $tid) {
+ $term = taxonomy_term_load($tid['value']);
+ $used = db_query_range('SELECT 1 FROM {taxonomy_term_data} WHERE tid = :tid AND vid = :vid',0 , 1, array(
+ ':tid' => $term->tid,
+ ':vid' => $term->vid,
))->fetchField();
- if ($used && in_array($term, $containers)) {
- $term = taxonomy_term_load($term);
- form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => $term->name)));
+ if ($used && in_array($term->tid, $containers)) {
+ form_set_error('taxonomy_forums', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => $term->name)));
}
}
}
@@ -271,26 +227,16 @@ function forum_node_validate($node, $for
* Assign forum taxonomy when adding a topic from within a forum.
*/
function forum_node_presave($node) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
+ if (_forum_node_check_node_type($node)) {
// Make sure all fields are set properly:
$node->icon = !empty($node->icon) ? $node->icon : '';
-
- if ($node->taxonomy && $tree = taxonomy_get_tree($vid)) {
- // Get the forum terms from the (cached) tree if we have a taxonomy.
- foreach ($tree as $term) {
- $forum_terms[] = $term->tid;
- }
- foreach ($node->taxonomy as $term_id) {
- if (in_array($term_id, $forum_terms)) {
- $node->tid = $term_id;
- }
- }
+ $langcode = array_shift(array_keys($node->taxonomy_forums));
+ if (!empty($node->taxonomy_forums[$langcode])) {
+ $node->forum_tid = $node->taxonomy_forums[$langcode][0]['value'];
$old_tid = db_query_range("SELECT f.tid FROM {forum} f INNER JOIN {node} n ON f.vid = n.vid WHERE n.nid = :nid ORDER BY f.vid DESC", 0, 1, array(':nid' => $node->nid))->fetchField();
- if ($old_tid && isset($node->tid) && ($node->tid != $old_tid) && !empty($node->shadow)) {
+ if ($old_tid && isset($node->forum_tid) && ($node->forum_tid != $old_tid) && !empty($node->shadow)) {
// A shadow copy needs to be created. Retain new term and add old term.
- $node->taxonomy[] = $old_tid;
+ $node->taxonomy_forums[$langcode][] = array('value' => $old_tid);
}
}
}
@@ -300,13 +246,11 @@ function forum_node_presave($node) {
* Implement hook_node_update().
*/
function forum_node_update($node) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
+ if (_forum_node_check_node_type($node)) {
if (empty($node->revision) && db_query('SELECT tid FROM {forum} WHERE nid=:nid', array(':nid' => $node->nid))->fetchField()) {
- if (!empty($node->tid)) {
+ if (!empty($node->forum_tid)) {
db_update('forum')
- ->fields(array('tid' => $node->tid))
+ ->fields(array('tid' => $node->forum_tid))
->condition('vid', $node->vid)
->execute();
}
@@ -318,16 +262,31 @@ function forum_node_update($node) {
}
}
else {
- if (!empty($node->tid)) {
+ if (!empty($node->forum_tid)) {
db_insert('forum')
->fields(array(
- 'tid' => $node->tid,
+ 'tid' => $node->forum_tid,
'vid' => $node->vid,
'nid' => $node->nid,
))
->execute();
}
}
+ // If the node has a shadow forum topic, update the record for this
+ // revision.
+ if ($node->shadow) {
+ db_delete('forum')
+ ->condition('nid', $node->nid)
+ ->condition('vid', $node->vid)
+ ->execute();
+ db_insert('forum')
+ ->fields(array(
+ 'nid' => $node->nid,
+ 'vid' => $node->vid,
+ 'tid' => $node->forum_tid,
+ ))
+ ->execute();
+ }
}
}
@@ -335,13 +294,11 @@ function forum_node_update($node) {
* Implement hook_node_insert().
*/
function forum_node_insert($node) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
- if (!empty($node->tid)) {
+ if (_forum_node_check_node_type($node)) {
+ if (!empty($node->forum_tid)) {
$nid = db_insert('forum')
->fields(array(
- 'tid' => $node->tid,
+ 'tid' => $node->forum_tid,
'vid' => $node->vid,
'nid' => $node->nid,
))
@@ -354,34 +311,32 @@ function forum_node_insert($node) {
* Implement hook_node_delete().
*/
function forum_node_delete($node) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (_forum_node_check_node_type($node, $vocabulary)) {
+ if (_forum_node_check_node_type($node)) {
db_delete('forum')
->condition('nid', $node->nid)
->execute();
+ db_delete('forum_index')
+ ->condition('nid', $node->nid)
+ ->execute();
}
}
/**
* Implement hook_node_load().
*/
-function forum_node_load($nodes, $types) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- // If no forum vocabulary is set up, return.
- if ($vid == '') {
- return;
- }
- $vocabulary = taxonomy_vocabulary_load($vid);
-
+function forum_node_load($nodes) {
$node_vids = array();
foreach ($nodes as $node) {
- if (isset($vocabulary->nodes[$node->type])) {
+ if (_forum_node_check_node_type($node)) {
$node_vids[] = $node->vid;
}
}
if (!empty($node_vids)) {
- $result = db_query('SELECT nid, tid FROM {forum} WHERE vid IN(:node_vids)', array(':node_vids' => $node_vids));
+ $query = db_select('forum', 'f');
+ $query
+ ->fields('f', array('nid', 'tid'))
+ ->condition('f.vid', $node_vids);
+ $result = $query->execute();
foreach ($result as $record) {
$nodes[$record->nid]->forum_tid = $record->tid;
}
@@ -418,26 +373,111 @@ function forum_permission() {
/**
* Implement hook_taxonomy().
*/
-function forum_taxonomy($op, $type, $term = NULL) {
- if ($op == 'delete' && $term['vid'] == variable_get('forum_nav_vocabulary', 0)) {
- switch ($type) {
- case 'term':
- $result = db_query('SELECT f.nid FROM {forum} f WHERE f.tid = :tid', array(':tid' => $term['tid']));
- foreach ($result as $node) {
- // node_delete will also remove any association with non-forum vocabularies.
- node_delete($node->nid);
- }
+function forum_taxonomy_term_delete($tid) {
+ // For containers, remove the tid from the forum_containers variable.
+ $containers = variable_get('forum_containers', array());
+ $key = array_search($tid, $containers);
+ if ($key !== FALSE) {
+ unset($containers[$key]);
+ }
+ variable_set('forum_containers', $containers);
+}
+
+/**
+ * Implement hook_comment_publish().
+ *
+ * This actually handles the insert and update of published nodes since
+ * comment_save() calls hook_comment_publish() for all published comments.
+ */
+function forum_comment_publish($comment) {
+ _forum_update_forum_index($comment->nid);
+}
+
+/**
+ * Implement forum_comment_update().
+ *
+ * Comment module doesn't call hook_comment_unpublish() when saving individual
+ * comments so we need to check for those here.
+ */
+function forum_comment_update($comment) {
+ // comment_save() calls hook_comment_publish() for all published comments
+ // so we to handle all other values here.
+ if (!$comment->status) {
+ _forum_update_forum_index($comment->nid);
+ }
+}
+
+/**
+ * Implement forum_comment_unpublish() {
+ */
+function forum_comment_unpublish($comment) {
+ _forum_update_forum_index($comment->nid);
+}
+
+/**
+ * Implement forum_comment_delete().
+ */
+function forum_comment_delete($comment) {
+ _forum_update_forum_index($comment->nid);
+}
+
+/**
+ * Implement hook_field_attach_pre_insert().
+ */
+function forum_field_attach_pre_insert($obj_type, $object, $skip_fields) {
+ if ($obj_type == 'node' && $object->status && _forum_node_check_node_type($object)) {
+ $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp'));
+ foreach ($object->taxonomy_forums as $language) {
+ foreach ($language as $delta) {
+ $query->values(array(
+ 'nid' => $object->nid,
+ 'title' => $object->title,
+ 'tid' => $delta['value'],
+ 'sticky' => $object->sticky,
+ 'created' => $object->created,
+ 'comment_count' => 0,
+ 'last_comment_timestamp' => $object->created,
+ ));
+ }
+ }
+ $query->execute();
+ }
+}
+
+/**
+ * Implement hook_field_attach_pre_update().
+ */
+function forum_field_attach_pre_update($obj_type, $object, $skip_fields) {
+ $first_call = &drupal_static(__FUNCTION__, array());
- // For containers, remove the tid from the forum_containers variable.
- $containers = variable_get('forum_containers', array());
- $key = array_search($term['tid'], $containers);
- if ($key !== FALSE) {
- unset($containers[$key]);
+ if ($obj_type == 'node' && $object->status && _forum_node_check_node_type($object)) {
+ // We don't maintain data for old revisions, so clear all previous values
+ // from the table. Since this hook runs once per field, per object, make
+ // sure we only wipe values once.
+ if (!isset($first_call[$object->nid])) {
+ $first_call[$object->nid] = FALSE;
+ db_delete('forum_index')->condition('nid', $object->nid)->execute();
+ }
+ // Only save data to the table if the node is published.
+ if ($object->status) {
+ $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp'));
+ foreach ($object->taxonomy_forums as $language) {
+ foreach ($language as $delta) {
+ $query->values(array(
+ 'nid' => $object->nid,
+ 'title' => $object->title,
+ 'tid' => $delta['value'],
+ 'sticky' => $object->sticky,
+ 'created' => $object->created,
+ 'comment_count' => 0,
+ 'last_comment_timestamp' => $object->created,
+ ));
}
- variable_set('forum_containers', $containers);
- break;
- case 'vocabulary':
- variable_del('forum_nav_vocabulary');
+ }
+ $query->execute();
+ // The logic for determining last_comment_count is fairly complex, so
+ // call _forum_update_forum_index() too.
+ _forum_update_forum_index($object->nid);
}
}
}
@@ -454,13 +494,8 @@ function forum_form_alter(&$form, $form_
'#markup' => t('This is the designated forum vocabulary. Some of the normal vocabulary options have been removed.'),
'#weight' => -1,
);
- $form['content_types']['nodes']['#required'] = TRUE;
$form['hierarchy'] = array('#type' => 'value', '#value' => 1);
- $form['settings']['required'] = array('#type' => 'value', '#value' => FALSE);
- $form['settings']['relations'] = array('#type' => 'value', '#value' => FALSE);
- $form['settings']['tags'] = array('#type' => 'value', '#value' => FALSE);
- $form['settings']['multiple'] = array('#type' => 'value', '#value' => FALSE);
- unset($form['delete']);
+ $form['delete']['#access'] = FALSE;
}
// Hide multiple parents select from forum terms.
elseif ($form_id == 'taxonomy_form_term') {
@@ -468,10 +503,10 @@ function forum_form_alter(&$form, $form_
}
}
if ($form_id == 'forum_node_form') {
+ $langcode = $form['taxonomy_forums']['#language'];
// Make the vocabulary required for 'real' forum-nodes.
- $vid = variable_get('forum_nav_vocabulary', 0);
- $form['taxonomy'][$vid]['#required'] = TRUE;
- $form['taxonomy'][$vid]['#options'][''] = t('- Please choose -');
+ $form['taxonomy_forums'][$langcode]['#required'] = TRUE;
+ $form['taxonomy_forums'][$langcode]['#multiple'] = FALSE;
}
}
@@ -512,28 +547,21 @@ function forum_block_save($delta = '', $
* most recently added forum topics.
*/
function forum_block_view($delta = '') {
- $query = db_select('node', 'n');
- $query->join('forum', 'f', 'f.vid = n.vid');
- $query->join('taxonomy_term_data', 'td', 'td.tid = f.tid');
- $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
- $query
- ->fields('n', array('nid', 'title'))
- ->fields('ncs', array('comment_count', 'last_comment_timestamp'))
- ->condition('n.status', 1)
- ->condition('td.vid', variable_get('forum_nav_vocabulary', 0))
+ $query = db_select('forum_index', 'f')
+ ->fields('f')
->addTag('node_access');
switch ($delta) {
case 'active':
$title = t('Active forum topics');
$query
- ->orderBy('ncs.last_comment_timestamp', 'DESC')
+ ->orderBy('f.last_comment_timestamp', 'DESC')
->range(0, variable_get('forum_block_num_active', '5'));
break;
case 'new':
$title = t('New forum topics');
$query
- ->orderBy('n.nid', 'DESC')
+ ->orderBy('f.created', 'DESC')
->range(0, variable_get('forum_block_num_new', '5'));
break;
}
@@ -581,11 +609,11 @@ function forum_form($node, $form_state)
$form['title'] = array('#type' => 'textfield', '#title' => check_plain($type->title_label), '#default_value' => !empty($node->title) ? $node->title : '', '#required' => TRUE, '#weight' => -5);
if (!empty($node->nid)) {
- $vid = variable_get('forum_nav_vocabulary', 0);
- $forum_terms = taxonomy_node_get_terms_by_vocabulary($node, $vid);
- // if editing, give option to leave shadows
+ $forum_terms = $node->taxonomy_forums;
+ // If editing, give option to leave shadows
$shadow = (count($forum_terms) > 1);
$form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
+ $form['forum_tid'] = array('#type' => 'value', '#value' => $node->forum_tid);
}
$form['#submit'][] = 'forum_submit';
@@ -667,7 +695,7 @@ function forum_get_forums($tid = 0) {
$last_post = new stdClass();
if (!empty($topic->last_comment_timestamp)) {
- $last_post->timestamp = $topic->last_comment_timestamp;
+ $last_post->created = $topic->last_comment_timestamp;
$last_post->name = $topic->last_comment_name;
$last_post->uid = $topic->last_comment_uid;
}
@@ -702,9 +730,9 @@ function forum_get_topics($tid, $sortby,
$forum_topic_list_header = array(
NULL,
- array('data' => t('Topic'), 'field' => 'n.title'),
- array('data' => t('Replies'), 'field' => 'ncs.comment_count'),
- array('data' => t('Last reply'), 'field' => 'ncs.last_comment_timestamp'),
+ array('data' => t('Topic'), 'field' => 'f.title'),
+ array('data' => t('Replies'), 'field' => 'f.comment_count'),
+ array('data' => t('Last reply'), 'field' => 'f.last_comment_timestamp'),
);
$order = _forum_get_topic_order($sortby);
@@ -714,48 +742,45 @@ function forum_get_topics($tid, $sortby,
}
}
- $query = db_select('node_comment_statistics', 'ncs')->extend('PagerDefault')->extend('TableSort');
- $query->join('node', 'n', 'n.nid = ncs.nid');
- $query->join('users', 'cu', 'ncs.last_comment_uid = cu.uid');
- $query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $tid));
- $query->join('users', 'u', 'n.uid = u.uid');
- $query->addExpression('IF(ncs.last_comment_uid != 0, cu.name, ncs.last_comment_name)', 'last_comment_name');
- $query->addField('n', 'created', 'timestamp');
- $query->addField('n', 'comment', 'comment_mode');
- $query->addField('ncs', 'comment_count', 'num_comments');
- $query->addField('f', 'tid', 'forum_tid');
+ $query = db_select('forum_index', 'f')->extend('PagerDefault')->extend('TableSort');
+ $query->fields('f');
$query
+ ->condition('f.tid', $tid)
->addTag('node_access')
- ->fields('n', array('nid', 'title', 'type', 'sticky'))
- ->fields('f', array('tid'))
- ->fields('u', array('name', 'uid'))
- ->fields('ncs', array('last_comment_timestamp', 'last_comment_uid'))
- ->condition('n.status', 1)
- ->orderBy('n.sticky', 'DESC')
+ ->orderBy('f.sticky', 'DESC')
->orderByHeader($forum_topic_list_header)
- ->orderBy('n.created', 'DESC')
+ ->orderBy('f.last_comment_timestamp', 'DESC')
->limit($forum_per_page);
- $count_query = db_select('node', 'n');
- $count_query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $tid));
+ $count_query = db_select('forum_index', 'f');
+ $count_query->condition('f.tid', $tid);
$count_query->addExpression('COUNT(*)');
- $count_query
- ->condition('n.status', 1)
- ->addTag('node_access');
+ $count_query->addTag('node_access');
$query->setCountQuery($count_query);
$result = $query->execute();
+ $nids = array();
+ foreach ($result as $record) {
+ $nids[] = $record->nid;
+ }
+ if ($nids) {
+ $result = db_query("SELECT n.title, n.nid, n.sticky, n.created, n.uid, n.comment AS comment_mode, ncs.*, f.tid AS forum_tid, u.name, IF (ncs.last_comment_uid != 0, u2.name, ncs.last_comment_name) AS last_comment_name FROM {node} n INNER JOIN {node_comment_statistics} ncs ON n.nid = ncs.nid INNER JOIN {forum} f ON n.vid = f.vid INNER JOIN {users} u ON n.uid = u.uid INNER JOIN {users} u2 ON ncs.last_comment_uid = u2.uid WHERE n.nid IN (:nids)", array(':nids' => $nids));
+ }
+ else {
+ $result = array();
+ }
+
$topics = array();
foreach ($result as $topic) {
if ($user->uid) {
// folder is new if topic is new or there are new comments since last visit
- if ($topic->tid != $tid) {
+ if ($topic->forum_tid != $tid) {
$topic->new = 0;
}
else {
$history = _forum_user_last_visit($topic->nid);
$topic->new_replies = comment_num_new($topic->nid, $history);
- $topic->new = $topic->new_replies || ($topic->timestamp > $history);
+ $topic->new = $topic->new_replies || ($topic->last_comment_timestamp > $history);
}
}
else {
@@ -764,9 +789,9 @@ function forum_get_topics($tid, $sortby,
$topic->new = 0;
}
- if ($topic->num_comments > 0) {
+ if ($topic->comment_count > 0) {
$last_reply = new stdClass();
- $last_reply->timestamp = $topic->last_comment_timestamp;
+ $last_reply->created = $topic->last_comment_timestamp;
$last_reply->name = $topic->last_comment_name;
$last_reply->uid = $topic->last_comment_uid;
$topic->last_reply = $last_reply;
@@ -820,8 +845,9 @@ function template_preprocess_forums(&$va
// Format the "post new content" links listing.
$forum_types = array();
- // Loop through all node types for forum vocabulary.
- foreach ($vocabulary->nodes as $type) {
+ // Loop through all bundles for forum taxonomy vocabulary field.
+ $field = field_info_field('taxonomy_' . $vocabulary->machine_name);
+ foreach ($field['bundles'] as $type) {
// Check if the current user has the 'create' permission for this node type.
if (node_access('create', $type)) {
// Fetch the "General" name of the content type;
@@ -951,14 +977,14 @@ function template_preprocess_forum_topic
if (!empty($variables['topics'])) {
$row = 0;
foreach ($variables['topics'] as $id => $topic) {
- $variables['topics'][$id]->icon = theme('forum_icon', $topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky);
+ $variables['topics'][$id]->icon = theme('forum_icon', $topic->new, $topic->comment_count, $topic->comment_mode, $topic->sticky);
$variables['topics'][$id]->zebra = $row % 2 == 0 ? 'odd' : 'even';
$row++;
// We keep the actual tid in forum table, if it's different from the
// current tid then it means the topic appears in two forums, one of
// them is a shadow copy.
- if ($topic->forum_tid != $variables['tid']) {
+ if ($variables['tid'] != $topic->forum_tid) {
$variables['topics'][$id]->moved = TRUE;
$variables['topics'][$id]->title = check_plain($topic->title);
$variables['topics'][$id]->message = l(t('This topic has been moved'), "forum/$topic->forum_tid");
@@ -968,6 +994,7 @@ function template_preprocess_forum_topic
$variables['topics'][$id]->title = l($topic->title, "node/$topic->nid");
$variables['topics'][$id]->message = '';
}
+ $topic->uid = $topic->last_comment_uid ? $topic->last_comment_uid : $topic->uid;
$variables['topics'][$id]->created = theme('forum_submitted', $topic);
$variables['topics'][$id]->last_reply = theme('forum_submitted', isset($topic->last_reply) ? $topic->last_reply : NULL);
@@ -1031,7 +1058,7 @@ function template_preprocess_forum_icon(
*/
function template_preprocess_forum_submitted(&$variables) {
$variables['author'] = isset($variables['topic']->uid) ? theme('username', $variables['topic']) : '';
- $variables['time'] = isset($variables['topic']->timestamp) ? format_interval(REQUEST_TIME - $variables['topic']->timestamp) : '';
+ $variables['time'] = isset($variables['topic']->created) ? format_interval(REQUEST_TIME - $variables['topic']->created) : '';
}
function _forum_user_last_visit($nid) {
@@ -1063,3 +1090,42 @@ function _forum_get_topic_order($sortby)
break;
}
}
+
+/**
+ * Updates the taxonomy index for a given node.
+ *
+ * @param $nid
+ * The ID of the node to update.
+ */
+function _forum_update_forum_index($nid) {
+ $count = db_query('SELECT COUNT(cid) FROM {comment} WHERE nid = :nid AND status = :status', array(
+ ':nid' => $nid,
+ ':status' => COMMENT_PUBLISHED,
+ ))->fetchField();
+
+ if ($count > 0) {
+ // Comments exist.
+ $last_reply = db_query_range('SELECT cid, name, timestamp, uid FROM {comment} WHERE nid = :nid AND status = :status ORDER BY cid DESC', array(
+ ':nid' => $nid,
+ ':status' => COMMENT_PUBLISHED,
+ ), 0, 1)->fetchObject();
+ db_update('forum_index')
+ ->fields( array(
+ 'comment_count' => $count,
+ 'last_comment_timestamp' => $last_reply->timestamp,
+ ))
+ ->condition('nid', $nid)
+ ->execute();
+ }
+ else {
+ // Comments do not exist.
+ $node = db_query('SELECT uid, created FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
+ db_update('forum_index')
+ ->fields( array(
+ 'comment_count' => 0,
+ 'last_comment_timestamp' => $node->created,
+ ))
+ ->condition('nid', $nid)
+ ->execute();
+ }
+}
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.32
diff -u -p -r1.32 forum.test
--- modules/forum/forum.test 28 Sep 2009 22:14:30 -0000 1.32
+++ modules/forum/forum.test 8 Oct 2009 07:29:02 -0000
@@ -131,8 +131,7 @@ class ForumTestCase extends DrupalWebTes
$edit = array(
'name' => $title,
'description' => $description,
- 'machine_name' => drupal_strtolower($this->randomName()),
- 'help' => '',
+ 'machine_name' => drupal_strtolower(drupal_substr($this->randomName(), 3, 9)),
);
// Edit the vocabulary.
@@ -251,7 +250,7 @@ class ForumTestCase extends DrupalWebTes
$edit = array(
'title' => $title,
"body[$langcode][0][value]" => $body,
- 'taxonomy[1]' => $tid
+ "taxonomy_forums[$langcode][value]" => $tid,
);
// TODO The taxonomy select value is set by drupal code when the tid is part
@@ -341,7 +340,7 @@ class ForumTestCase extends DrupalWebTes
$langcode = FIELD_LANGUAGE_NONE;
$edit["body[$langcode][0][value]"] = $this->randomName(256);
// Assume the topic is initially associated with $forum.
- $edit['taxonomy[1]'] = $this->root_forum['tid'];
+ $edit["taxonomy_forums[$langcode][value]"] = $this->root_forum['tid'];
$edit['shadow'] = TRUE;
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Forum topic %title has been updated.', array('%title' => $edit['title'])), t('Forum node was edited'));
Index: modules/node/node.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v
retrieving revision 1.84
diff -u -p -r1.84 node.pages.inc
--- modules/node/node.pages.inc 3 Oct 2009 17:45:26 -0000 1.84
+++ modules/node/node.pages.inc 8 Oct 2009 07:29:03 -0000
@@ -85,7 +85,7 @@ function node_object_prepare($node) {
// If this is a new node, fill in the default values.
if (!isset($node->nid)) {
foreach (array('status', 'promote', 'sticky') as $key) {
- $node->$key = in_array($key, $node_options);
+ $node->$key = (int) in_array($key, $node_options);
}
global $user;
$node->uid = $user->uid;
@@ -543,9 +543,6 @@ function node_revision_revert_confirm_su
$node_revision = $form['#node_revision'];
$node_revision->revision = 1;
$node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
- if (module_exists('taxonomy')) {
- $node_revision->taxonomy = array_keys($node_revision->taxonomy);
- }
node_save($node_revision);
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.80
diff -u -p -r1.80 common.test
--- modules/simpletest/tests/common.test 5 Oct 2009 14:56:43 -0000 1.80
+++ modules/simpletest/tests/common.test 8 Oct 2009 07:29:03 -0000
@@ -1355,14 +1355,15 @@ class DrupalDataApiTest extends DrupalWe
$this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when a record updated with drupal_write_record() for table with single-field primary key.'));
// Insert an object record for a table with a multi-field primary key.
- $vocabulary_node_type = new stdClass();
- $vocabulary_node_type->vid = $vocabulary->vid;
- $vocabulary_node_type->type = 'page';
- $insert_result = drupal_write_record('taxonomy_vocabulary_node_type', $vocabulary_node_type);
+ $node_access = new stdClass();
+ $node_access->nid = mt_rand();
+ $node_access->gid = mt_rand();
+ $node_access->realm = $this->randomName();
+ $insert_result = drupal_write_record('node_access', $node_access);
$this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when a record is inserted with drupal_write_record() for a table with a multi-field primary key.'));
// Update the record.
- $update_result = drupal_write_record('taxonomy_vocabulary_node_type', $vocabulary_node_type, array('vid', 'type'));
+ $update_result = drupal_write_record('node_access', $node_access, array('nid', 'gid', 'realm'));
$this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when a record is updated with drupal_write_record() for a table with a multi-field primary key.'));
}
Index: modules/taxonomy/taxonomy.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v
retrieving revision 1.70
diff -u -p -r1.70 taxonomy.admin.inc
--- modules/taxonomy/taxonomy.admin.inc 21 Sep 2009 06:44:14 -0000 1.70
+++ modules/taxonomy/taxonomy.admin.inc 8 Oct 2009 07:29:04 -0000
@@ -17,14 +17,8 @@ function taxonomy_overview_vocabularies(
$vocabularies = taxonomy_get_vocabularies();
$form['#tree'] = TRUE;
foreach ($vocabularies as $vocabulary) {
- $types = array();
- foreach ($vocabulary->nodes as $type) {
- $node_type = node_type_get_name($type);
- $types[] = $node_type ? check_plain($node_type) : check_plain($type);
- }
$form[$vocabulary->vid]['#vocabulary'] = $vocabulary;
$form[$vocabulary->vid]['name'] = array('#markup' => check_plain($vocabulary->name));
- $form[$vocabulary->vid]['types'] = array('#markup' => implode(', ', $types));
$form[$vocabulary->vid]['weight'] = array('#type' => 'weight', '#delta' => 10, '#default_value' => $vocabulary->weight);
$form[$vocabulary->vid]['edit'] = array('#markup' => l(t('edit vocabulary'), "admin/structure/taxonomy/$vocabulary->vid"));
$form[$vocabulary->vid]['list'] = array('#markup' => l(t('list terms'), "admin/structure/taxonomy/$vocabulary->vid/list"));
@@ -71,7 +65,6 @@ function theme_taxonomy_overview_vocabul
$row = array();
$row[] = drupal_render($vocabulary['name']);
- $row[] = drupal_render($vocabulary['types']);
if (isset($vocabulary['weight'])) {
$vocabulary['weight']['#attributes']['class'] = array('vocabulary-weight');
$row[] = drupal_render($vocabulary['weight']);
@@ -87,7 +80,7 @@ function theme_taxonomy_overview_vocabul
$rows[] = array(array('data' => t('No vocabularies available. Add vocabulary.', array('@link' => url('admin/structure/taxonomy/add'))), 'colspan' => '5'));
}
- $header = array(t('Vocabulary name'), t('Content types'));
+ $header = array(t('Vocabulary name'));
if (isset($form['submit'])) {
$header[] = t('Weight');
drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight');
@@ -110,12 +103,7 @@ function taxonomy_form_vocabulary($form,
'name' => '',
'machine_name' => '',
'description' => '',
- 'help' => '',
- 'nodes' => array(),
'hierarchy' => 0,
- 'tags' => 0,
- 'multiple' => 0,
- 'required' => 0,
'weight' => 0,
);
$form['#vocabulary'] = (object) $edit;
@@ -155,47 +143,11 @@ function taxonomy_form_vocabulary($form,
'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings),
),
);
- $form['help'] = array(
- '#type' => 'textfield',
- '#title' => t('Help text'),
- '#maxlength' => 255,
- '#default_value' => $edit['help'],
- '#description' => t('Instructions to present to the user when selecting terms, e.g., "Enter a comma separated list of words".'),
- );
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#default_value' => $edit['description'],
);
- $form['nodes'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Apply to content types'),
- '#default_value' => $edit['nodes'],
- '#options' => array_map('check_plain', node_type_get_names()),
- );
- $form['settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Settings'),
- '#collapsible' => TRUE,
- );
- $form['settings']['tags'] = array(
- '#type' => 'checkbox',
- '#title' => t('Tags'),
- '#default_value' => $edit['tags'],
- '#description' => t('Terms are created by users when submitting posts by typing a comma separated list.'),
- );
- $form['settings']['multiple'] = array(
- '#type' => 'checkbox',
- '#title' => t('Multiple select'),
- '#default_value' => $edit['multiple'],
- '#description' => t('Allows posts to have more than one term from this vocabulary (always true for tags).'),
- );
- $form['settings']['required'] = array(
- '#type' => 'checkbox',
- '#title' => t('Required'),
- '#default_value' => $edit['required'],
- '#description' => t('At least one term in this vocabulary must be selected when submitting a post.'),
- );
// Set the hierarchy to "multiple parents" by default. This simplifies the
// vocabulary form and standardizes the term form.
$form['hierarchy'] = array(
@@ -225,6 +177,11 @@ function taxonomy_form_vocabulary_valida
if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['machine_name'])) {
form_set_error('machine_name', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
}
+ // Restrict machine names to 21 characters to avoid exceeding the limit
+ // for field names.
+ if (drupal_strlen($machine_name) > 21) {
+ form_set_error('machine_name', t('The machine-readable name must not exceed 21 characters.'));
+ }
// Do not allow duplicate machine names.
$vocabularies = taxonomy_get_vocabularies();
@@ -246,8 +203,6 @@ function taxonomy_form_vocabulary_submit
$form_state['confirm_delete'] = TRUE;
return;
}
- // Fix up the nodes array to remove unchecked nodes.
- $form_state['values']['nodes'] = array_filter($form_state['values']['nodes']);
$vocabulary = (object) $form_state['values'];
if ($vocabulary->machine_name != $old_vocabulary->machine_name) {
field_attach_rename_bundle($old_vocabulary->machine_name, $vocabulary->machine_name);
@@ -306,106 +261,71 @@ function taxonomy_overview_terms($form,
// An array of the terms to be displayed on this page.
$current_page = array();
- // Case for free tagging.
- if ($vocabulary->tags) {
- // We are not calling taxonomy_get_tree because that might fail with a big
- // number of tags in the freetagging vocabulary.
- $query = db_select('taxonomy_term_data', 't')->extend('PagerDefault');
- $query->join('taxonomy_term_hierarchy', 'h', 't.tid = h.tid');
- $query->addTag('term_access');
- $query->condition('t.vid', $vocabulary->vid);
-
- // Store count in total entries and use this as count query.
- $count_query = db_select('taxonomy_term_data', 't');
- $count_query->join('taxonomy_term_hierarchy', 'h', 't.tid = h.tid');
- $count_query->addTag('term_access');
- $count_query->condition('t.vid', $vocabulary->vid);
- $count_query->addExpression('COUNT(t.tid)');
- $total_entries = $count_query->execute();
- $query->setCountQuery($count_query);
-
- $result = $query
- ->fields('t')
- ->fields('h', array('parent'))
- ->orderBy('weight')
- ->orderBy('name')
- ->limit($page_increment)
- ->execute();
-
- foreach ($result as $term) {
- $key = 'tid:' . $term->tid . ':0';
- $current_page[$key] = $term;
- $page_entries++;
+ $term_deltas = array();
+ $tree = taxonomy_get_tree($vocabulary->vid);
+ $term = current($tree);
+ do {
+ // In case this tree is completely empty.
+ if (empty($term)) {
+ break;
}
- }
- // Case for restricted vocabulary.
- else {
- $term_deltas = array();
- $tree = taxonomy_get_tree($vocabulary->vid);
- $term = current($tree);
- do {
- // In case this tree is completely empty.
- if (empty($term)) {
- break;
- }
- // Count entries before the current page.
- if ($page && ($page * $page_increment) > $before_entries && !isset($back_peddle)) {
- $before_entries++;
- continue;
- }
- // Count entries after the current page.
- elseif ($page_entries > $page_increment && isset($complete_tree)) {
- $after_entries++;
- continue;
- }
-
- // Do not let a term start the page that is not at the root.
- if (isset($term->depth) && ($term->depth > 0) && !isset($back_peddle)) {
- $back_peddle = 0;
- while ($pterm = prev($tree)) {
- $before_entries--;
- $back_peddle++;
- if ($pterm->depth == 0) {
- prev($tree);
- continue 2; // Jump back to the start of the root level parent.
- }
- }
- }
- $back_peddle = isset($back_peddle) ? $back_peddle : 0;
-
- // Continue rendering the tree until we reach the a new root item.
- if ($page_entries >= $page_increment + $back_peddle + 1 && $term->depth == 0 && $root_entries > 1) {
- $complete_tree = TRUE;
- // This new item at the root level is the first item on the next page.
- $after_entries++;
- continue;
- }
- if ($page_entries >= $page_increment + $back_peddle) {
- $forward_peddle++;
- }
-
- // Finally, if we've gotten down this far, we're rendering a term on this page.
- $page_entries++;
- $term_deltas[$term->tid] = isset($term_deltas[$term->tid]) ? $term_deltas[$term->tid] + 1 : 0;
- $key = 'tid:' . $term->tid . ':' . $term_deltas[$term->tid];
-
- // Keep track of the first term displayed on this page.
- if ($page_entries == 1) {
- $form['#first_tid'] = $term->tid;
- }
- // Keep a variable to make sure at least 2 root elements are displayed.
- if ($term->parents[0] == 0) {
- $root_entries++;
- }
- $current_page[$key] = $term;
- } while ($term = next($tree));
-
- // Because we didn't use a pager query, set the necessary pager variables.
- $total_entries = $before_entries + $page_entries + $after_entries;
- $pager_total_items[0] = $total_entries;
- $pager_page_array[0] = $page;
- $pager_total[0] = ceil($total_entries / $page_increment);
- }
+ // Count entries before the current page.
+ if ($page && ($page * $page_increment) > $before_entries && !isset($back_peddle)) {
+ $before_entries++;
+ continue;
+ }
+ // Count entries after the current page.
+ elseif ($page_entries > $page_increment && isset($complete_tree)) {
+ $after_entries++;
+ continue;
+ }
+
+ // Do not let a term start the page that is not at the root.
+ if (isset($term->depth) && ($term->depth > 0) && !isset($back_peddle)) {
+ $back_peddle = 0;
+ while ($pterm = prev($tree)) {
+ $before_entries--;
+ $back_peddle++;
+ if ($pterm->depth == 0) {
+ prev($tree);
+ continue 2; // Jump back to the start of the root level parent.
+ }
+ }
+ }
+ $back_peddle = isset($back_peddle) ? $back_peddle : 0;
+
+ // Continue rendering the tree until we reach the a new root item.
+ if ($page_entries >= $page_increment + $back_peddle + 1 && $term->depth == 0 && $root_entries > 1) {
+ $complete_tree = TRUE;
+ // This new item at the root level is the first item on the next page.
+ $after_entries++;
+ continue;
+ }
+ if ($page_entries >= $page_increment + $back_peddle) {
+ $forward_peddle++;
+ }
+
+ // Finally, if we've gotten down this far, we're rendering a term on this page.
+ $page_entries++;
+ $term_deltas[$term->tid] = isset($term_deltas[$term->tid]) ? $term_deltas[$term->tid] + 1 : 0;
+ $key = 'tid:' . $term->tid . ':' . $term_deltas[$term->tid];
+
+ // Keep track of the first term displayed on this page.
+ if ($page_entries == 1) {
+ $form['#first_tid'] = $term->tid;
+ }
+ // Keep a variable to make sure at least 2 root elements are displayed.
+ if ($term->parents[0] == 0) {
+ $root_entries++;
+ }
+ $current_page[$key] = $term;
+ } while ($term = next($tree));
+
+ // Because we didn't use a pager query, set the necessary pager variables.
+ $total_entries = $before_entries + $page_entries + $after_entries;
+ $pager_total_items[0] = $total_entries;
+ $pager_page_array[0] = $page;
+ $pager_total[0] = ceil($total_entries / $page_increment);
// If this form was already submitted once, it's probably hit a validation
// error. Ensure the form is rebuilt in the same order as the user submitted.
@@ -433,7 +353,7 @@ function taxonomy_overview_terms($form,
}
$form[$key]['view'] = array('#markup' => l($term->name, "taxonomy/term/$term->tid"));
- if (!$vocabulary->tags && $vocabulary->hierarchy < 2 && count($tree) > 1) {
+ if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
$form['#parent_fields'] = TRUE;
$form[$key]['tid'] = array(
'#type' => 'hidden',
@@ -460,7 +380,7 @@ function taxonomy_overview_terms($form,
$form['#forward_peddle'] = $forward_peddle;
$form['#empty_text'] = t('No terms available. Add term.', array('@link' => url('admin/structure/taxonomy/' . $vocabulary->vid . '/list/add')));
- if (!$vocabulary->tags && $vocabulary->hierarchy < 2 && count($tree) > 1) {
+ if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
@@ -690,7 +610,6 @@ function taxonomy_form_term($form, &$for
$form['#term'] = $edit;
$form['#term']['parent'] = $parent;
$form['#vocabulary'] = $vocabulary;
- $form['#vocabulary']->nodes = drupal_map_assoc($vocabulary->nodes);
$form['#builder_function'] = 'taxonomy_form_term_submit_builder';
// Check for confirmation forms.
@@ -747,7 +666,7 @@ function taxonomy_form_term($form, &$for
}
$exclude[] = $edit['tid'];
- $form['advanced']['parent'] = _taxonomy_term_select(t('Parents'), $parent, $vocabulary->vid, t('Parent terms') . '.', 1, '<' . t('root') . '>', $exclude);
+ $form['advanced']['parent'] = _taxonomy_term_select(t('Parents'), $parent, $vocabulary->vid, t('Parent terms') . '.', '<' . t('root') . '>', $exclude);
}
$form['advanced']['synonyms'] = array(
'#type' => 'textarea',
@@ -814,7 +733,7 @@ function taxonomy_form_term_submit($form
return;
}
// Rebuild the form to confirm enabling multiple parents.
- elseif ($form_state['clicked_button']['#value'] == t('Save') && !$form['#vocabulary']->tags && count($form_state['values']['parent']) > 1 && $form['#vocabulary']->hierarchy < 2) {
+ elseif ($form_state['clicked_button']['#value'] == t('Save') && count($form_state['values']['parent']) > 1 && $form['#vocabulary']->hierarchy < 2) {
$form_state['rebuild'] = TRUE;
$form_state['confirm_parents'] = TRUE;
return;
@@ -834,26 +753,24 @@ function taxonomy_form_term_submit($form
break;
}
- if (!$form['#vocabulary']->tags) {
- $current_parent_count = count($form_state['values']['parent']);
- $previous_parent_count = count($form['#term']['parent']);
- // Root doesn't count if it's the only parent.
- if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) {
- $current_parent_count = 0;
- $form_state['values']['parent'] = array();
- }
-
- // If the number of parents has been reduced to one or none, do a check on the
- // parents of every term in the vocabulary value.
- if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
- taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
- }
- // If we've increased the number of parents and this is a single or flat
- // hierarchy, update the vocabulary immediately.
- elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
- $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
- taxonomy_vocabulary_save($form['#vocabulary']);
- }
+ $current_parent_count = count($form_state['values']['parent']);
+ $previous_parent_count = count($form['#term']['parent']);
+ // Root doesn't count if it's the only parent.
+ if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) {
+ $current_parent_count = 0;
+ $form_state['values']['parent'] = array();
+ }
+
+ // If the number of parents has been reduced to one or none, do a check on the
+ // parents of every term in the vocabulary value.
+ if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
+ taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
+ }
+ // If we've increased the number of parents and this is a single or flat
+ // hierarchy, update the vocabulary immediately.
+ elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
+ $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
+ taxonomy_vocabulary_save($form['#vocabulary']);
}
$form_state['tid'] = $term->tid;
Index: modules/taxonomy/taxonomy.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.install,v
retrieving revision 1.23
diff -u -p -r1.23 taxonomy.install
--- modules/taxonomy/taxonomy.install 29 Sep 2009 15:13:56 -0000 1.23
+++ modules/taxonomy/taxonomy.install 8 Oct 2009 07:29:04 -0000
@@ -93,42 +93,6 @@ function taxonomy_schema() {
'primary key' => array('tid', 'parent'),
);
- $schema['taxonomy_term_node'] = array(
- 'description' => 'Stores the relationship of terms to nodes.',
- 'fields' => array(
- 'nid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: The {node}.nid of the node.',
- ),
- 'vid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: The {node}.vid of the node.',
- ),
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: The {taxonomy_term_data}.tid of a term assigned to the node.',
- ),
- ),
- 'indexes' => array(
- 'vid' => array('vid'),
- 'nid' => array('nid'),
- ),
- 'foreign keys' => array(
- 'nid' => array('node' => 'nid'),
- 'vid' => array('node' => 'vid'),
- 'tid' => array('taxonomy_term_data' => 'tid'),
- ),
- 'primary key' => array('tid', 'vid'),
- );
$schema['taxonomy_term_synonym'] = array(
'description' => 'Stores term synonyms.',
'fields' => array(
@@ -191,13 +155,6 @@ function taxonomy_schema() {
'size' => 'big',
'description' => 'Description of the vocabulary.',
),
- 'help' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Help text to display for the vocabulary.',
- ),
'relations' => array(
'type' => 'int',
'unsigned' => TRUE,
@@ -214,30 +171,6 @@ function taxonomy_schema() {
'size' => 'tiny',
'description' => 'The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)',
),
- 'multiple' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'size' => 'tiny',
- 'description' => 'Whether or not multiple terms from this vocabulary may be assigned to a node. (0 = disabled, 1 = enabled)',
- ),
- 'required' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'size' => 'tiny',
- 'description' => 'Whether or not terms are required for nodes using this vocabulary. (0 = disabled, 1 = enabled)',
- ),
- 'tags' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'size' => 'tiny',
- 'description' => 'Whether or not free tagging is enabled for the vocabulary. (0 = disabled, 1 = enabled)',
- ),
'module' => array(
'type' => 'varchar',
'length' => 255,
@@ -250,7 +183,7 @@ function taxonomy_schema() {
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
- 'description' => 'The weight of the vocabulary in relation to other vocabularies.',
+ 'description' => 'The weight of this vocabulary in relation to other vocabularies.',
),
),
'primary key' => array('vid'),
@@ -259,30 +192,44 @@ function taxonomy_schema() {
),
);
- $schema['taxonomy_vocabulary_node_type'] = array(
- 'description' => 'Stores which node types vocabularies may be used with.',
+ $schema['taxonomy_index'] = array(
+ 'description' => 'Maintains denormalized information about node/term relationships.',
'fields' => array(
- 'vid' => array(
+ 'nid' => array(
+ 'description' => 'The {node}.nid this record tracks.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
- 'description' => 'Primary Key: the {taxonomy_vocabulary}.vid of the vocabulary.',
),
- 'type' => array(
- 'type' => 'varchar',
- 'length' => 32,
+ 'tid' => array(
+ 'description' => 'The term ID.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'sticky' => array(
+ 'description' => 'Boolean indicating whether the node is sticky.',
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'default' => 0,
+ 'size' => 'tiny',
+ ),
+ 'created' => array(
+ 'description' => 'The Unix timestamp when the node was created.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
'not null' => TRUE,
- 'default' => '',
- 'description' => 'The {node}.type of the node type for which the vocabulary may be used.',
+ 'default'=> 0,
),
),
- 'primary key' => array('type', 'vid'),
'indexes' => array(
- 'vid' => array('vid'),
+ 'term_node' => array('tid', 'sticky', 'created'),
),
'foreign keys' => array(
- 'vid' => array('taxonomy_vocabulary' => 'vid'),
+ 'node' => 'nid',
+ 'taxonomy_term_data' => 'tid',
),
);
@@ -322,3 +269,170 @@ function taxonomy_update_7002() {
function taxonomy_update_7003() {
db_drop_field('taxonomy_vocabulary', 'relations');
}
+
+/**
+ * Move taxonomy vocabulary associations for nodes to fields and field instances.
+ */
+function taxonomy_update_7004() {
+ $taxonomy_index = array(
+ 'description' => 'Maintains denormalized information about node/term relationships.',
+ 'fields' => array(
+ 'nid' => array(
+ 'description' => 'The {node}.nid this record tracks.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'tid' => array(
+ 'description' => 'The term ID.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'sticky' => array(
+ 'description' => 'Boolean indicating whether the node is sticky.',
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'default' => 0,
+ 'size' => 'tiny',
+ ),
+ 'created' => array(
+ 'description' => 'The Unix timestamp when the node was created.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default'=> 0,
+ ),
+ ),
+ 'indexes' => array(
+ 'term_node' => array('tid', 'sticky', 'created'),
+ ),
+ 'foreign keys' => array(
+ 'node' => 'nid',
+ 'taxonomy_term_data' => 'tid',
+ ),
+ );
+ db_create_table('taxonomy_index', $taxonomy_index);
+
+ // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
+ // we can no longer rely on $vocabulary->nodes from the API function.
+ $result = db_query('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid ORDER BY v.weight, v.name');
+ $vocabularies = array();
+ foreach ($result as $record) {
+ // If no node types are associated with a vocabulary, the LEFT JOIN will
+ // return a NULL value for type.
+ if (isset($record->type)) {
+ $node_types[$record->vid][$record->type] = $record->type;
+ unset($record->type);
+ $record->nodes = $node_types[$record->vid];
+ }
+ elseif (!isset($record->nodes)) {
+ $record->nodes = array();
+ }
+ $vocabularies[$record->vid] = $record;
+ }
+
+ foreach ($vocabularies as $vocabulary) {
+ $field_name = 'taxonomy_' . $vocabulary->machine_name;
+ $field = array(
+ 'field_name' => $field_name,
+ 'type' => 'taxonomy_term',
+ 'cardinality' => $vocabulary->multiple || $vocabulary->tags ? FIELD_CARDINALITY_UNLIMITED : 1,
+ 'settings' => array(
+ 'required' => $vocabulary->required ? TRUE : FALSE,
+ 'allowed_values' => array(
+ array(
+ 'vid' => $vocabulary->vid,
+ 'parent' => 0,
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ foreach ($vocabulary->nodes as $bundle) {
+ $instance = array(
+ 'label' => $vocabulary->name,
+ 'field_name' => $field_name,
+ 'bundle' => $bundle,
+ 'description' => $vocabulary->help,
+ 'widget' => array(
+ 'type' => $vocabulary->tags ? 'taxonomy_autocomplete' : 'select',
+ ),
+ );
+ field_create_instance($instance);
+ }
+ }
+ db_drop_table('taxonomy_vocabulary_node_type');
+ $fields = array('help', 'multiple', 'required', 'tags');
+ foreach ($fields as $field) {
+ db_drop_field('taxonomy_vocabulary', $field);
+ }
+}
+
+/**
+ * Migrate {taxonomy_term_node} table to field storage.
+ */
+function taxonomy_update_7005(&$sandbox) {
+ // Since we are upgrading from Drupal 6, we know that only
+ // field_sql_storage.module will be enabled.
+ $field = field_info_field($field['field_name']);
+ $data_table = _field_sql_storage_tablename($field);
+ $revision_table = _field_sql_storage_revision_tablename($field);
+ $etid = _field_sql_storage_etid('node');
+ $value_column = $field['field_name'] . '_value';
+ $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta', $value_column);
+
+ // This is a multi-pass update. On the first call we need to initialize some
+ // variables.
+ if (!isset($sandbox['total'])) {
+ $sandbox['last'] = 0;
+ $sandbox['count'] = 0;
+
+ $query = db_select('taxonomy_term_node', 't');
+ $sandbox['total'] = $query->countQuery()->execute()->fetchField();
+ $found = (bool) $sandbox['total'];
+ }
+ else {
+ // We do each pass in batches of 1000, this should result in a
+ // maximum of 2000 insert queries each operation.
+ $batch = 1000 + $sandbox['last'];
+
+ // Query and save data for the current revision.
+ $result = db_query_range('SELECT td.tid, tn.nid, td.weight, tn.vid, n2.type, n2.created, n2.sticky FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid INNER JOIN {node} n2 ON tn.nid = n2.nid INNER JOIN {node} n ON tn.vid = n.vid AND td.vid = :vocabulary_id ORDER BY td.weight ASC', array(':vocabulary_id' => $vocabulary->vid), $sandbox['last'], $batch);
+ $deltas = array();
+ foreach ($result as $record) {
+ $found = TRUE;
+ $sandbox['count'] += 1;
+ // Start deltas from 0, and increment by one for each
+ // term attached to a node.
+ $deltas[$record->nid] = isset($deltas[$record->nid]) ? ++$deltas[$record->nid] : 0;
+ $values = array($etid, $record->nid, $record->vid, $record->type, $deltas[$record->nid], $record->tid);
+ db_insert($data_table)->fields($columns)->values($values)->execute();
+
+ // Update the {taxonomy_index} table.
+ db_insert('taxonomy_index')
+ ->fields(array('nid', 'tid', 'sticky', 'created',))
+ ->values(array($record->nid, $record->tid, $record->sticky, $record->created))
+ ->execute();
+ }
+
+ // Query and save data for all revisions.
+ $result = db_query('SELECT td.tid, tn.nid, td.weight, tn.vid, n.type FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid AND td.vid = :vocabulary_id INNER JOIN {node} n ON tn.nid = n.nid ORDER BY td.weight ASC', array(':vocabulary_id' => $vocabulary->vid), $sandbox['last'][$batch]);
+ $deltas = array();
+ foreach ($result as $record) {
+ $found = TRUE;
+ $sandbox['count'] += 1;
+ // Start deltas at 0, and increment by one for each term attached to a revision.
+ $deltas[$record->vid] = isset($deltas[$record->vid]) ? ++$deltas[$record->vid] : 0;
+ $values = array($etid, $record->nid, $record->vid, $record->type, $deltas[$record->vid], $record->tid);
+ db_insert($revision_table)->fields($columns)->values($values)->execute();
+ }
+ $sandbox['last'] = $batch;
+ }
+ if (!$found) {
+ db_drop_table('taxonomy_term_node');
+ }
+}
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.513
diff -u -p -r1.513 taxonomy.module
--- modules/taxonomy/taxonomy.module 26 Sep 2009 15:57:39 -0000 1.513
+++ modules/taxonomy/taxonomy.module 8 Oct 2009 07:29:05 -0000
@@ -63,6 +63,54 @@ function taxonomy_entity_info() {
}
/**
+ * Return nodes attached to a term across all field instances.
+ *
+ * This function requires taxonomy module to be maintaining its own tables,
+ * and will return an empty array if it is not. If using other field storage
+ * methods alternatives methods for listing terms will need to be used.
+ *
+ * @param $term
+ * The term object.
+ * @param $pager
+ * Boolean to indicate whether a pager should be used.
+ * @order
+ * An array of fields and directions.
+ *
+ * @return
+ * An array of nids matching the query.
+ */
+function taxonomy_select_nodes($term, $pager = TRUE, $order = array('t.sticky' => 'DESC', 't.created' => 'DESC')) {
+ if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
+ return array();
+ }
+ $query = db_select('taxonomy_index', 't');
+ $query->addTag('node_access');
+ if ($pager) {
+ $count_query = clone $query;
+ $count_query->addExpression('COUNT(t.nid)');
+
+ $query = $query
+ ->extend('PagerDefault')
+ ->limit(variable_get('default_nodes_main', 10));
+ $query->setCountQuery($count_query);
+ }
+ else {
+ $query->range(0, variable_get('feed_default_items', 10));
+ }
+ $query->condition('tid', $term->tid );
+ $query->addField('t', 'nid');
+ $query->addField('t', 'tid');
+ foreach ($order as $field => $direction) {
+ $query->orderBy($field, $direction);
+ // ORDER BY fields need to be loaded too, assume they are in the form
+ // table_alias.name
+ list($table_alias, $name) = explode('.', $field);
+ $query->addField($table_alias, $name);
+ }
+ return $query->execute()->fetchCol();
+}
+
+/**
* Implement hook_field_build_modes();
*
* @TODO: build mode for display as a field (when attached to nodes etc.).
@@ -98,66 +146,6 @@ function taxonomy_theme() {
}
/**
- * Implement hook_node_view().
- */
-function taxonomy_node_view($node, $build_mode) {
- if (empty($node->taxonomy)) {
- return;
- }
-
- if ($build_mode == 'rss') {
- // Provide category information for RSS feeds.
- foreach ($node->taxonomy as $term) {
- $node->rss_elements[] = array(
- 'key' => 'category',
- 'value' => $term->name,
- 'attributes' => array('domain' => url(taxonomy_term_path($term), array('absolute' => TRUE))),
- );
- }
- }
- else {
- $links = array();
-
- // If previewing, the terms must be converted to objects first.
- if (!empty($node->in_preview)) {
- $node->taxonomy = taxonomy_preview_terms($node);
- }
-
- foreach ($node->taxonomy as $term) {
- // During preview the free tagging terms are in an array unlike the
- // other terms which are objects. So we have to check if a $term
- // is an object or not.
- if (is_object($term)) {
- $links['taxonomy_term_' . $term->tid] = array(
- 'title' => $term->name,
- 'href' => taxonomy_term_path($term),
- 'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description))
- );
- }
- // Previewing free tagging terms; we don't link them because the
- // term-page might not exist yet.
- else {
- foreach ($term as $free_typed) {
- $typed_terms = drupal_explode_tags($free_typed);
- foreach ($typed_terms as $typed_term) {
- $links['taxonomy_preview_term_' . $typed_term] = array(
- 'title' => $typed_term,
- );
- }
- }
- }
- }
-
- $node->content['links']['terms'] = array(
- '#theme' => 'links',
- '#links' => $links,
- '#attributes' => array('class' => array('links', 'inline')),
- '#sorted' => TRUE,
- );
- }
-}
-
-/**
* For vocabularies not maintained by taxonomy.module, give the maintaining
* module a chance to provide a path for terms in that vocabulary.
*
@@ -244,14 +232,6 @@ function taxonomy_menu() {
'type' => MENU_CALLBACK,
'file' => 'taxonomy.pages.inc',
);
- // TODO: remove with taxonomy_term_node_*
- $items['taxonomy/autocomplete/legacy'] = array(
- 'title' => 'Autocomplete taxonomy',
- 'page callback' => 'taxonomy_autocomplete_legacy',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- 'file' => 'taxonomy.pages.inc',
- );
$items['admin/structure/taxonomy/%taxonomy_vocabulary'] = array(
'title' => 'Vocabulary', // this is replaced by callback
@@ -303,9 +283,6 @@ function taxonomy_admin_vocabulary_title
* Save a vocabulary given a vocabulary object.
*/
function taxonomy_vocabulary_save($vocabulary) {
- if (empty($vocabulary->nodes)) {
- $vocabulary->nodes = array();
- }
if (!empty($vocabulary->name)) {
// Prevent leading and trailing spaces in vocabulary names.
@@ -318,38 +295,12 @@ function taxonomy_vocabulary_save($vocab
if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');
- db_delete('taxonomy_vocabulary_node_type')
- ->condition('vid', $vocabulary->vid)
- ->execute();
-
- if (!empty($vocabulary->nodes)) {
- $query = db_insert('taxonomy_vocabulary_node_type')
- ->fields(array('vid', 'type'));
- foreach ($vocabulary->nodes as $type => $selected) {
- $query->values(array(
- 'vid' => $vocabulary->vid,
- 'type' => $type,
- ));
- }
- $query->execute();
- }
module_invoke_all('taxonomy_vocabulary_update', $vocabulary);
}
elseif (empty($vocabulary->vid)) {
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary);
-
- if (!empty($vocabulary->nodes)) {
- $query = db_insert('taxonomy_vocabulary_node_type')
- ->fields(array('vid', 'type'));
- foreach ($vocabulary->nodes as $type => $selected) {
- $query->values(array(
- 'vid' => $vocabulary->vid,
- 'type' => $type,
- ));
- }
- $query->execute();
- }
field_attach_create_bundle($vocabulary->machine_name);
+ taxonomy_vocabulary_create_field($vocabulary);
module_invoke_all('taxonomy_vocabulary_insert', $vocabulary);
}
@@ -373,9 +324,6 @@ function taxonomy_vocabulary_delete($vid
db_delete('taxonomy_vocabulary')
->condition('vid', $vid)
->execute();
- db_delete('taxonomy_vocabulary_node_type')
- ->condition('vid', $vid)
- ->execute();
$result = db_query('SELECT tid FROM {taxonomy_term_data} WHERE vid = :vid', array(':vid' => $vid))->fetchCol();
foreach ($result as $tid) {
taxonomy_term_delete($tid);
@@ -432,6 +380,31 @@ function taxonomy_check_vocabulary_hiera
}
/**
+ * Create a default field when a vocabulary is created.
+ *
+ * @param $vocabulary
+ * A taxonomy vocabulary object.
+ */
+function taxonomy_vocabulary_create_field($vocabulary) {
+ $field = array(
+ 'field_name' => 'taxonomy_' . $vocabulary->machine_name,
+ 'type' => 'taxonomy_term',
+ // Set cardinality to unlimited so that select
+ // and autocomplete widgets behave as normal.
+ 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+ 'settings' => array(
+ 'allowed_values' => array(
+ array(
+ 'vid' => $vocabulary->vid,
+ 'parent' => 0,
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+}
+
+/**
* Save a term object to the database.
*
* @param $term
@@ -470,6 +443,9 @@ function taxonomy_term_save($term) {
if (!isset($term->parent) || empty($term->parent)) {
$term->parent = array(0);
}
+ if (!is_array($term->parent)) {
+ $term->parent = array($term->parent);
+ }
$query = db_insert('taxonomy_term_hierarchy')
->fields(array('tid', 'parent'));
if (is_array($term->parent)) {
@@ -490,12 +466,6 @@ function taxonomy_term_save($term) {
}
}
}
- else {
- $query->values(array(
- 'tid' => $term->tid,
- 'parent' => $parent
- ));
- }
$query->execute();
db_delete('taxonomy_term_synonym')
@@ -556,9 +526,6 @@ function taxonomy_term_delete($tid) {
db_delete('taxonomy_term_synonym')
->condition('tid', $tid)
->execute();
- db_delete('taxonomy_term_node')
- ->condition('tid', $tid)
- ->execute();
field_attach_delete('taxonomy_term', $term);
_taxonomy_clean_field_cache($term);
@@ -606,26 +573,18 @@ function taxonomy_form($vid, $value = 0,
$vocabulary = taxonomy_vocabulary_load($vid);
$help = ($help) ? $help : filter_xss_admin($vocabulary->help);
- if (!$vocabulary->multiple) {
- $blank = ($vocabulary->required) ? t('- Please choose -') : t('- None selected -');
- }
- else {
- $blank = ($vocabulary->required) ? 0 : t('- None -');
- }
+ $blank = t('- Please choose -');
- return _taxonomy_term_select(check_plain($vocabulary->name), $value, $vid, $help, intval($vocabulary->multiple), $blank);
+ return _taxonomy_term_select(check_plain($vocabulary->name), $value, $vid, $help, $blank);
}
/**
* Generate a set of options for selecting a term from all vocabularies.
*/
-function taxonomy_form_all($free_tags = 0) {
+function taxonomy_form_all() {
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $vid => $vocabulary) {
- if ($vocabulary->tags && !$free_tags) {
- continue;
- }
$tree = taxonomy_get_tree($vid);
if ($tree && (count($tree) > 0)) {
$options[$vocabulary->name] = array();
@@ -643,9 +602,8 @@ function taxonomy_form_all($free_tags =
* @param $type
* If set, return only those vocabularies associated with this node type.
*/
-function taxonomy_get_vocabularies($type = NULL) {
- $conditions = !empty($type) ? array('type' => $type) : NULL;
- return taxonomy_vocabulary_load_multiple(FALSE, $conditions);
+function taxonomy_get_vocabularies() {
+ return taxonomy_vocabulary_load_multiple(FALSE, array());
}
/**
@@ -660,330 +618,6 @@ function taxonomy_vocabulary_get_names()
}
/**
- * Implement hook_form_alter().
- * Generate a form for selecting terms to associate with a node.
- * We check for taxonomy_override_selector before loading the full
- * vocabulary, so contrib modules can intercept before hook_form_alter
- * and provide scalable alternatives.
- */
-function taxonomy_form_alter(&$form, $form_state, $form_id) {
- if (!variable_get('taxonomy_override_selector', FALSE) && !empty($form['#node_edit_form'])) {
- $node = $form['#node'];
-
- if (!isset($node->taxonomy)) {
- $terms = empty($node->nid) ? array() : taxonomy_node_get_terms($node);
- }
- else {
- // After preview the terms must be converted to objects.
- if (isset($form_state['node_preview'])) {
- $node->taxonomy = taxonomy_preview_terms($node);
- }
- $terms = $node->taxonomy;
- }
- $query = db_select('taxonomy_vocabulary', 'v');
- $query->join('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid');
- $query->addTag('term_access');
-
- $result = $query
- ->fields('v')
- ->condition('n.type', $node->type)
- ->orderBy('v.weight')
- ->orderBy('v.name')
- ->execute();
-
- foreach ($result as $vocabulary) {
- if ($vocabulary->tags) {
- if (isset($form_state['node_preview'])) {
- // Typed string can be changed by the user before preview,
- // so we just insert the tags directly as provided in the form.
- $typed_string = $node->taxonomy['tags'][$vocabulary->vid];
- }
- else {
- $typed_string = taxonomy_implode_tags($terms, $vocabulary->vid) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
- }
- if ($vocabulary->help) {
- $help = filter_xss_admin($vocabulary->help);
- }
- else {
- $help = t('A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc."');
- }
- $form['taxonomy']['tags'][$vocabulary->vid] = array('#type' => 'textfield',
- '#title' => $vocabulary->name,
- '#description' => $help,
- '#required' => $vocabulary->required,
- '#default_value' => $typed_string,
- '#autocomplete_path' => 'taxonomy/autocomplete/legacy/' . $vocabulary->vid,
- '#weight' => $vocabulary->weight,
- '#maxlength' => 1024,
- );
- }
- else {
- // Extract terms belonging to the vocabulary in question.
- $default_terms = array();
- foreach ($terms as $term) {
- // Free tagging has no default terms and also no vid after preview.
- if (isset($term->vid) && $term->vid == $vocabulary->vid) {
- $default_terms[$term->tid] = $term;
- }
- }
- $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), filter_xss_admin($vocabulary->help));
- $form['taxonomy'][$vocabulary->vid]['#weight'] = $vocabulary->weight;
- $form['taxonomy'][$vocabulary->vid]['#required'] = $vocabulary->required;
- }
- }
- if (!empty($form['taxonomy']) && is_array($form['taxonomy'])) {
- if (count($form['taxonomy']) > 1) {
- // Add fieldset only if form has more than 1 element.
- $form['taxonomy'] += array(
- '#type' => 'fieldset',
- '#title' => t('Vocabularies'),
- '#collapsible' => TRUE,
- '#collapsed' => FALSE,
- );
- }
- $form['taxonomy']['#weight'] = -3;
- $form['taxonomy']['#tree'] = TRUE;
- }
- }
-}
-
-/**
- * Helper function to convert terms after a preview.
- *
- * After preview the tags are an array instead of proper objects. This function
- * converts them back to objects with the exception of 'free tagging' terms,
- * because new tags can be added by the user before preview and those do not
- * yet exist in the database. We therefore save those tags as a string so
- * we can fill the form again after the preview.
- */
-function taxonomy_preview_terms($node) {
- $taxonomy = array();
- if (isset($node->taxonomy)) {
- foreach ($node->taxonomy as $key => $term) {
- unset($node->taxonomy[$key]);
- // A 'Multiple select' and a 'Free tagging' field returns an array.
- if (is_array($term)) {
- foreach ($term as $tid) {
- if ($key == 'tags') {
- // Free tagging; the values will be saved for later as strings
- // instead of objects to fill the form again.
- $taxonomy['tags'] = $term;
- }
- else {
- $taxonomy[$tid] = taxonomy_term_load($tid);
- }
- }
- }
- // A 'Single select' field returns the term id.
- elseif ($term) {
- $taxonomy[$term] = taxonomy_term_load($term);
- }
- }
- }
- return $taxonomy;
-}
-
-/**
- * Find all terms associated with the given node, within one vocabulary.
- */
-function taxonomy_node_get_terms_by_vocabulary($node, $vid, $key = 'tid') {
- $query = db_select('taxonomy_term_data', 't');
- $query->join('taxonomy_term_node', 'r', 'r.tid = t.tid');
- $query->addTag('term_access');
-
- $result = $query
- ->fields('t')
- ->condition('t.vid', $vid)
- ->condition('r.vid', $node->vid)
- ->orderBy('weight')
- ->execute();
-
- $terms = array();
- foreach ($result as $term) {
- $terms[$term->$key] = $term;
- }
- return $terms;
-}
-
-/**
- * Find all term IDs associated with a set of nodes.
- *
- * @param $nodes
- * An array of node objects.
- *
- * @return
- * An array of term and node IDs ordered by vocabulary and term weight.
- */
-function taxonomy_get_tids_from_nodes($nodes) {
- $node_vids = array();
- foreach ($nodes as $node) {
- $node_vids[] = $node->vid;
- }
- $query = db_select('taxonomy_term_node', 'r');
- $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');
- $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
- $query->addTag('term_access');
-
- return $query
- ->fields('r', array('tid', 'nid', 'vid'))
- ->condition('r.vid', $node_vids, 'IN')
- ->orderBy('v.weight')
- ->orderBy('t.weight')
- ->orderBy('t.name')
- ->execute()
- ->fetchAll();
-}
-
-/**
- * Find all terms associated with the given node, ordered by vocabulary and term weight.
- */
-function taxonomy_node_get_terms($node, $key = 'tid') {
- $terms = &drupal_static(__FUNCTION__);
-
- if (!isset($terms[$node->vid][$key])) {
- $query = db_select('taxonomy_term_node', 'r');
- $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');
- $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
- $query->addTag('term_access');
-
- $result = $query
- ->fields('r', array('tid', 'nid', 'vid'))
- ->condition('r.vid', $node->vid)
- ->orderBy('v.weight')
- ->orderBy('t.weight')
- ->orderBy('t.name')
- ->execute();
- $terms[$node->vid][$key] = array();
- foreach ($result as $term) {
- $terms[$node->vid][$key][$term->$key] = $term;
- }
- }
- return $terms[$node->vid][$key];
-}
-
-/**
- * Save term associations for a given node.
- */
-function taxonomy_node_save($node, $terms) {
- taxonomy_node_revision_delete($node);
-
- // Free tagging vocabularies do not send their tids in the form,
- // so we'll detect them here and process them independently.
- if (isset($terms['tags'])) {
- $typed_input = $terms['tags'];
- unset($terms['tags']);
-
- foreach ($typed_input as $vid => $vid_value) {
- $vocabulary = taxonomy_vocabulary_load($vid);
- $typed_terms = drupal_explode_tags($vid_value);
-
- $inserted = array();
- foreach ($typed_terms as $typed_term) {
- // See if the term exists in the chosen vocabulary
- // and return the tid; otherwise, add a new record.
- $possibilities = taxonomy_get_term_by_name($typed_term);
- $typed_term_tid = NULL; // tid match, if any.
- foreach ($possibilities as $possibility) {
- if ($possibility->vid == $vid) {
- $typed_term_tid = $possibility->tid;
- }
- }
-
- if (!$typed_term_tid) {
- $edit = array(
- 'vid' => $vid,
- 'name' => $typed_term,
- 'vocabulary_machine_name' => $vocabulary->machine_name,
- );
- $term = (object)$edit;
- $status = taxonomy_term_save($term);
- $typed_term_tid = $term->tid;
- }
-
- // Defend against duplicate, differently cased tags
- if (!isset($inserted[$typed_term_tid])) {
- db_insert('taxonomy_term_node')
- ->fields(array(
- 'nid' => $node->nid,
- 'vid' => $node->vid,
- 'tid' => $typed_term_tid
- ))
- ->execute();
- $inserted[$typed_term_tid] = TRUE;
- }
- }
- }
- }
-
- if (is_array($terms) && !empty($terms)) {
- $query = db_insert('taxonomy_term_node')
- ->fields(array('nid', 'vid', 'tid'));
-
- foreach ($terms as $term) {
- if (is_array($term)) {
- foreach ($term as $tid) {
- if ($tid) {
- $query->values(array(
- 'nid' => $node->nid,
- 'vid' => $node->vid,
- 'tid' => $tid,
- ));
- }
- }
- }
- elseif (is_object($term)) {
- $query->values(array(
- 'nid' => $node->nid,
- 'vid' => $node->vid,
- 'tid' => $term->tid,
- ));
- }
- elseif ($term) {
- $query->values(array(
- 'nid' => $node->nid,
- 'vid' => $node->vid,
- 'tid' => $term,
- ));
- }
- }
- $query->execute();
- }
-}
-
-/**
- * Implement hook_node_type_insert().
- */
-function taxonomy_node_type_insert($info) {
- drupal_static_reset('taxonomy_term_count_nodes');
-}
-
-/**
- * Implement hook_node_type_update().
- */
-function taxonomy_node_type_update($info) {
- if (!empty($info->old_type) && $info->type != $info->old_type) {
- db_update('taxonomy_vocabulary_node_type')
- ->fields(array(
- 'type' => $info->type,
- ))
- ->condition('type', $info->old_type)
- ->execute();
- }
- drupal_static_reset('taxonomy_term_count_nodes');
-}
-
-/**
- * Implement hook_node_type_delete().
- */
-function taxonomy_node_type_delete($info) {
- db_delete('taxonomy_vocabulary_node_type')
- ->condition('type', $info->type)
- ->execute();
-
- drupal_static_reset('taxonomy_term_count_nodes');
-}
-
-/**
* Find all parents of a given term ID.
*/
function taxonomy_get_parents($tid, $key = 'tid') {
@@ -1150,51 +784,6 @@ function taxonomy_get_synonym_root($syno
}
/**
- * Count the number of published nodes classified by a term.
- *
- * @param $tid
- * The term ID
- * @param $type
- * (Optional) The $node->type. If given, taxonomy_term_count_nodes only counts
- * nodes of $type that are classified with the term $tid.
- *
- * @return
- * An integer representing a number of nodes.
- * Results are statically cached.
- */
-function taxonomy_term_count_nodes($tid, $type = NULL) {
- $count = &drupal_static(__FUNCTION__, array());
- // Reset the taxonomy tree when first called (or if reset).
- if (empty($count)) {
- drupal_static_reset('taxonomy_get_tree');
- }
- // If $type is NULL, change it to 0 to allow it to be used as an array key
- // for the static cache.
- $type = empty($type) ? 0 : $type;
-
- if (!isset($count[$type][$tid])) {
- $term = taxonomy_term_load($tid);
- $tree = taxonomy_get_tree($term->vid, $tid, NULL);
- $tids = array($tid);
- foreach ($tree as $descendent) {
- $tids[] = $descendent->tid;
- }
-
- $query = db_select('taxonomy_term_node', 't');
- $query->addExpression('COUNT(DISTINCT(n.nid))', 'nid_count');
- $query->join('node', 'n', 't.vid = n.vid');
- $query->condition('t.tid', $tids, 'IN');
- $query->condition('n.status', 1);
- if (!is_numeric($type)) {
- $query->condition('n.type', $type);
- }
- $query->addTag('term_access');
- $count[$type][$tid] = $query->execute()->fetchField();
- }
- return $count[$type][$tid];
-}
-
-/**
* Try to map a string to an existing term, as for glossary use.
*
* Provides a case-insensitive and trimmed mapping, to maximize the
@@ -1211,17 +800,6 @@ function taxonomy_get_term_by_name($name
}
/**
- * Return array of tids and join operator.
- *
- * This is a wrapper function for taxonomy_terms_parse_string which is called
- * by the menu system when loading a path with taxonomy terms.
- */
-function taxonomy_terms_load($str_tids) {
- $terms = taxonomy_terms_parse_string($str_tids);
- return $terms;
-}
-
-/**
* Controller class for taxonomy terms.
*
* This extends the DrupalDefaultEntityController class. Only alteration is
@@ -1251,10 +829,6 @@ class TaxonomyTermController extends Dru
// Add the machine name field from the {taxonomy_vocabulary} table.
$this->query->innerJoin('taxonomy_vocabulary', 'v', 'base.vid = v.vid');
$this->query->addField('v', 'machine_name', 'vocabulary_machine_name');
-
- if (!empty($this->type)) {
- $this->query->innerJoin('taxonomy_vocabulary_node_type', 'n', 'base.vid = n.vid AND n.type = :type', array(':type' => $this->type));
- }
}
protected function cacheGet($ids) {
@@ -1278,24 +852,8 @@ class TaxonomyTermController extends Dru
* special handling for taxonomy vocabulary objects.
*/
class TaxonomyVocabularyController extends DrupalDefaultEntityController {
- protected $type;
- public function load($ids = array(), $conditions = array()) {
- if (isset($conditions['type'])) {
- $this->type = $conditions['type'];
- unset($conditions['type']);
- }
- return parent::load($ids, $conditions);
- }
-
protected function buildQuery() {
parent::buildQuery();
- if (!empty($this->type)) {
- $this->query->innerJoin('taxonomy_vocabulary_node_type', 'n', 'base.vid = n.vid AND n.type = :type', array(':type' => $this->type));
- }
- else {
- $this->query->leftJoin('taxonomy_vocabulary_node_type', 'n', 'base.vid = n.vid');
- }
- $this->query->addField('n', 'type');
$this->query->orderBy('base.weight');
$this->query->orderBy('base.name');
}
@@ -1304,14 +862,6 @@ class TaxonomyVocabularyController exten
foreach ($records as $record) {
// If no node types are associated with a vocabulary, the LEFT JOIN will
// return a NULL value for type.
- if (isset($record->type)) {
- $node_types[$record->vid][$record->type] = $record->type;
- unset($record->type);
- $record->nodes = $node_types[$record->vid];
- }
- elseif (!isset($record->nodes)) {
- $record->nodes = array();
- }
$queried_vocabularies[$record->vid] = $record;
}
$records = $queried_vocabularies;
@@ -1419,7 +969,7 @@ function taxonomy_term_load($tid) {
* @see taxonomy_form()
* @see taxonomy_form_term()
*/
-function _taxonomy_term_select($title, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
+function _taxonomy_term_select($title, $value, $vocabulary_id, $description, $blank, $exclude = array()) {
$tree = taxonomy_get_tree($vocabulary_id);
$options = array();
@@ -1441,8 +991,6 @@ function _taxonomy_term_select($title, $
'#default_value' => $value,
'#options' => $options,
'#description' => $description,
- '#multiple' => $multiple,
- '#size' => $multiple ? min(9, count($options)) : 0,
'#weight' => -15,
'#theme' => 'taxonomy_term_select',
);
@@ -1459,186 +1007,6 @@ function theme_taxonomy_term_select($ele
}
/**
- * Finds all nodes that match selected taxonomy conditions.
- *
- * @param $tids
- * An array of term IDs to match.
- * @param $operator
- * How to interpret multiple IDs in the array. Can be "or" or "and".
- * @param $depth
- * How many levels deep to traverse the taxonomy tree. Can be a non-negative
- * integer or "all".
- * @param $pager
- * Whether the nodes are to be used with a pager (the case on most Drupal
- * pages) or not (in an XML feed, for example).
- * @param $order
- * The order clause for the query that retrieve the nodes.
- * It is important to specifc the table alias (n).
- *
- * Example:
- * array('table_alias.field_name' = 'DESC');
- * @return
- * An array of node IDs.
- */
-function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = array('n.sticky' => 'DESC', 'n.created' => 'DESC')) {
- if (count($tids) <= 0) {
- return array();
- }
- // For each term ID, generate an array of descendant term IDs to the right depth.
- $descendant_tids = array();
- if ($depth === 'all') {
- $depth = NULL;
- }
- $terms = taxonomy_term_load_multiple($tids);
- foreach ($terms as $term) {
- $tree = taxonomy_get_tree($term->vid, $term->tid, $depth);
- $descendant_tids[] = array_merge(array($term->tid), array_map('_taxonomy_get_tid_from_term', $tree));
- }
-
- $query = db_select('node', 'n');
- $query->addTag('node_access');
- $query->condition('n.status', 1);
-
- if ($operator == 'or') {
- $args = call_user_func_array('array_merge', $descendant_tids);
- $query->join('taxonomy_term_node', 'tn', 'n.vid = tn.vid');
- $query->condition('tn.tid', $args, 'IN');
- }
- else {
- foreach ($descendant_tids as $tids) {
- $alias = $query->join('taxonomy_term_node', 'tn', 'n.vid = tn.vid');
- $query->condition($alias . '.tid', $tids, 'IN');
- }
- }
-
- if ($pager) {
- $count_query = clone $query;
- $count_query->addExpression('COUNT(DISTINCT n.nid)');
-
- $query = $query
- ->extend('PagerDefault')
- ->limit(variable_get('default_nodes_main', 10));
- $query->setCountQuery($count_query);
- }
- else {
- $query->range(0, variable_get('feed_default_items', 10));
- }
-
- $query->distinct(TRUE);
- $query->addField('n', 'nid');
- foreach ($order as $field => $direction) {
- $query->orderBy($field, $direction);
- // ORDER BY fields need to be loaded too, assume they are in the form table_alias.name
- list($table_alias, $name) = explode('.', $field);
- $query->addField($table_alias, $name);
- }
-
- return $query->execute()->fetchCol();
-}
-
-/**
- * Implement hook_node_load().
- */
-function taxonomy_node_load($nodes) {
- // Get an array of tid, vid associations ordered by vocabulary and term
- // weight.
- $tids = taxonomy_get_tids_from_nodes($nodes);
-
- // Extract the tids only from this array.
- $term_ids = array();
- foreach ($tids as $term) {
- $term_ids[$term->tid] = $term->tid;
- }
-
- // Load the full term objects for these tids.
- $terms = taxonomy_term_load_multiple($term_ids);
- foreach ($tids as $term) {
- $nodes[$term->nid]->taxonomy[$term->tid] = $terms[$term->tid];
- }
- foreach ($nodes as $node) {
- if (!isset($nodes[$node->nid]->taxonomy)) {
- $node->taxonomy = array();
- }
- }
-}
-
-/**
- * Implement hook_node_insert().
- */
-function taxonomy_node_insert($node) {
- if (!empty($node->taxonomy)) {
- taxonomy_node_save($node, $node->taxonomy);
- }
-}
-
-/**
- * Implement hook_node_update().
- */
-function taxonomy_node_update($node) {
- if (!empty($node->taxonomy)) {
- taxonomy_node_save($node, $node->taxonomy);
- }
-}
-
-/**
- * Implement hook_node_delete().
- *
- * Remove associations of a node to its terms.
- */
-function taxonomy_node_delete($node) {
- db_delete('taxonomy_term_node')
- ->condition('nid', $node->nid)
- ->execute();
- drupal_static_reset('taxonomy_term_count_nodes');
-}
-
-/**
- * Implement hook_node_revision_delete().
- *
- * Remove associations of a node to its terms.
- */
-function taxonomy_node_revision_delete($node) {
- db_delete('taxonomy_term_node')
- ->condition('vid', $node->vid)
- ->execute();
- drupal_static_reset('taxonomy_term_count_nodes');
-}
-
-/**
- * Implement hook_node_validate().
- *
- * Make sure incoming vids are free tagging enabled.
- */
-function taxonomy_node_validate($node, $form) {
- if (!empty($node->taxonomy)) {
- $terms = $node->taxonomy;
- if (!empty($terms['tags'])) {
- foreach ($terms['tags'] as $vid => $vid_value) {
- $vocabulary = taxonomy_vocabulary_load($vid);
- if (empty($vocabulary->tags)) {
- // see form_get_error $key = implode('][', $element['#parents']);
- // on why this is the key
- form_set_error("taxonomy][tags][$vid", t('The %name vocabulary can not be modified in this way.', array('%name' => $vocabulary->name)));
- }
- }
- }
- }
-}
-
-/**
- * Implement hook_node_update_index().
- */
-function taxonomy_node_update_index($node) {
- $output = array();
- foreach ($node->taxonomy as $term) {
- $output[] = $term->name;
- }
- if (count($output)) {
- return '(' . implode(', ', $output) . ')';
- }
-}
-
-/**
* Implement hook_help().
*/
function taxonomy_help($path, $arg) {
@@ -1658,9 +1026,6 @@ function taxonomy_help($path, $arg) {
return $output;
case 'admin/structure/taxonomy/%/list':
$vocabulary = taxonomy_vocabulary_load($arg[3]);
- if ($vocabulary->tags) {
- return '' . t('%capital_name is a free-tagging vocabulary. To change the name or description of a term, click the edit link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) . ' ';
- }
switch ($vocabulary->hierarchy) {
case 0:
return '' . t('%capital_name is a flat vocabulary. You may organize the terms in the %name vocabulary by using the handles on the left side of the table. To change the name or description of a term, click the edit link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . ' ';
@@ -1823,7 +1188,7 @@ function taxonomy_field_validate($obj_ty
* Implement hook_field_is_empty().
*/
function taxonomy_field_is_empty($item, $field) {
- if (empty($item['value']) && (string) $item['value'] !== '0') {
+ if (!is_array($item) || (empty($item['value']) && (string) $item['value'] !== '0')) {
return TRUE;
}
return FALSE;
@@ -2166,3 +1531,95 @@ function taxonomy_field_settings_form($f
return $form;
}
+
+/**
+ * @defgroup taxonomy indexing Taxonomy functions maintaining {taxonomy_index}.
+ *
+ * Taxonomy uses default field storage to store canonical relationships
+ * between terms and fieldable entities. However its most common use case
+ * requires listing all content associated with a term or group of terms
+ * sorted by creation date. To avoid slow queries due to joining across
+ * multiple node and field tables with various conditions and order by criteria,
+ * we maintain a denormalized table with all relationships between terms,
+ * published nodes and common sort criteria such as sticky and created.
+ * This is used as a lookup table by taxonomy_select_nodes(). When using other
+ * field storage engines or alternative methods of denormalizing this data
+ * you should set the variable 'taxonomy_maintain_index_table' to FALSE
+ * to avoid unnecessary writes in SQL.
+ * @{
+ */
+
+/**
+ * Implement hook_field_insert().
+ */
+function taxonomy_field_insert($obj_type, $object, $field, $instance, $langcode, &$items) {
+ // We maintain a denormalized table of term/node relationships, containing
+ // only data for current, published nodes.
+ if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $obj_type == 'node' && $object->status) {
+ $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created', ));
+ foreach ($items as $item) {
+ $query->values(array(
+ 'nid' => $object->nid,
+ 'tid' => $item['value'],
+ 'sticky' => $object->sticky,
+ 'created' => $object->created,
+ ));
+ }
+ $query->execute();
+ }
+}
+
+/**
+ * Implement hook_field_update().
+ */
+function taxonomy_field_update($obj_type, $object, $field, $instance, $langcode, &$items) {
+ if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $obj_type = 'node') {
+ $first_call = &drupal_static(__FUNCTION__, array());
+
+ // We don't maintain data for old revisions, so clear all previous values
+ // from the table. Since this hook runs once per field, per object, make
+ // sure we only wipe values once.
+ if (!isset($first_call[$object->nid])) {
+ $first_call[$object->nid] = FALSE;
+ db_delete('taxonomy_index')->condition('nid', $object->nid)->execute();
+ }
+ // Only save data to the table if the node is published.
+ if ($object->status) {
+ $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
+ foreach ($items as $item) {
+ $query->values(array(
+ 'nid' => $object->nid,
+ 'tid' => $item['value'],
+ 'sticky' => $object->sticky,
+ 'created' => $object->created,
+ ));
+ }
+ $query->execute();
+ }
+ }
+}
+
+/**
+ * Implement hook_node_delete().
+ */
+function taxonomy_node_delete($node) {
+ if (variable_get('taxonomy_maintain_index_table', TRUE)) {
+ // Clean up the {taxonomy_index} table when nodes are deleted.
+ db_delete('taxonomy_index')->condition('nid', $node->nid)->execute();
+ }
+}
+
+/**
+ * Implement hook_taxonomy_term_delete().
+ */
+function taxonomy_taxonomy_term_delete($term) {
+ if (variable_get('taxonomy_maintain_index_table', TRUE)) {
+ // Clean up the {taxonomy_index} table when terms are deleted.
+ db_delete('taxonomy_index')->condition('tid', $term->tid)->execute();
+ }
+}
+
+/**
+ * @} End of "defgroup taxonomy indexing"
+ */
+
Index: modules/taxonomy/taxonomy.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v
retrieving revision 1.36
diff -u -p -r1.36 taxonomy.pages.inc
--- modules/taxonomy/taxonomy.pages.inc 21 Sep 2009 07:56:08 -0000 1.36
+++ modules/taxonomy/taxonomy.pages.inc 8 Oct 2009 07:29:05 -0000
@@ -40,8 +40,7 @@ function taxonomy_term_page($term) {
'#suffix' => '',
);
}
-
- if ($nids = taxonomy_select_nodes(array($term->tid), NULL, TRUE)) {
+ if ($nids = taxonomy_select_nodes($term)) {
$nodes = node_load_multiple($nids);
$build += node_build_multiple($nodes);
$build['pager'] = array(
@@ -71,7 +70,7 @@ function taxonomy_term_feed($term) {
// Only display the description if we have a single term, to avoid clutter and confusion.
// HTML will be removed from feed description, so no need to filter here.
$channel['description'] = $term->description;
- $nids = taxonomy_select_nodes(array($term->tid, NULL, NULL, FALSE));
+ $nids = taxonomy_select_nodes(array($term->tid, FALSE));
node_feed($nids, $channel);
}
@@ -91,56 +90,6 @@ function taxonomy_term_edit($term) {
/**
* Helper function for autocompletion
*/
-function taxonomy_autocomplete_legacy($vid = 0, $tags_typed = '') {
- // The user enters a comma-separated list of tags. We only autocomplete the last tag.
- $tags_typed = drupal_explode_tags($tags_typed);
- $tag_last = drupal_strtolower(array_pop($tags_typed));
-
- $matches = array();
- if ($tag_last != '') {
- $query = db_select('taxonomy_term_data', 't');
- $query->addTag('term_access');
- $query->leftJoin('taxonomy_term_synonym', 'ts', 't.tid = ts.tid');
- // Don't select already entered terms.
- if (count($tags_typed)) {
- $query->condition('t.name', $tags_typed, 'NOT IN');
- }
- $tags_return = $query
- ->fields('t', array('tid', 'name'))
- ->condition('t.vid', $vid)
- // Select rows that either match by term or synonym name.
- ->condition(db_or()
- ->where("LOWER(t.name) LIKE :last_string", array(':last_string' => '%' . $tag_last . '%'))
- ->where("LOWER(ts.name) LIKE :last_string", array(':last_string' => '%' . $tag_last . '%'))
- )
- ->range(0, 10)
- ->execute()
- ->fetchAllKeyed();
-
- $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
-
- // We use two arrays to make sure synonym suggestions appear last.
- $term_matches = $synonym_matches = array();
- foreach ($tags_return as $tid => $name) {
- $n = $name;
- // Commas and quotes in terms are special cases, so encode 'em.
- if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
- $n = '"' . str_replace('"', '""', $name) . '"';
- }
- // Inform the user his query matched a synonym rather than a term.
- if (strpos(drupal_strtolower($name), $tag_last) === FALSE) {
- $name = t('Did you mean %suggestion', array('%suggestion' => $name));
- $synonym_matches[$prefix . $n] = filter_xss($name);
- }
- }
- }
-
- drupal_json_output(array_merge($term_matches, $synonym_matches));
-}
-
-/**
- * Helper function for autocompletion
- */
function taxonomy_autocomplete($field_name, $bundle, $tags_typed = '') {
$instance = field_info_instance($field_name, $bundle);
$field = field_info_field($field_name);
Index: modules/taxonomy/taxonomy.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.test,v
retrieving revision 1.47
diff -u -p -r1.47 taxonomy.test
--- modules/taxonomy/taxonomy.test 20 Sep 2009 17:40:42 -0000 1.47
+++ modules/taxonomy/taxonomy.test 8 Oct 2009 07:29:05 -0000
@@ -73,11 +73,6 @@ class TaxonomyVocabularyFunctionalTest e
$edit['name'] = $this->randomName();
$edit['description'] = $this->randomName();
$edit['machine_name'] = $machine_name;
- $edit['help'] = $this->randomName();
- $edit['nodes[article]'] = 'article';
- $edit['tags'] = 1;
- $edit['multiple'] = 1;
- $edit['required'] = 1;
$this->drupalPost(NULL, $edit, t('Save'));
$this->assertRaw(t('Created new vocabulary %name.', array('%name' => $edit['name'])), t('Vocabulary created successfully'));
@@ -154,7 +149,6 @@ class TaxonomyVocabularyFunctionalTest e
$edit = array(
'name' => $this->randomName(),
'machine_name' => drupal_strtolower($this->randomName()),
- 'nodes[article]' => 'article',
);
$this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save'));
$this->assertText(t('Created new vocabulary'), t('New vocabulary was created.'));
@@ -276,27 +270,23 @@ class TaxonomyVocabularyUnitTest extends
// Fetch all of the vocabularies using taxonomy_get_vocabularies().
// Confirm that the vocabularies are ordered by weight.
$vocabularies = taxonomy_get_vocabularies();
- $this->assertEqual(array_shift($vocabularies), $vocabulary1, t('Vocabulary was found in the vocabularies array.'));
- $this->assertEqual(array_shift($vocabularies), $vocabulary2, t('Vocabulary was found in the vocabularies array.'));
- $this->assertEqual(array_shift($vocabularies), $vocabulary3, t('Vocabulary was found in the vocabularies array.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary1->vid, t('Vocabulary was found in the vocabularies array.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary2->vid, t('Vocabulary was found in the vocabularies array.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary3->vid, t('Vocabulary was found in the vocabularies array.'));
// Fetch the vocabularies with taxonomy_vocabulary_load_multiple(), specifying IDs.
// Ensure they are returned in the same order as the original array.
$vocabularies = taxonomy_vocabulary_load_multiple(array($vocabulary3->vid, $vocabulary2->vid, $vocabulary1->vid));
- $this->assertEqual(array_shift($vocabularies), $vocabulary3, t('Vocabulary loaded successfully by ID.'));
- $this->assertEqual(array_shift($vocabularies), $vocabulary2, t('Vocabulary loaded successfully by ID.'));
- $this->assertEqual(array_shift($vocabularies), $vocabulary1, t('Vocabulary loaded successfully by ID.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary3->vid, t('Vocabulary loaded successfully by ID.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary2->vid, t('Vocabulary loaded successfully by ID.'));
+ $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary1->vid, t('Vocabulary loaded successfully by ID.'));
// Fetch vocabulary 1 by name.
- $this->assertTrue(current(taxonomy_vocabulary_load_multiple(array(), array('name' => $vocabulary1->name))) == $vocabulary1, t('Vocabulary loaded successfully by name.'));
+ $vocabulary = current(taxonomy_vocabulary_load_multiple(array(), array('name' => $vocabulary1->name)));
+ $this->assertTrue($vocabulary->vid == $vocabulary1->vid, t('Vocabulary loaded successfully by name.'));
// Fetch vocabulary 1 by name and ID.
- $this->assertTrue(current(taxonomy_vocabulary_load_multiple(array($vocabulary1->vid), array('name' => $vocabulary1->name))) == $vocabulary1, t('Vocabulary loaded successfully by name and ID.'));
-
- // Fetch vocabulary 1 with specified node type.
- entity_get_controller('taxonomy_vocabulary')->resetCache();
- $vocabulary_node_type = current(taxonomy_vocabulary_load_multiple(array($vocabulary1->vid), array('type' => 'article')));
- $this->assertEqual($vocabulary_node_type, $vocabulary1, t('Vocabulary with specified node type loaded successfully.'));
+ $this->assertTrue(current(taxonomy_vocabulary_load_multiple(array($vocabulary1->vid), array('name' => $vocabulary1->name)))->vid == $vocabulary1->vid, t('Vocabulary loaded successfully by name and ID.'));
}
}
@@ -312,65 +302,6 @@ class TaxonomyTermUnitTest extends Taxon
'group' => 'Taxonomy',
);
}
-
- /**
- * Tests for taxonomy_term_count_nodes().
- *
- * Attach nodes to a hierarchical vocabulary and check they are counted
- * correctly.
- */
- function testTaxonomyTermCountNodes() {
- // Create a vocabulary with three terms.
- $vocabulary = $this->createVocabulary();
- $term1 = $this->createTerm($vocabulary);
- $term2 = $this->createTerm($vocabulary);
- $term3 = $this->createTerm($vocabulary);
-
- // Attach term1 to a node.
- $node1 = $this->drupalCreateNode(array('type' => 'page'));
- $node1->taxonomy = array($term1->tid);
- node_save($node1);
- $this->assertEqual(taxonomy_term_count_nodes($term1->tid), 1, t('Term has one valid node association.'));
-
- // Attach term2 to a node.
- $node2 = $this->drupalCreateNode(array('type' => 'article'));
- $node2->taxonomy = array($term2->tid);
- node_save($node2);
- $this->assertEqual(taxonomy_term_count_nodes($term2->tid), 1, t('Term has one valid node association.'));
-
- // Confirm that term3 is not associated with any nodes.
- $this->assertEqual(taxonomy_term_count_nodes($term3->tid), 0, t('Term is not associated with any nodes'));
-
- // Set term3 as the parent of term1.
- $term1->parent = array($term3->tid);
- taxonomy_term_save($term1);
-
- // Confirm that the term hierarchy is altered correctly.
- $children = taxonomy_get_children($term3->tid);
- $this->assertTrue(isset($children[$term1->tid]), t('Term 3 saved as parent of term 1'));
-
- $this->assertEqual(count(taxonomy_get_tree($term3->vid, $term3->tid)), 1, t('Term 3 has one child term'));
-
- // Confirm that term3's parental relationship with term1 leads to a
- // node assocation being counted.
- $this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL), 1, t('Term has one valid node association due to child term.'));
-
- // Set term3 as the parent of term2.
- $term2->parent = array($term3->tid);
- taxonomy_term_save($term2);
-
- // term3 should now have two node associations counted.
- $this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL), 2, t('Term has two valid node associations due to child terms.'));
-
- // Save node1 with both child taxonomy terms, this should still result
- // in term3 having two node associations.
- $node1->taxonomy = array($term1->tid, $term2->tid);
- node_save($node1);
- $this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL), 2, t('Term has two valid node associations.'));
-
- // Confirm that the node type argument returns a single node association.
- $this->assertEqual(taxonomy_term_count_nodes($term3->tid, 'page'), 1, t("Term is associated with one node of type 'page'."));
- }
}
/**
@@ -391,6 +322,20 @@ class TaxonomyTermTestCase extends Taxon
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
+
+ $this->instance = array(
+ 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
+ 'bundle' => 'article',
+ 'widget' => array(
+ 'type' => 'options_select',
+ ),
+ 'display' => array(
+ 'full' => array(
+ 'type' => 'taxonomy_term_link',
+ ),
+ ),
+ );
+ field_create_instance($this->instance);
}
/**
@@ -422,7 +367,7 @@ class TaxonomyTermTestCase extends Taxon
// Edit $term2, setting $term1 as parent.
$edit = array();
- $edit['parent[]'] = $term1->tid;
+ $edit['parent'] = $term1->tid;
$this->drupalPost('taxonomy/term/' . $term2->tid . '/edit', $edit, t('Save'));
// Check the hierarchy.
@@ -454,7 +399,7 @@ class TaxonomyTermTestCase extends Taxon
$edit['title'] = $this->randomName();
$langcode = FIELD_LANGUAGE_NONE;
$edit["body[$langcode][0][value]"] = $this->randomName();
- $edit['taxonomy[' . $this->vocabulary->vid . ']'] = $term1->tid;
+ $edit[$this->instance['field_name'] . '[' . $langcode .'][value][]'] = $term1->tid;
$this->drupalPost('node/add/article', $edit, t('Save'));
// Check that the term is displayed when the node is viewed.
@@ -463,19 +408,11 @@ class TaxonomyTermTestCase extends Taxon
$this->assertText($term1->name, t('Term is displayed when viewing the node.'));
// Edit the node with a different term.
- $edit['taxonomy[' . $this->vocabulary->vid . ']'] = $term2->tid;
+ $edit[$this->instance['field_name'] . '[' . $langcode . '][value][]'] = $term2->tid;
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->drupalGet('node/' . $node->nid);
$this->assertText($term2->name, t('Term is displayed when viewing the node.'));
-
- // Delete node through browser.
- $this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
- $this->drupalGet('node/' . $node->nid);
- $this->assertNoText($term2->name, t('Checking if node exists'));
- // Checking database fields.
- $result = db_query('SELECT * FROM {taxonomy_term_node} WHERE nid = :nid', array(':nid' => $node->nid))->fetch();
- $this->assertTrue(empty($result), t('Term/node relationships are no longer in the database table.'));
}
/**
@@ -483,22 +420,25 @@ class TaxonomyTermTestCase extends Taxon
*/
function testNodeTermCreation() {
// Enable tags in the vocabulary.
- $this->vocabulary->tags = 1;
- taxonomy_vocabulary_save($this->vocabulary);
+ $instance = $this->instance;
+ $instance['widget'] = array('type' => 'taxonomy_autocomplete');
+ $instance['bundle'] = 'page';
+ field_create_instance($instance);
$terms = array(
$this->randomName(),
$this->randomName(),
$this->randomName(),
);
+
$edit = array();
$edit['title'] = $this->randomName();
- // Insert the terms in a comma separated list. Vocabulary 1 is a
- // free-tagging field created by the default profile.
- $edit['taxonomy[tags][' . $this->vocabulary->vid . ']'] = implode(', ', $terms);
$langcode = FIELD_LANGUAGE_NONE;
$edit["body[$langcode][0][value]"] = $this->randomName();
- $this->drupalPost('node/add/article', $edit, t('Save'));
- $this->assertRaw(t('@type %title has been created.', array('@type' => t('Article'), '%title' => $edit['title'])), t('The node was created successfully'));
+ // Insert the terms in a comma separated list. Vocabulary 1 is a
+ // free-tagging field created by the default profile.
+ $edit[$instance['field_name'] . "[$langcode][value]"] = implode(', ', $terms);
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+ $this->assertRaw(t('@type %title has been created.', array('@type' => t('Page'), '%title' => $edit['title'])), t('The node was created successfully'));
foreach ($terms as $term) {
$this->assertText($term, t('The term was saved and appears on the node page'));
}
@@ -514,7 +454,7 @@ class TaxonomyTermTestCase extends Taxon
);
// Explicitly set the parents field to 'root', to ensure that
// taxonomy_form_term_submit() handles the invalid term ID correctly.
- $edit['parent[]'] = 0;
+ $edit['parent'] = 0;
// Create the term to edit.
$this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->vid . '/list/add', $edit, t('Save'));
Index: profiles/default/default.install
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.install,v
retrieving revision 1.8
diff -u -p -r1.8 default.install
--- profiles/default/default.install 1 Oct 2009 13:22:43 -0000 1.8
+++ profiles/default/default.install 8 Oct 2009 07:29:05 -0000
@@ -175,20 +175,26 @@ function default_install() {
variable_set('theme_settings', $theme_settings);
// Create a default vocabulary named "Tags", enabled for the 'article' content type.
- $vocabulary = new stdClass;
- $vocabulary->name = 'Tags';
- $vocabulary->description = st('Use tags to group articles on similar topics into categories.');
- $vocabulary->machine_name = 'tags';
- $vocabulary->help = st('Enter a comma-separated list of words to describe your content.');
- $vocabulary->relations = 0;
- $vocabulary->hierarchy = 0;
- $vocabulary->multiple = 0;
- $vocabulary->required = 0;
- $vocabulary->tags = 1;
- $vocabulary->module = 'taxonomy';
- $vocabulary->weight = 0;
- $vocabulary->nodes = array('article' => 'article');
+ $description = st('Use tags to group articles on similar topics into categories.');
+ $help = st('Enter a comma-separated list of words to describe your content.');
+ $vocabulary = (object) array(
+ 'name' => 'Tags',
+ 'description' => $description,
+ 'machine_name' => 'tags',
+ 'help' => $help,
+ 'weight' => 0,
+ );
taxonomy_vocabulary_save($vocabulary);
+ $instance = array(
+ 'field_name' => 'taxonomy_' . $vocabulary->machine_name,
+ 'label' => $vocabulary->name,
+ 'bundle' => 'article',
+ 'description' => $vocabulary->help,
+ 'widget' => array(
+ 'type' => 'taxonomy_autocomplete',
+ ),
+ );
+ field_create_instance($instance);
// Enable default permissions for system roles.
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access content', 'use text format 1'));
|