<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[BuddyPress][7956] trunk: Overhaul the way that individual group objects are cached</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://buddypress.trac.wordpress.org/changeset/7956">7956</a></dd>
<dt>Author</dt> <dd>boonebgorges</dd>
<dt>Date</dt> <dd>2014-02-21 17:51:10 +0000 (Fri, 21 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Overhaul the way that individual group objects are cached

The existing implementation was broken in a number of ways. Most critically,
user-specific data (like is_member) was being stored in the persistent object
cache without respect to user.

This refactor excludes the user-specific data from being cached along with the
group object. It also reworks the way that items are keyed in the cache, for
greater consistency with WordPress and the other BP components.

See <a href="http://buddypress.trac.wordpress.org/ticket/5407">#5407</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkbpgroupsbpgroupscachephp">trunk/bp-groups/bp-groups-cache.php</a></li>
<li><a href="#trunkbpgroupsbpgroupsclassesphp">trunk/bp-groups/bp-groups-classes.php</a></li>
<li><a href="#trunkbpgroupsbpgroupsfunctionsphp">trunk/bp-groups/bp-groups-functions.php</a></li>
<li><a href="#trunkteststestcasesgroupscachephp">trunk/tests/testcases/groups/cache.php</a></li>
<li><a href="#trunkteststestcasesgroupsclassbpgroupsgroupphp">trunk/tests/testcases/groups/class-bp-groups-group.php</a></li>
<li><a href="#trunkteststestcasesgroupsfunctionsphp">trunk/tests/testcases/groups/functions.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkbpgroupsbpgroupscachephp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-cache.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-cache.php      2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/bp-groups/bp-groups-cache.php 2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -64,8 +64,7 @@
</span><span class="cx">  * @param int $group_id The group being edited.
</span><span class="cx">  */
</span><span class="cx"> function bp_groups_delete_group_cache( $group_id = 0 ) {
</span><del>-       wp_cache_delete( 'bp_groups_group_' . $group_id . '_load_users', 'bp' );
-       wp_cache_delete( 'bp_groups_group_' . $group_id . '_noload_users', 'bp' );
</del><ins>+        wp_cache_delete( $group_id, 'bp_groups' );
</ins><span class="cx"> }
</span><span class="cx"> add_action( 'groups_delete_group',     'bp_groups_delete_group_cache' );
</span><span class="cx"> add_action( 'groups_update_group',     'bp_groups_delete_group_cache' );
</span><span class="lines">@@ -78,8 +77,7 @@
</span><span class="cx">  * @since BuddyPress (2.0.0)
</span><span class="cx">  */
</span><span class="cx"> function bp_groups_delete_group_cache_on_metadata_change( $meta_id, $group_id ) {
</span><del>-       wp_cache_delete( 'bp_groups_group_' . $group_id . '_load_users', 'bp' );
-       wp_cache_delete( 'bp_groups_group_' . $group_id . '_noload_users', 'bp' );
</del><ins>+        wp_cache_delete( $group_id, 'bp_groups' );
</ins><span class="cx"> }
</span><span class="cx"> add_action( 'updated_group_meta', 'bp_groups_delete_group_cache_on_metadata_change', 10, 2 );
</span><span class="cx"> add_action( 'added_group_meta', 'bp_groups_delete_group_cache_on_metadata_change', 10, 2 );
</span></span></pre></div>
<a id="trunkbpgroupsbpgroupsclassesphp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-classes.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-classes.php    2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/bp-groups/bp-groups-classes.php       2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -176,23 +176,50 @@
</span><span class="cx">  public function populate() {
</span><span class="cx">          global $wpdb, $bp;
</span><span class="cx"> 
</span><del>-               if ( $group = $wpdb->get_row( $wpdb->prepare( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id = %d", $this->id ) ) ) {
-                       $this->id                 = $group->id;
-                       $this->creator_id         = $group->creator_id;
-                       $this->name               = stripslashes($group->name);
-                       $this->slug               = $group->slug;
-                       $this->description        = stripslashes($group->description);
-                       $this->status             = $group->status;
-                       $this->enable_forum       = $group->enable_forum;
-                       $this->date_created       = $group->date_created;
</del><ins>+                $group = wp_cache_get( $this->id, 'bp_groups' );
+               if ( false === $group ) {
+                       $group = $wpdb->get_row( $wpdb->prepare( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id = %d", $this->id ) );
</ins><span class="cx"> 
</span><ins>+                       if ( empty( $group ) ) {
+                               $this->id = 0;
+                               return;
+                       }
+
+                       $this->id           = $group->id;
+                       $this->creator_id   = $group->creator_id;
+                       $this->name         = stripslashes( $group->name );
+                       $this->slug         = $group->slug;
+                       $this->description  = stripslashes( $group->description );
+                       $this->status       = $group->status;
+                       $this->enable_forum = $group->enable_forum;
+                       $this->date_created = $group->date_created;
+
</ins><span class="cx">                   if ( ! empty( $this->args['populate_extras'] ) ) {
</span><span class="cx">                          $this->last_activity      = groups_get_groupmeta( $this->id, 'last_activity' );
</span><span class="cx">                          $this->total_member_count = groups_get_groupmeta( $this->id, 'total_member_count' );
</span><del>-                               $this->is_member          = BP_Groups_Member::check_is_member( bp_loggedin_user_id(), $this->id );
-                               $this->is_invited         = BP_Groups_Member::check_has_invite( bp_loggedin_user_id(), $this->id );
-                               $this->is_pending         = BP_Groups_Member::check_for_membership_request( bp_loggedin_user_id(), $this->id );
</del><span class="cx"> 
</span><ins>+                               // Get group admins and mods
+                               $admin_mods = $wpdb->get_results( apply_filters( 'bp_group_admin_mods_user_join_filter', $wpdb->prepare( "SELECT u.ID as user_id, u.user_login, u.user_email, u.user_nicename, m.is_admin, m.is_mod FROM {$wpdb->users} u, {$bp->groups->table_name_members} m WHERE u.ID = m.user_id AND m.group_id = %d AND ( m.is_admin = 1 OR m.is_mod = 1 )", $this->id ) ) );
+
+                               foreach ( (array) $admin_mods as $user ) {
+                                       if ( (int) $user->is_admin ) {
+                                               $this->admins[] = $user;
+                                       } else {
+                                               $this->mods[] = $user;
+                                       }
+                               }
+
+                               // Cache general (non-user-specific)
+                               // information about the group
+                               wp_cache_set( $this->id, $this, 'bp_groups' );
+                       }
+
+                       // Set user-specific data
+                       if ( ! empty( $this->args['populate_extras'] ) ) {
+                               $this->is_member  = BP_Groups_Member::check_is_member( bp_loggedin_user_id(), $this->id );
+                               $this->is_invited = BP_Groups_Member::check_has_invite( bp_loggedin_user_id(), $this->id );
+                               $this->is_pending = BP_Groups_Member::check_for_membership_request( bp_loggedin_user_id(), $this->id );
+
</ins><span class="cx">                           // If this is a private or hidden group, does the current user have access?
</span><span class="cx">                          if ( 'private' == $this->status || 'hidden' == $this->status ) {
</span><span class="cx">                                  if ( $this->is_member && is_user_logged_in() || bp_current_user_can( 'bp_moderate' ) )
</span><span class="lines">@@ -202,18 +229,7 @@
</span><span class="cx">                          } else {
</span><span class="cx">                                  $this->user_has_access = true;
</span><span class="cx">                          }
</span><del>-
-                               // Get group admins and mods
-                               $admin_mods = $wpdb->get_results( apply_filters( 'bp_group_admin_mods_user_join_filter', $wpdb->prepare( "SELECT u.ID as user_id, u.user_login, u.user_email, u.user_nicename, m.is_admin, m.is_mod FROM {$wpdb->users} u, {$bp->groups->table_name_members} m WHERE u.ID = m.user_id AND m.group_id = %d AND ( m.is_admin = 1 OR m.is_mod = 1 )", $this->id ) ) );
-                               foreach( (array) $admin_mods as $user ) {
-                                       if ( (int) $user->is_admin )
-                                               $this->admins[] = $user;
-                                       else
-                                               $this->mods[] = $user;
-                               }
</del><span class="cx">                   }
</span><del>-               } else {
-                       $this->id = 0;
</del><span class="cx">           }
</span><span class="cx">  }
</span><span class="cx"> 
</span><span class="lines">@@ -288,7 +304,7 @@
</span><span class="cx"> 
</span><span class="cx">          do_action_ref_array( 'groups_group_after_save', array( &$this ) );
</span><span class="cx"> 
</span><del>-               wp_cache_delete( 'bp_groups_group_' . $this->id, 'bp' );
</del><ins>+                wp_cache_delete( $this->id, 'bp_groups' );
</ins><span class="cx"> 
</span><span class="cx">          return true;
</span><span class="cx">  }
</span><span class="lines">@@ -316,7 +332,7 @@
</span><span class="cx"> 
</span><span class="cx">          do_action_ref_array( 'bp_groups_delete_group', array( &$this, $user_ids ) );
</span><span class="cx"> 
</span><del>-               wp_cache_delete( 'bp_groups_group_' . $this->id, 'bp' );
</del><ins>+                wp_cache_delete( $this->id, 'bp_groups' );
</ins><span class="cx"> 
</span><span class="cx">          // Finally remove the group entry from the DB
</span><span class="cx">          if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name} WHERE id = %d", $this->id ) ) )
</span></span></pre></div>
<a id="trunkbpgroupsbpgroupsfunctionsphp"></a>
<div class="modfile"><h4>Modified: trunk/bp-groups/bp-groups-functions.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/bp-groups/bp-groups-functions.php  2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/bp-groups/bp-groups-functions.php     2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -40,26 +40,18 @@
</span><span class="cx">  * @return BP_Groups_Group $group The group object
</span><span class="cx">  */
</span><span class="cx"> function groups_get_group( $args = '' ) {
</span><del>-       $defaults = array(
</del><ins>+        $r = wp_parse_args( $args, array(
</ins><span class="cx">           'group_id'          => false,
</span><span class="cx">          'load_users'        => false,
</span><span class="cx">          'populate_extras'   => true,
</span><ins>+       ) );
+
+       $group_args = array(
+               'populate_extras' => $r['populate_extras'],
</ins><span class="cx">   );
</span><span class="cx"> 
</span><del>-       $args = wp_parse_args( $args, $defaults );
-       extract( $args, EXTR_SKIP );
</del><ins>+        $group = new BP_Groups_Group( $r['group_id'], $group_args );
</ins><span class="cx"> 
</span><del>-       $cache_key = 'bp_groups_group_' . $group_id . ( $load_users ? '_load_users' : '_noload_users' );
-
-       if ( !$group = wp_cache_get( $cache_key, 'bp' ) ) {
-               $group_args = array(
-                       'populate_extras'   => $populate_extras,
-               );
-
-               $group = new BP_Groups_Group( $group_id, $group_args );
-               wp_cache_set( $cache_key, $group, 'bp' );
-       }
-
</del><span class="cx">   return apply_filters( 'groups_get_group', $group );
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkteststestcasesgroupscachephp"></a>
<div class="modfile"><h4>Modified: trunk/tests/testcases/groups/cache.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/testcases/groups/cache.php   2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/tests/testcases/groups/cache.php      2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -73,14 +73,14 @@
</span><span class="cx">          $g = $this->factory->group->create();
</span><span class="cx"> 
</span><span class="cx">          // Prime cache
</span><del>-               groups_get_group( array( 'group_id' => $g ) );
</del><ins>+                groups_get_group( array( 'group_id' => $g, ) );
</ins><span class="cx"> 
</span><del>-               $this->assertNotEmpty( wp_cache_get( 'bp_groups_group_' . $g . '_noload_users', 'bp' ) );
</del><ins>+                $this->assertNotEmpty( wp_cache_get( $g, 'bp_groups' ) );
</ins><span class="cx"> 
</span><span class="cx">          // Trigger flush
</span><span class="cx">          groups_update_groupmeta( $g, 'foo', 'bar' );
</span><span class="cx"> 
</span><del>-               $this->assertFalse( wp_cache_get( 'bp_groups_group_' . $g . '_noload_users', 'bp' ) );
</del><ins>+                $this->assertFalse( wp_cache_get( $g, 'bp_groups' ) );
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">  /**
</span><span class="lines">@@ -94,11 +94,11 @@
</span><span class="cx">          groups_update_groupmeta( $g, 'foo', 'bar' );
</span><span class="cx">          groups_get_group( array( 'group_id' => $g ) );
</span><span class="cx"> 
</span><del>-               $this->assertNotEmpty( wp_cache_get( 'bp_groups_group_' . $g . '_noload_users', 'bp' ) );
</del><ins>+                $this->assertNotEmpty( wp_cache_get( $g, 'bp_groups' ) );
</ins><span class="cx"> 
</span><span class="cx">          // Trigger flush
</span><span class="cx">          groups_update_groupmeta( $g, 'foo', 'baz' );
</span><del>-               $this->assertFalse( wp_cache_get( 'bp_groups_group_' . $g . '_noload_users', 'bp' ) );
</del><ins>+                $this->assertFalse( wp_cache_get( $g, 'bp_groups' ) );
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkteststestcasesgroupsclassbpgroupsgroupphp"></a>
<div class="modfile"><h4>Modified: trunk/tests/testcases/groups/class-bp-groups-group.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/testcases/groups/class-bp-groups-group.php   2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/tests/testcases/groups/class-bp-groups-group.php      2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -643,6 +643,42 @@
</span><span class="cx">  }
</span><span class="cx"> 
</span><span class="cx">  /**
</span><ins>+        * @group delete
+        * @group cache
+        */
+       public function test_delete_clear_cache() {
+               $g = $this->factory->group->create();
+
+               // Prime cache
+               groups_get_group( array( 'group_id' => $g, ) );
+
+               $this->assertNotEmpty( wp_cache_get( $g, 'bp_groups' ) );
+
+               $group = new BP_Groups_Group( $g );
+               $group->delete();
+
+               $this->assertFalse( wp_cache_get( $g, 'bp_groups' ) );
+       }
+
+       /**
+        * @group save
+        * @group cache
+        */
+       public function test_save_clear_cache() {
+               $g = $this->factory->group->create();
+
+               // Prime cache
+               groups_get_group( array( 'group_id' => $g, ) );
+
+               $this->assertNotEmpty( wp_cache_get( $g, 'bp_groups' ) );
+
+               $group = new BP_Groups_Group( $g );
+               $group->name = 'Foo';
+               $group->save();
+
+               $this->assertFalse( wp_cache_get( $g, 'bp_groups' ) );
+       }
+       /**
</ins><span class="cx">    * @group get_group_extras
</span><span class="cx">   */
</span><span class="cx">  public function test_get_group_extras_non_logged_in() {
</span></span></pre></div>
<a id="trunkteststestcasesgroupsfunctionsphp"></a>
<div class="modfile"><h4>Modified: trunk/tests/testcases/groups/functions.php (7955 => 7956)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/testcases/groups/functions.php       2014-02-21 17:51:07 UTC (rev 7955)
+++ trunk/tests/testcases/groups/functions.php  2014-02-21 17:51:10 UTC (rev 7956)
</span><span class="lines">@@ -548,4 +548,28 @@
</span><span class="cx">          groups_add_groupmeta( $g, 'foo', 'bar' );
</span><span class="cx">          $this->assertNotEmpty( groups_add_groupmeta( $g, 'foo', 'baz' ) );
</span><span class="cx">  }
</span><ins>+
+       /**
+        * @group groups_get_group
+        * @group cache
+        */
+       public function test_groups_get_group_cache_different_users() {
+               $g = $this->factory->group->create();
+               $u1 = $this->create_user();
+               $u2 = $this->create_user();
+               $this->add_user_to_group( $u1, $g );
+
+               $old_user = get_current_user_id();
+               $this->set_current_user( $u1 );
+
+               $group1 = groups_get_group( array( 'group_id' => $g, ) );
+
+               $this->set_current_user( $u2 );
+
+               $group2 = groups_get_group( array( 'group_id' => $g, ) );
+
+               $this->assertNotEquals( $group1, $group2 );
+
+               $this->set_current_user( $old_user );
+       }
</ins><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>