#829536 by Mile23, ilo: Improve nodeapi example to support revisions
authorRandy Fay
Fri, 10 Dec 2010 06:49:28 +0000 (06:49 +0000)
committerRandy Fay
Fri, 10 Dec 2010 06:49:28 +0000 (06:49 +0000)
nodeapi_example/nodeapi_example.install
nodeapi_example/nodeapi_example.module
nodeapi_example/nodeapi_example.test

index 1be20d4..abddcf1 100644 (file)
@@ -29,10 +29,32 @@ function nodeapi_example_schema() {
   $schema['nodeapi_example'] = array(
     'description' => 'Stores information of extended content.',
     'fields' => array(
-      'nid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'rating' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-  ),
-    'primary key' => array('nid'),
+      'nid'    => array(
+        'description' => 'Node ID that the rating is applied to.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0
+      ),
+      'vid'    => array(
+        'description' => 'Revision ID, as we are tracking rating with node revisions',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0
+      ),
+      'rating' => array(
+        'description' => 'The rating of the node.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0
+      ),
+    ),
+    'primary key' => array('vid'),
+    'indexes' => array(
+      'nid'   => array('nid'),
+    ),
   );
 
   return $schema;
index 4d365cf..cf6f1c1 100755 (executable)
@@ -7,7 +7,8 @@
  * content types.
  *
  * We will add the ability for each node to have a "rating," which will be a
- * number from one to five.
+ * number from one to five. The rating will be tracked using the revision
+ * system also, so every node revision may have different rating values.
  */
 
 /**
@@ -124,21 +125,25 @@ function nodeapi_example_node_validate($node, $form) {
  */
 function nodeapi_example_node_load($nodes, $form) {
   foreach ($nodes as $node) {
+    // We are using the revision id instead of node id
     if (variable_get('nodeapi_example_' . $node->type, FALSE)) {
-      $nids[] = $node->nid;
+      $vids[] = $node->vid;
     }
   }
   // Check if we should load rating for any of the nodes
-  if (!isset($nids) || !count($nids)) {
+  if (!isset($vids) || !count($vids)) {
     return;
   }
 
+  // When we read, we don't care about the node->nid, but we look for the right
+  // revision ID (node->vid)
   $result = db_select('nodeapi_example', 'e')
   ->fields('e', array(
         'nid',
+        'vid',
         'rating',
   ))
-  ->where('e.nid IN (:nids)', array(':nids' => $nids))
+  ->where('e.vid IN (:vids)', array(':vids' => $vids))
   ->execute();
 
   foreach ($result as $record) {
@@ -158,6 +163,7 @@ function nodeapi_example_node_insert($node) {
     db_insert('nodeapi_example')
     ->fields(array(
         'nid' => $node->nid,
+        'vid' => $node->vid,
         'rating' => $node->nodeapi_example_rating,
     ))
     ->execute();
@@ -167,7 +173,8 @@ function nodeapi_example_node_insert($node) {
 /**
  * Implements hook_node_delete().
  *
- * When a node is deleted, we need to remove all related records from our table.
+ * When a node is deleted, we need to remove all related records from our table,
+ * including all revisions. For the delete operations we use node->nid.
  */
 function nodeapi_example_node_delete($node) {
   // Notice that we're deleting even if the content type has no rating enabled.
@@ -189,8 +196,26 @@ function nodeapi_example_node_delete($node) {
  */
 function nodeapi_example_node_update($node) {
   if (variable_get('nodeapi_example_' . $node->type, FALSE)) {
-    nodeapi_example_node_delete($node);
-    nodeapi_example_node_insert($node);
+    // If may happen that this node does not have a previous saved rating
+    // value, so we can't just update it, we need to check first if this
+    $rating = db_select('nodeapi_example', 'e')
+      ->fields('e', array(
+        'rating',
+      ))
+      ->where('e.vid = (:vid)', array(':vid' => $node->vid))
+      ->execute()->fetchField();
+
+    if($rating) {
+      // node has been rated before.
+      db_update('nodeapi_example')
+         ->fields(array('rating' => $node->nodeapi_example_rating))
+         ->condition('vid', $node->vid)
+         ->execute();
+    }
+    else {
+      // Node was not previously rated, so insert a new rating in database.
+      nodeapi_example_node_insert($node);
+    }
   }
 }
 
index 835eab8..3e44b42 100644 (file)
@@ -36,14 +36,21 @@ class NodeApiExampleTestCase extends DrupalWebTestCase {
   function setUp() {
     parent::setUp('nodeapi_example');
 
-    // Create admin user. This module has no access control, so we can use a trusted user.
-    $this->web_user = $this->drupalCreateUser(array('administer content types', 'bypass node access'));
+    // Create admin user. This module has no access control, so we can use a
+    // trusted user. Revision access and revert permissions are required too.
+    $this->web_user = $this->drupalCreateUser(array(
+      'administer nodes', // Required to set revision checkbox
+      'administer content types',
+      'bypass node access',
+      'view revisions',
+      'revert revisions'
+    ));
     // Login the admin user.
     $this->drupalLogin($this->web_user);
   }
 
   /**
-   * Login user, create an example node, and test blog functionality through the admin and user interfaces.
+   * Login user, create an example node, and use the rating system
    */
   function testNodeExampleBasic() {
 
@@ -106,5 +113,100 @@ class NodeApiExampleTestCase extends DrupalWebTestCase {
 
     // Check that content has been rated
     $this->assertRaw(t('Rating: %rating', array('%rating' => t('Good'))), t('Content is successfully rated.'));
+
+  }
+
+  /**
+   * Login user, create an example node, and test rating functionality with
+   * a node using revisions.
+   */
+  function testNodeExampleRevision() {
+
+    // Login the user.
+    $this->drupalLogin($this->web_user);
+
+    // Create custom content type
+    $content_type = $this->drupalCreateContentType();
+    $type = $content_type->type;
+
+    // Go to edit the settings of this content type
+    $this->drupalGet('admin/structure/types/manage/' . $type);
+    $this->assertResponse(200);
+
+    // Check if the new Rating options appear in the settings page
+    $this->assertText(t('NodeAPI Example Rating'), t('Rating options found in content type.'));
+    $this->assertFieldByName('nodeapi_example', 1, t('Rating is Disabled by default.'));
+
+    // Disable the rating for this content type: 0 for Disabled, 1 for Enabled.
+    $content_settings = array(
+      'nodeapi_example' => 0,
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $type, $content_settings, t('Save content type'));
+    $this->assertResponse(200);
+    $this->assertRaw(' has been updated.', t('Settings modified successfully for content type.'));
+
+    // Create an example node
+    $langcode = LANGUAGE_NONE;
+    $edit = array(
+      "title" => $this->randomName(),
+    );
+    $this->drupalPost('node/add/' . $type, $edit, t('Save'));
+    $this->assertResponse(200);
+
+    // Check that the rating is not shown, as we have not yet enabled it
+    $this->assertNoRaw('Rating: <em>', t('Extended rating information is not shown.'));
+
+    // Save current current url (we are viewing the new node)
+    $node_url = $this->getUrl();
+
+    // Enable the rating for this content type: 0 for Disabled, 1 for Enabled.
+    $content_settings = array(
+      'nodeapi_example' => TRUE,
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $type, $content_settings, t('Save content type'));
+    $this->assertResponse(200);
+    $this->assertRaw(' has been updated.', t('Settings modified successfully for content type.'));
+
+    // Check previously create node. It should be not rated
+    $this->drupalGet($node_url);
+    $this->assertResponse(200);
+    $this->assertRaw(t('Rating: %rating', array('%rating' => t('Unrated'))), t('Content is not rated.'));
+
+    // Rate the content, 4 is for "Good"
+    $rate = array(
+      'nodeapi_example_rating' => 4,
+    );
+    $this->drupalPost($node_url . '/edit', $rate, t('Save'));
+    $this->assertResponse(200);
+
+    // Check that content has been rated
+    $this->assertRaw(t('Rating: %rating', array('%rating' => t('Good'))), t('Content is successfully rated.'));
+
+    // Rate the content to poor using a new revision, 1 is for "Poor"
+    $rate = array(
+      'nodeapi_example_rating' => 1,
+      'revision'               => 1,
+    );
+    $this->drupalPost($node_url . '/edit', $rate, t('Save'));
+    $this->assertResponse(200);
+
+    // Check that content has been rated
+    $this->assertRaw(t('Rating: %rating', array('%rating' => t('Poor'))), t('Content is successfully rated.'));
+
+    //Now switch back to previous revision of the node.
+    $this->drupalGet($node_url . '/revisions');
+    // There is only a revision, so it must work just clicking the first link..
+    $this->clickLink('revert');
+    $revert_form = $this->getUrl();
+    $this->drupalPost($revert_form, array(), t('Revert'));
+
+    // Go back to the node page.
+    $this->drupalGet($node_url);
+    $this->assertResponse(200);
+
+    // Check that content has been rated
+    $this->assertRaw(t('Rating: %rating', array('%rating' => t('Good'))), t('Content rating matches reverted revision.'));
+
   }
+
 }