diff options
Diffstat (limited to 'modules/node')
-rw-r--r-- | modules/node/node.api.php | 67 | ||||
-rw-r--r-- | modules/node/node.install | 2 | ||||
-rw-r--r-- | modules/node/node.module | 60 | ||||
-rw-r--r-- | modules/node/node.test | 85 | ||||
-rw-r--r-- | modules/node/node.tpl.php | 20 | ||||
-rw-r--r-- | modules/node/tests/node_test.module | 10 |
6 files changed, 173 insertions, 71 deletions
diff --git a/modules/node/node.api.php b/modules/node/node.api.php index 6d14a0737..052effc9b 100644 --- a/modules/node/node.api.php +++ b/modules/node/node.api.php @@ -498,9 +498,18 @@ function hook_node_revision_delete($node) { /** * Respond to creation of a new node. * - * This hook is invoked from node_save() after the node is inserted into the - * node table in the database, after the type-specific hook_insert() is invoked, - * and after field_attach_insert() is called. + * This hook is invoked from node_save() after the database query that will + * insert the node into the node table is scheduled for execution, after the + * type-specific hook_insert() is invoked, and after field_attach_insert() is + * called. + * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and node_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check node_save() and db_transaction() for more info. * * @param $node * The node that is being created. @@ -517,40 +526,43 @@ function hook_node_insert($node) { } /** - * Act on nodes being loaded from the database. + * Act on arbitrary nodes being loaded from the database. + * + * This hook should be used to add information that is not in the node or + * node revisions table, not to replace information that is in these tables + * (which could interfere with the entity cache). For performance reasons, + * information for all available nodes should be loaded in a single query where + * possible. * * This hook is invoked during node loading, which is handled by entity_load(), * via classes NodeController and DrupalDefaultEntityController. After the node * information is read from the database or the entity cache, hook_load() is - * invoked on the node's content type module, then field_attach_node_revision() + * invoked on the node's content type module, then field_attach_load_revision() * or field_attach_load() is called, then hook_entity_load() is invoked on all * implementing modules, and finally hook_node_load() is invoked on all * implementing modules. * - * This hook should only be used to add information that is not in the node or - * node revisions table, not to replace information that is in these tables - * (which could interfere with the entity cache). For performance reasons, - * information for all available nodes should be loaded in a single query where - * possible. - * - * The $types parameter allows for your module to have an early return (for - * efficiency) if your module only supports certain node types. However, if your - * module defines a content type, you can use hook_load() to respond to loading - * of just that content type. - * * @param $nodes * An array of the nodes being loaded, keyed by nid. * @param $types - * An array containing the types of the nodes. + * An array containing the node types present in $nodes. Allows for an early + * return for modules that only support certain node types. However, if your + * module defines a content type, you can use hook_load() to respond to + * loading of just that content type. * * For a detailed usage example, see nodeapi_example.module. * * @ingroup node_api_hooks */ function hook_node_load($nodes, $types) { - $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes))); - foreach ($result as $record) { - $nodes[$record->nid]->foo = $record->foo; + // Decide whether any of $types are relevant to our purposes. + if (count(array_intersect($types_we_want_to_process, $types))) { + // Gather our extra data for each of these nodes. + $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes))); + // Add our extra data to the node objects. + foreach ($result as $record) { + $nodes[$record->nid]->foo = $record->foo; + } } } @@ -684,9 +696,18 @@ function hook_node_presave($node) { /** * Respond to updates to a node. * - * This hook is invoked from node_save() after the node is updated in the node - * table in the database, after the type-specific hook_update() is invoked, and - * after field_attach_update() is called. + * This hook is invoked from node_save() after the database query that will + * update node in the node table is scheduled for execution, after the + * type-specific hook_update() is invoked, and after field_attach_update() is + * called. + * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and node_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check node_save() and db_transaction() for more info. * * @param $node * The node that is being updated. diff --git a/modules/node/node.install b/modules/node/node.install index 434410c8d..16d3dbaa0 100644 --- a/modules/node/node.install +++ b/modules/node/node.install @@ -474,7 +474,7 @@ function node_update_dependencies() { * * This function is valid for a database schema version 7000. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_node_get_types() { $node_types = db_query('SELECT * FROM {node_type}')->fetchAllAssoc('type', PDO::FETCH_OBJ); diff --git a/modules/node/node.module b/modules/node/node.module index 264816c00..f181b52bb 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -243,7 +243,7 @@ function node_field_display_node_alter(&$display, $context) { } /** - * Entity uri callback. + * Entity URI callback. */ function node_uri($node) { return array( @@ -1345,6 +1345,14 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) { // Remove previously built content, if exists. $node->content = array(); + // Allow modules to change the view mode. + $context = array( + 'entity_type' => 'node', + 'entity' => $node, + 'langcode' => $langcode, + ); + drupal_alter('entity_view_mode', $view_mode, $context); + // The 'view' hook can be implemented to overwrite the default function // to display nodes. if (node_hook($node, 'view')) { @@ -1984,6 +1992,9 @@ function node_menu() { 'page callback' => 'node_feed', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, + // Pass a FALSE and array argument to ensure that additional path components + // are not passed to node_feed(). + 'page arguments' => array(FALSE, array()), ); // @todo Remove this loop when we have a 'description callback' property. // Reset internal static cache of _node_types_build(), forces to rebuild the @@ -2578,10 +2589,10 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $weight = 0, $langcod function node_page_default() { $select = db_select('node', 'n') ->fields('n', array('nid', 'sticky', 'created')) - ->condition('promote', 1) - ->condition('status', 1) - ->orderBy('sticky', 'DESC') - ->orderBy('created', 'DESC') + ->condition('n.promote', 1) + ->condition('n.status', 1) + ->orderBy('n.sticky', 'DESC') + ->orderBy('n.created', 'DESC') ->extend('PagerDefault') ->limit(variable_get('default_nodes_main', 10)) ->addTag('node_access'); @@ -2764,7 +2775,7 @@ function node_search_validate($form, &$form_state) { // Insert extra restrictions into the search keywords string. if (isset($form_state['values']['type']) && is_array($form_state['values']['type'])) { - // Retrieve selected types - Forms API sets the value of unselected + // Retrieve selected types - Form API sets the value of unselected // checkboxes to 0. $form_state['values']['type'] = array_filter($form_state['values']['type']); if (count($form_state['values']['type'])) { @@ -3891,24 +3902,25 @@ function node_unpublish_by_keyword_action($node, $context) { */ function node_requirements($phase) { $requirements = array(); - // Ensure translations don't break at install time - $t = get_t(); - // Only show rebuild button if there are either 0, or 2 or more, rows - // in the {node_access} table, or if there are modules that - // implement hook_node_grants(). - $grant_count = db_query('SELECT COUNT(*) FROM {node_access}')->fetchField(); - if ($grant_count != 1 || count(module_implements('node_grants')) > 0) { - $value = format_plural($grant_count, 'One permission in use', '@count permissions in use', array('@count' => $grant_count)); - } else { - $value = $t('Disabled'); - } - $description = $t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Rebuilding will remove all privileges to content and replace them with permissions based on the current modules and settings. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions.'); - - $requirements['node_access'] = array( - 'title' => $t('Node Access Permissions'), - 'value' => $value, - 'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'), - ); + if ($phase === 'runtime') { + // Only show rebuild button if there are either 0, or 2 or more, rows + // in the {node_access} table, or if there are modules that + // implement hook_node_grants(). + $grant_count = db_query('SELECT COUNT(*) FROM {node_access}')->fetchField(); + if ($grant_count != 1 || count(module_implements('node_grants')) > 0) { + $value = format_plural($grant_count, 'One permission in use', '@count permissions in use', array('@count' => $grant_count)); + } + else { + $value = t('Disabled'); + } + $description = t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Rebuilding will remove all privileges to content and replace them with permissions based on the current modules and settings. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions.'); + + $requirements['node_access'] = array( + 'title' => t('Node Access Permissions'), + 'value' => $value, + 'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'), + ); + } return $requirements; } diff --git a/modules/node/node.test b/modules/node/node.test index 37d05e529..9ef4c2586 100644 --- a/modules/node/node.test +++ b/modules/node/node.test @@ -832,7 +832,11 @@ class NodeRSSContentTestCase extends DrupalWebTestCase { // viewing node. $this->drupalGet("node/$node->nid"); $this->assertNoText($rss_only_content, t('Node content designed for RSS doesn\'t appear when viewing node.')); - + + // Check that the node feed page does not try to interpret additional path + // components as arguments for node_feed() and returns default content. + $this->drupalGet('rss.xml/' . $this->randomName() . '/' . $this->randomName()); + $this->assertText($rss_only_content, t('Ignore page arguments when delivering rss.xml.')); } } @@ -2030,9 +2034,9 @@ class NodeQueryAlter extends DrupalWebTestCase { // Create user with simple node access permission. The 'node test view' // permission is implemented and granted by the node_access_test module. - $this->accessUser = $this->drupalCreateUser(array('access content', 'node test view')); - $this->noAccessUser = $this->drupalCreateUser(array('access content')); - $this->noAccessUser2 = $this->drupalCreateUser(array('access content')); + $this->accessUser = $this->drupalCreateUser(array('access content overview', 'access content', 'node test view')); + $this->noAccessUser = $this->drupalCreateUser(array('access content overview', 'access content')); + $this->noAccessUser2 = $this->drupalCreateUser(array('access content overview', 'access content')); } /** @@ -2045,11 +2049,19 @@ class NodeQueryAlter extends DrupalWebTestCase { $this->assertText('Yes, 4 nodes', "4 nodes were found for access user"); $this->assertNoText('Exception', "No database exception"); + // Test the content overview page. + $this->drupalGet('admin/content'); + $table_rows = $this->xpath('//tbody/tr'); + $this->assertEqual(4, count($table_rows), "4 nodes were found for access user"); + // Verify that a user with no access permission cannot see nodes. $this->drupalLogin($this->noAccessUser); $this->drupalGet('node_access_test_page'); $this->assertText('No nodes', "No nodes were found for no access user"); $this->assertNoText('Exception', "No database exception"); + + $this->drupalGet('admin/content'); + $this->assertText(t('No content available.')); } /** @@ -2474,24 +2486,24 @@ class NodeAccessPagerTestCase extends DrupalWebTestCase { // View the node page. With the default 50 comments per page there should // be two pages (0, 1) but no third (2) page. $this->drupalGet('node/' . $node->nid); - $this->assertText($node->title, t('Node title found.')); - $this->assertText(t('Comments'), t('Has a comments section.')); - $this->assertRaw('page=1', t('Secound page exists.')); - $this->assertNoRaw('page=2', t('No third page exists.')); + $this->assertText($node->title); + $this->assertText(t('Comments')); + $this->assertRaw('page=1'); + $this->assertNoRaw('page=2'); } /** * Tests the forum node pager for nodes with multiple grants per realm. */ public function testForumPager() { - // Lookup the forums vocabulary vid. + // Look up the forums vocabulary ID. $vid = variable_get('forum_nav_vocabulary', 0); - $this->assertTrue($vid, t('Forum navigation vocabulary found.')); + $this->assertTrue($vid, 'Forum navigation vocabulary ID is set.'); - // Lookup the general discussion term. + // Look up the general discussion term. $tree = taxonomy_get_tree($vid, 0, 1); $tid = reset($tree)->tid; - $this->assertTrue($tid, t('General discussion term found.')); + $this->assertTrue($tid, 'General discussion term is found in the forum vocabulary.'); // Create 30 nodes. for ($i = 0; $i < 30; $i++) { @@ -2510,8 +2522,8 @@ class NodeAccessPagerTestCase extends DrupalWebTestCase { // page there should be two pages for 30 nodes, no more. $this->drupalLogin($this->web_user); $this->drupalGet('forum/' . $tid); - $this->assertRaw('page=1', t('Secound page exists.')); - $this->assertNoRaw('page=2', t('No third page exists.')); + $this->assertRaw('page=1'); + $this->assertNoRaw('page=2'); } } @@ -2589,3 +2601,48 @@ class NodeAccessFieldTestCase extends NodeWebTestCase { $this->assertRaw($default, 'The updated default value is displayed when creating a new node.'); } } + +/** + * Tests changing view modes for nodes. + */ +class NodeEntityViewModeAlterTest extends NodeWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Node entity view mode', + 'description' => 'Test changing view mode.', + 'group' => 'Node' + ); + } + + function setUp() { + parent::setUp(array('node_test')); + } + + /** + * Create a "Basic page" node and verify its consistency in the database. + */ + function testNodeViewModeChange() { + $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content')); + $this->drupalLogin($web_user); + + // Create a node. + $edit = array(); + $langcode = LANGUAGE_NONE; + $edit["title"] = $this->randomName(8); + $edit["body[$langcode][0][value]"] = t('Data that should appear only in the body for the node.'); + $edit["body[$langcode][0][summary]"] = t('Extra data that should appear only in the teaser for the node.'); + $this->drupalPost('node/add/page', $edit, t('Save')); + + $node = $this->drupalGetNodeByTitle($edit["title"]); + + // Set the flag to alter the view mode and view the node. + variable_set('node_test_change_view_mode', 'teaser'); + $this->drupalGet('node/' . $node->nid); + + // Check that teaser mode is viewed. + $this->assertText('Extra data that should appear only in the teaser for the node.', 'Teaser text present'); + // Make sure body text is not present. + $this->assertNoText('Data that should appear only in the body for the node.', 'Body text not present'); + } +} diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php index 6d0f489d7..4c358a16d 100644 --- a/modules/node/node.tpl.php +++ b/modules/node/node.tpl.php @@ -14,7 +14,7 @@ * - $date: Formatted creation date. Preprocess functions can reformat it by * calling format_date() with the desired parameters on the $created variable. * - $name: Themed username of node author output from theme_username(). - * - $node_url: Direct url of the current node. + * - $node_url: Direct URL of the current node. * - $display_submitted: Whether submission information should be displayed. * - $submitted: Submission information created from $name and $date during * template_preprocess_node(). @@ -22,7 +22,7 @@ * CSS. It can be manipulated through the variable $classes_array from * preprocess functions. The default values can be one or more of the * following: - * - node: The current template type, i.e., "theming hook". + * - node: The current template type; for example, "theming hook". * - node-[type]: The current node type. For example, if the node is a * "Blog entry" it would result in "node-blog". Note that the machine * name will often be in a short form of the human readable label. @@ -42,7 +42,7 @@ * * Other variables: * - $node: Full node object. Contains data that may not be safe. - * - $type: Node type, i.e. story, page, blog, etc. + * - $type: Node type; for example, story, page, blog, etc. * - $comment_count: Number of comments attached to the node. * - $uid: User ID of the node author. * - $created: Time the node was published formatted in Unix timestamp. @@ -53,7 +53,7 @@ * - $id: Position of the node. Increments each time it's output. * * Node status variables: - * - $view_mode: View mode, e.g. 'full', 'teaser'... + * - $view_mode: View mode; for example, "full", "teaser". * - $teaser: Flag for the teaser state (shortcut for $view_mode == 'teaser'). * - $page: Flag for the full page state. * - $promote: Flag for front page promotion state. @@ -67,15 +67,17 @@ * - $is_admin: Flags true when the current user is an administrator. * * Field variables: for each field instance attached to the node a corresponding - * variable is defined, e.g. $node->body becomes $body. When needing to access - * a field's raw values, developers/themers are strongly encouraged to use these - * variables. Otherwise they will have to explicitly specify the desired field - * language, e.g. $node->body['en'], thus overriding any language negotiation - * rule that was previously applied. + * variable is defined; for example, $node->body becomes $body. When needing to + * access a field's raw values, developers/themers are strongly encouraged to + * use these variables. Otherwise they will have to explicitly specify the + * desired field language; for example, $node->body['en'], thus overriding any + * language negotiation rule that was previously applied. * * @see template_preprocess() * @see template_preprocess_node() * @see template_process() + * + * @ingroup themeable */ ?> <div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>> diff --git a/modules/node/tests/node_test.module b/modules/node/tests/node_test.module index b0ebc149a..a52c1fad0 100644 --- a/modules/node/tests/node_test.module +++ b/modules/node/tests/node_test.module @@ -149,3 +149,13 @@ function node_test_node_update($node) { } } } + +/** + * Implements hook_entity_view_mode_alter(). + */ +function node_test_entity_view_mode_alter(&$view_mode, $context) { + // Only alter the view mode if we are on the test callback. + if ($change_view_mode = variable_get('node_test_change_view_mode', '')) { + $view_mode = $change_view_mode; + } +} |