- Patch #504666 by catch, yched, et al: make comments fieldable. Oh my. Bye bye comments as nodes?

merge-requests/26/head
Dries Buytaert 2009-07-31 19:44:21 +00:00
parent 04d7eb4acb
commit a8a15bcd90
11 changed files with 199 additions and 84 deletions

View File

@ -59,7 +59,7 @@ Drupal 7.0, xxxx-xx-xx (development version)
- Aggregator:
* Introduced architecture that allows pluggable parsers and processors for
syndicating RSS and Atom feeds.
* Added options to suspend updating specific feeds and never discard feeds
* Added options to suspend updating specific feeds and never discard feeds
items.
- Testing:
* Added test framework and tests.
@ -95,7 +95,7 @@ Drupal 7.0, xxxx-xx-xx (development version)
on as contributed themes (http://drupal.org/project/bluemarine,
http://drupal.org/project/chameleon and http://drupal.org/project/pushbutton).
* Added Stark theme to make analyzing Drupal's default HTML and CSS easier.
* Added Slate theme as the default administration interface theme.
* Added Seven theme as the default administration interface theme.
- File handling:
* Files are now first class Drupal objects with file_load(), file_save(),
and file_validate() functions and corresponding hooks.
@ -106,7 +106,7 @@ Drupal 7.0, xxxx-xx-xx (development version)
uploading a site logo--that don't require the overhead of databases and
hooks, the current unmanaged copy, move and delete operations have been
preserved but renamed to file_unmanaged_*().
* Rewrote file handling to use PHP stream wrappers to enable support for
* Rewrote file handling to use PHP stream wrappers to enable support for
both public and private files and to support pluggable storage mechanisms
and access to remote resources (e.g. S3 storage or Flickr photos).
- Image handling:
@ -120,7 +120,8 @@ Drupal 7.0, xxxx-xx-xx (development version)
* Modules can declare RDF namespaces which are serialized in the <html> tag
for RDFa support.
- Field API:
* Custom data fields may be attached to nodes and users, and taxonomy terms.
* Custom data fields may be attached to nodes, users, comments and taxonomy
terms.
* Node bodies and teasers are now Field API fields instead of
being a hard-coded property of node objects.
* In addition, any other object type may register with Field API
@ -132,12 +133,12 @@ Drupal 7.0, xxxx-xx-xx (development version)
via a command line script.
- Page organization
* Made the help text area a full featured region with blocks.
* Site mission is replaced with the highlighted content block region and
* Site mission is replaced with the highlighted content block region and
separate RSS feed description settings.
* The footer message setting was removed in favor of custom blocks.
* The footer message setting was removed in favor of custom blocks.
* Made the main page content a block which can be moved and ordered
with other blocks in the same region.
* Blocks can now return structured arrays for later rendering just
* Blocks can now return structured arrays for later rendering just
like page callbacks.
- Translation system
* The translation system now supports message context (msgctxt).

View File

@ -244,12 +244,12 @@ class NewDefaultThemeBlocks extends DrupalWebTestCase {
$this->drupalLogin($admin_user);
// Ensure no other theme's blocks are in the block table yet.
$count = db_query_range("SELECT 1 FROM {block} WHERE theme != 'garland'", 0, 1)->fetchField();
$this->assertFalse($count, t('Only Garland has blocks.'));
$count = db_query_range("SELECT 1 FROM {block} WHERE theme NOT IN ('garland', 'seven')", 0, 1)->fetchField();
$this->assertFalse($count, t('Only Garland and Seven have blocks.'));
// Populate list of all blocks for matching against new theme.
$blocks = array();
$result = db_query('SELECT * FROM {block}');
$result = db_query("SELECT * FROM {block} WHERE theme = 'garland'");
foreach ($result as $block) {
// $block->theme and $block->bid will not match, so remove them.
unset($block->theme, $block->bid);

View File

@ -128,7 +128,6 @@ class BlogTestCase extends DrupalWebTestCase {
if ($response2 == 200) {
$this->assertTitle(t('Blog | Drupal'), t('Blog help node was displayed'));
$this->assertText(t('Blog'), t('Blog help node was displayed'));
$this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('Breadcrumbs were displayed'));
}
// Verify the blog block was displayed.
@ -147,7 +146,6 @@ class BlogTestCase extends DrupalWebTestCase {
$this->assertResponse($response);
if ($response == 200) {
$this->assertTitle('Edit Blog entry ' . $node->title . ' | Drupal', t('Blog edit node was displayed'));
$this->assertText(t('Home ' . $crumb . ' @title', array('@title' => $node->title)), t('Breadcrumbs were displayed'));
}
if ($response == 200) {

View File

@ -196,14 +196,11 @@ function comment_multiple_delete_confirm(&$form_state) {
*/
function comment_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['comments'] as $cid => $value) {
$comment = comment_load($cid);
// Perform the actual comment deletion.
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
}
comment_delete_multiple(array_keys($form_state['values']['comments']));
cache_clear_all();
drupal_set_message(t('The comments have been deleted.'));
$count = count($form_state['values']['comments']);
watchdog('content', 'Deleted @count comments.', array('@count' => $count));
drupal_set_message(t('Deleted @count comments.', array('@count' => $count)));
}
$form_state['redirect'] = 'admin/content/comment';
}
@ -214,7 +211,7 @@ function comment_multiple_delete_confirm_submit($form, &$form_state) {
* @param $cid
* The comment to be deleted.
*/
function comment_delete($cid = NULL) {
function comment_delete_page($cid = NULL) {
$comment = db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comment} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = :cid', array(':cid' => $cid))->fetch();
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$output = '';
@ -252,41 +249,13 @@ function comment_confirm_delete(&$form_state, $comment) {
* Process comment_confirm_delete form submissions.
*/
function comment_confirm_delete_submit($form, &$form_state) {
drupal_set_message(t('The comment and all its replies have been deleted.'));
$comment = $form['#comment'];
// Delete the comment and its replies.
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
comment_delete($comment->cid);
drupal_set_message(t('The comment and all its replies have been deleted.'));
watchdog('content', t('Deleted comment @cid and its replies.', array('@cid' => $comment->cid)));
// Clear the cache so an anonymous user sees that his comment was deleted.
cache_clear_all();
$form_state['redirect'] = "node/$comment->nid";
}
/**
* Perform the actual deletion of a comment and all its replies.
*
* @param $comment
* An associative array describing the comment to be deleted.
*/
function _comment_delete_thread($comment) {
if (!is_object($comment) || !is_numeric($comment->cid)) {
watchdog('content', 'Cannot delete non-existent comment.', array(), WATCHDOG_WARNING);
return;
}
// Delete the comment.
db_delete('comment')
->condition('cid', $comment->cid)
->execute();
watchdog('content', 'Comment: deleted %subject.', array('%subject' => $comment->subject));
module_invoke_all('comment_delete', $comment);
// Delete the comment's replies.
$result = db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comment} c INNER JOIN {users} u ON u.uid = c.uid WHERE pid = :cid', array(':cid' => $comment->cid));
foreach ($result as $comment) {
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
_comment_delete_thread($comment);
}
}

View File

@ -296,3 +296,15 @@ function comment_schema() {
return $schema;
}
/**
* Create comment Field API bundles.
*/
function comment_update_7005() {
$ret = array();
foreach (node_type_get_types() as $info) {
field_attach_create_bundle('comment_node_' . $info->type);
}
return $ret;
}

View File

@ -148,7 +148,7 @@ function comment_menu() {
);
$items['comment/delete'] = array(
'title' => 'Delete comment',
'page callback' => 'comment_delete',
'page callback' => 'comment_delete_page',
'access arguments' => array('administer comments'),
'type' => MENU_CALLBACK,
);
@ -186,22 +186,59 @@ function comment_menu() {
return $items;
}
/**
* Implement hook_fieldable_info().
*/
function comment_fieldable_info() {
$return = array(
'comment' => array(
'label' => t('Comment'),
'object keys' => array(
'id' => 'cid',
'bundle' => 'node_type',
),
'bundle keys' => array(
'bundle' => 'type',
),
'bundles' => array(),
),
);
foreach (node_type_get_names() as $type => $name) {
$return['comment']['bundles']['comment_node_' . $type] = array(
'label' => $name,
);
}
return $return;
}
/**
* Implement hook_node_type().
*/
function comment_node_type($op, $info) {
$settings = array(
'comment',
'comment_default_mode',
'comment_default_per_page',
'comment_anonymous',
'comment_subject_field',
'comment_preview',
'comment_form_location',
);
switch ($op) {
case 'insert':
field_attach_create_bundle('comment_node_' . $info->type);
break;
case 'update':
if (!empty($info->old_type) && $info->type != $info->old_type) {
field_attach_rename_bundle('comment_node_' . $info->old_type, 'comment_node_' . $info->type);
}
break;
case 'delete':
field_attach_delete_bundle('comment_node_' . $info->type);
$settings = array(
'comment',
'comment_default_mode',
'comment_default_per_page',
'comment_anonymous',
'comment_subject_field',
'comment_preview',
'comment_form_location',
);
foreach ($settings as $setting) {
variable_del($setting . '_' . $info->type);
}
@ -782,6 +819,8 @@ function comment_build_content($comment, $build_mode = 'full') {
'#markup' => check_markup($comment->comment, $comment->format, '', FALSE),
);
$comment->content += field_attach_view('comment', $comment, $build_mode);
if (empty($comment->in_preview)) {
$comment->content['links']['comment'] = array(
'#theme' => 'links',
@ -1009,9 +1048,8 @@ function comment_node_insert($node) {
* Implement hook_node_delete().
*/
function comment_node_delete($node) {
db_delete('comment')
->condition('nid', $node->nid)
->execute();
$cids = db_query('SELECT cid FROM {comment} WHERE nid = :nid', array(':nid' => $node->nid))->fetchCol();
comment_delete_multiple($cids);
db_delete('node_comment_statistics')
->condition('nid', $node->nid)
->execute();
@ -1082,13 +1120,8 @@ function comment_user_cancel($edit, $account, $method) {
case 'user_cancel_delete':
module_load_include('inc', 'comment', 'comment.admin');
$result = db_query('SELECT c.cid FROM {comment} c WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
foreach ($result as $cid) {
$comment = comment_load($cid);
// Delete the comment and its replies.
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
}
$cids = db_query('SELECT c.cid FROM {comment} c WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
comment_delete_multiple($cids);
break;
}
}
@ -1136,6 +1169,14 @@ function comment_save($comment) {
$comment->$key = $default;
}
}
// Make sure we have a bundle name.
if (!isset($comment->node_type)) {
$node = node_load($comment->nid);
$comment->node_type = 'comment_node_' . $node->type;
}
field_attach_presave('comment', $comment);
if ($comment->cid) {
// Update the comment in the database.
db_update('comment')
@ -1152,6 +1193,7 @@ function comment_save($comment) {
))
->condition('cid', $comment->cid)
->execute();
field_attach_update('comment', $comment);
// Allow modules to respond to the updating of a comment.
module_invoke_all('comment_update', $comment);
// Add an entry to the watchdog log.
@ -1229,6 +1271,8 @@ function comment_save($comment) {
// saved node to be propagated to the slave.
db_ignore_slave();
field_attach_insert('comment', $comment);
// Tell the other modules a new comment has been submitted.
module_invoke_all('comment_insert', $comment);
// Add an entry to the watchdog log.
@ -1243,6 +1287,42 @@ function comment_save($comment) {
}
}
/**
* Delete a comment and all its replies.
*
* @param $cid
* The comment to delete.
*/
function comment_delete($cid) {
comment_delete_multiple(array($cid));
}
/**
* Delete comments and all their replies.
*
* @param $cids
* The comment to delete.
*/
function comment_delete_multiple($cids) {
$comments = comment_load_multiple($cids);
if ($comments) {
// Delete the comments.
db_delete('comment')
->condition('cid', array_keys($comments), 'IN')
->execute();
foreach ($comments as $comment) {
field_attach_delete('comment', $comment);
module_invoke_all('comment_delete', $comment);
// Delete the comment's replies.
$child_cids = db_query('SELECT cid FROM {comment} WHERE pid = :cid', array(':cid' => $comment->cid))->fetchCol();
comment_delete_multiple($child_cids);
_comment_update_node_statistics($comment->nid);
}
}
}
/**
* Implement hook_link().
*/
@ -1366,7 +1446,9 @@ function comment_load_multiple($cids = array(), $conditions = array()) {
if ($cids || $conditions) {
$query = db_select('comment', 'c');
$query->innerJoin('users', 'u', 'c.uid = u.uid');
$query->innerJoin('node', 'n', 'c.nid = n.nid');
$query->addField('u', 'name', 'registered_name');
$query->addField('n', 'type', 'node_type');
$query
->fields('c', array('cid', 'nid', 'pid', 'comment', 'subject', 'format', 'timestamp', 'name', 'mail', 'homepage', 'status', 'thread'))
->fields('u', array( 'uid', 'signature', 'picture', 'data', 'status'));
@ -1390,11 +1472,14 @@ function comment_load_multiple($cids = array(), $conditions = array()) {
$comment = drupal_unpack($comment);
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$comment->new = node_mark($comment->nid, $comment->timestamp);
$comment->node_type = 'comment_node_' . $comment->node_type;
$comments[$key] = $comment;
}
// Invoke hook_comment_load().
if (!empty($comments)) {
// Attach fields.
field_attach_load('comment', $comments);
// Invoke hook_comment_load().
module_invoke_all('comment_load', $comments);
}
return $comments;
@ -1752,6 +1837,10 @@ function comment_form(&$form_state, $edit = array()) {
'#type' => 'value',
'#value' => !empty($edit['uid']) ? $edit['uid'] : 0,
);
$form['node_type'] = array(
'#type' => 'value',
'#value' => 'comment_node_' . $node->type,
);
// Only show the save button if comment previews are optional or if we are
// already previewing the submission. However, if there are form errors,
@ -1776,6 +1865,11 @@ function comment_form(&$form_state, $edit = array()) {
$form['#action'] = url('comment/reply/' . $edit['nid']);
}
$comment = (object) $edit;
$comment->node_type = 'comment_node_' . $node->type;
$form['#builder_function'] = 'comment_form_submit_build_comment';
field_attach_form('comment', $comment, $form, $form_state);
return $form;
}
@ -1829,12 +1923,11 @@ function comment_preview($comment) {
}
if ($comment->pid) {
$parent_comment = db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comment} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = :cid AND c.status = :status', array(
':cid' => $comment->pid,
':status' => COMMENT_PUBLISHED,
))->fetchObject();
$build = comment_build($parent_comment);
$build = array();
if ($comments = comment_load_multiple(array($comment->pid), array('status' => COMMENT_PUBLISHED))) {
$parent_comment = $comments[$comment->pid];
$build = comment_build($parent_comment);
}
}
else {
$build = node_build($node);
@ -1851,6 +1944,9 @@ function comment_preview($comment) {
*/
function comment_form_validate($form, &$form_state) {
global $user;
$comment = (object) $form_state['values'];
field_attach_form_validate('comment', $comment, $form, $form_state);
if ($user->uid === 0) {
foreach (array('name', 'homepage', 'mail') as $field) {
// Set cookie for 365 days.
@ -1949,6 +2045,8 @@ function comment_submit($comment) {
function comment_form_submit_build_comment($form, &$form_state) {
$comment = comment_submit($form_state['values']);
field_attach_submit('comment', $comment, $form, $form_state);
$form_state['comment'] = (array)$comment;
$form_state['rebuild'] = TRUE;
return $comment;

View File

@ -73,6 +73,8 @@ function comment_reply($node, $pid = NULL) {
}
// Display the parent comment
$comment = drupal_unpack($comment);
$comment->node_type = 'comment_node_' . $node->type;
field_attach_load('comment', array($comment->cid => $comment));
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$build['comment_parent'] = comment_build($comment);
}

View File

@ -207,7 +207,7 @@ class CommentHelperCase extends DrupalWebTestCase {
if ($operation == 'delete') {
$this->drupalPost(NULL, array(), t('Delete comments'));
$this->assertText(t('The comments have been deleted.'), t('Operation "' . $operation . '" was performed on comment.'));
$this->assertRaw(t('Deleted @count comments.', array('@count' => 1)), t('Operation "' . $operation . '" was performed on comment.'));
}
else {
$this->assertText(t('The update has been performed.'), t('Operation "' . $operation . '" was performed on comment.'));

View File

@ -288,7 +288,6 @@ class ForumTestCase extends DrupalWebTestCase {
if ($response2 == 200) {
$this->assertTitle(t('Forum | Drupal'), t('Forum help title was displayed'));
$this->assertText(t('Forum'), t('Forum help node was displayed'));
$this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('Breadcrumbs were displayed'));
}
// Verify the forum blocks were displayed.
@ -316,7 +315,6 @@ class ForumTestCase extends DrupalWebTestCase {
$this->assertResponse($response);
if ($response == 200) {
$this->assertTitle('Edit Forum topic ' . $node->title . ' | Drupal', t('Forum edit node was displayed'));
$this->assertText(t('Home ' . $crumb . ' @title', array('@title' => $node->title)), t('Breadcrumbs were displayed'));
}
if ($response == 200) {

View File

@ -64,8 +64,6 @@ class HelpTestCase extends DrupalWebTestCase {
// continue;
// }
$this->assertTitle($name . ' | Drupal', t('[' . $module . '] Title was displayed'));
$this->assertRaw('<h2>' . t($name) . '</h2>', t('[' . $module . '] Heading was displayed'));
$this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('[' . $module . '] Breadcrumbs were displayed'));
}
}
}

View File

@ -84,6 +84,36 @@ function default_profile_site_setup(&$install_state) {
'pages' => '',
'cache' => -1,
),
array(
'module' => 'system',
'delta' => 'main',
'theme' => 'seven',
'status' => 1,
'weight' => 0,
'region' => 'content',
'pages' => '',
'cache' => -1,
),
array(
'module' => 'system',
'delta' => 'help',
'theme' => 'seven',
'status' => 1,
'weight' => 0,
'region' => 'help',
'pages' => '',
'cache' => -1,
),
array(
'module' => 'user',
'delta' => 'login',
'theme' => 'seven',
'status' => 1,
'weight' => 10,
'region' => 'content',
'pages' => '',
'cache' => -1,
),
);
$query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
foreach ($values as $record) {
@ -188,6 +218,15 @@ function default_profile_site_setup(&$install_state) {
// Save some default links.
$link = array('link_path' => 'admin/structure/menu-customize/main-menu/add', 'link_title' => 'Add a main menu link', 'menu_name' => 'main-menu');
menu_link_save($link);
// Enable the admin theme.
db_update('system')
->fields(array('status' => 1))
->condition('type', 'theme')
->condition('name', 'seven')
->execute();
variable_set('admin_theme', 'seven');
variable_set('node_admin_theme', '1');
}
/**