<!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][8537] trunk: Groups: Cache calls to BP_Groups_Member::get_group_administrator_ids()</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/8537">8537</a></dd>
<dt>Author</dt> <dd>r-a-y</dd>
<dt>Date</dt> <dd>2014-06-16 20:19:57 +0000 (Mon, 16 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Groups: Cache calls to BP_Groups_Member::get_group_administrator_ids()

When a logged-in user is viewing the group directory and is a member of
each group in the loop, when rendering the "Leave Group" button, a call
is done to fetch the group admins of each group to determine whether the
user is the sole admin.

Since this query is uncached, this could lead to twenty additional DB
queries being run on the page.  Thus, this commit caches this query and
invalidates the cache whenever a group member is promoted / demoted or
saved into the database.

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

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcbpgroupsbpgroupscachephp">trunk/src/bp-groups/bp-groups-cache.php</a></li>
<li><a href="#trunksrcbpgroupsbpgroupsclassesphp">trunk/src/bp-groups/bp-groups-classes.php</a></li>
<li><a href="#trunktestsphpunittestcasesgroupscachephp">trunk/tests/phpunit/testcases/groups/cache.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcbpgroupsbpgroupscachephp"></a>
<div class="modfile"><h4>Modified: trunk/src/bp-groups/bp-groups-cache.php (8536 => 8537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/bp-groups/bp-groups-cache.php  2014-06-16 20:11:55 UTC (rev 8536)
+++ trunk/src/bp-groups/bp-groups-cache.php     2014-06-16 20:19:57 UTC (rev 8537)
</span><span class="lines">@@ -173,6 +173,35 @@
</span><span class="cx"> add_action( 'groups_uninvite_user', 'groups_clear_group_user_object_cache', 10, 2 );
</span><span class="cx"> add_action( 'groups_remove_member', 'groups_clear_group_user_object_cache', 10, 2 );
</span><span class="cx"> 
</span><ins>+/**
+ * Clear group administrator cache.
+ *
+ * @since BuddyPress (2.1.0)
+ *
+ * @param int $group_id The group ID.
+ */
+function groups_clear_group_administrator_cache( $group_id ) {
+       wp_cache_delete( $group_id, 'bp_group_admins' );
+}
+add_action( 'groups_promote_member', 'groups_clear_group_administrator_cache' );
+add_action( 'groups_demote_member',  'groups_clear_group_administrator_cache' );
+add_action( 'groups_delete_group',   'groups_clear_group_administrator_cache' );
+
+/**
+ * Clear group administrator cache when a group member is saved.
+ *
+ * This accounts for situations where group administrators are added manually
+ * using {@link BP_Groups_Member::save()}.  Usually via a plugin.
+ *
+ * @since BuddyPress (2.1.0)
+ *
+ * @param BP_Groups_Member $member
+ */
+function groups_clear_group_administrator_cache_on_member_save( BP_Groups_Member $member ) {
+       groups_clear_group_administrator_cache( $member->group_id );
+}
+add_action( 'groups_member_after_save', 'groups_clear_group_administrator_cache_on_member_save' );
+
</ins><span class="cx"> /* List actions to clear super cached pages on, if super cache is installed */
</span><span class="cx"> add_action( 'groups_join_group',                 'bp_core_clear_cache' );
</span><span class="cx"> add_action( 'groups_leave_group',                'bp_core_clear_cache' );
</span></span></pre></div>
<a id="trunksrcbpgroupsbpgroupsclassesphp"></a>
<div class="modfile"><h4>Modified: trunk/src/bp-groups/bp-groups-classes.php (8536 => 8537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/bp-groups/bp-groups-classes.php        2014-06-16 20:11:55 UTC (rev 8536)
+++ trunk/src/bp-groups/bp-groups-classes.php   2014-06-16 20:19:57 UTC (rev 8537)
</span><span class="lines">@@ -2626,7 +2626,15 @@
</span><span class="cx">  public static function get_group_administrator_ids( $group_id ) {
</span><span class="cx">          global $bp, $wpdb;
</span><span class="cx"> 
</span><del>-               return $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_admin = 1 AND is_banned = 0", $group_id ) );
</del><ins>+                $group_admins = wp_cache_get( $group_id, 'bp_group_admins' );
+
+               if ( false === $group_admins ) {
+                       $group_admins = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_admin = 1 AND is_banned = 0", $group_id ) );
+
+                       wp_cache_set( $group_id, $group_admins, 'bp_group_admins' );
+               }
+
+               return $group_admins;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">  /**
</span></span></pre></div>
<a id="trunktestsphpunittestcasesgroupscachephp"></a>
<div class="modfile"><h4>Modified: trunk/tests/phpunit/testcases/groups/cache.php (8536 => 8537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/phpunit/testcases/groups/cache.php   2014-06-16 20:11:55 UTC (rev 8536)
+++ trunk/tests/phpunit/testcases/groups/cache.php      2014-06-16 20:19:57 UTC (rev 8537)
</span><span class="lines">@@ -154,4 +154,47 @@
</span><span class="cx">          $this->assertNotEmpty( wp_cache_get( $g1, 'bp_groups' ) );
</span><span class="cx">          $this->assertNotEmpty( wp_cache_get( $g2, 'bp_groups' ) );
</span><span class="cx">  }
</span><ins>+
+       /**
+        * @group groups_get_group_admins
+        */
+       public function test_groups_get_group_admins_cache() {
+               $u1 = $this->create_user();
+               $u2 = $this->create_user();
+               $g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+
+               // prime cache
+               groups_get_group_admins( $g );
+
+               // promote user 2 to an admin
+               bp_update_is_item_admin( true );
+               groups_promote_member( $u2, $g, 'admin' );
+
+               // assert that cache is invalidated
+               $this->assertEmpty( wp_cache_get( $g, 'bp_group_admins' ) );
+
+               // assert new cached value
+               $this->assertEquals( 2, count( groups_get_group_admins( $g ) ) );
+       }
+
+       /**
+        * @group groups_get_group_admins
+        */
+       public function test_groups_get_group_admins_cache_on_member_save() {
+               $u1 = $this->create_user();
+               $u2 = $this->create_user();
+               $g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+
+               // prime cache
+               groups_get_group_admins( $g );
+
+               // promote user 2 to an admin via BP_Groups_Member::save()
+               self::add_user_to_group( $u2, $g, array( 'is_admin' => 1 ) );
+
+               // assert that cache is invalidated
+               $this->assertEmpty( wp_cache_get( $g, 'bp_group_admins' ) );
+
+               // assert new cached value
+               $this->assertEquals( 2, count( groups_get_group_admins( $g ) ) );
+       }
</ins><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>