Skip to:
Content

BuddyPress.org

Ticket #6978: 6978.4.patch

File 6978.4.patch, 23.6 KB (added by dcavins, 5 years ago)

One more place could potentially use a cached object.

  • src/bp-friends/bp-friends-cache.php

    diff --git src/bp-friends/bp-friends-cache.php src/bp-friends/bp-friends-cache.php
    index 5fb11a5..819f817 100644
    add_action( 'friends_friendship_accepted', 'friends_clear_friend_object_cache' ) 
    3535add_action( 'friends_friendship_deleted',  'friends_clear_friend_object_cache' );
    3636
    3737/**
     38 * Clear friendship caches on friendship changes.
     39 *
     40 * @since 2.7.0
     41 *
     42 * @param int $friendship_id     ID of the friendship that has changed.
     43 * @param int $initiator_user_id ID of the first user.
     44 * @param int $friend_user_id    ID of the second user.
     45 * @return bool
     46 */
     47function bp_friends_clear_bp_friends_friendships_cache( $friendship_id, $initiator_user_id, $friend_user_id ) {
     48        // Clear friendship ID cache for each user.
     49        wp_cache_delete( $initiator_user_id, 'bp_friends_friendships_for_user' );
     50        wp_cache_delete( $friend_user_id,    'bp_friends_friendships_for_user' );
     51
     52        // Clear the friendship object cache.
     53        wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
     54}
     55add_action( 'friends_friendship_requested', 'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     56add_action( 'friends_friendship_accepted',  'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     57add_action( 'friends_friendship_deleted',   'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     58
     59/**
     60 * Clear friendship caches on friendship changes.
     61 *
     62 * @since 2.7.0
     63 *
     64 * @param int                   $friendship_id The friendship ID.
     65 * @param BP_Friends_Friendship $friendship Friendship object.
     66 */
     67function bp_friends_clear_bp_friends_friendships_cache_remove( $friendship_id, BP_Friends_Friendship $friendship ) {
     68        // Clear friendship ID cache for each user.
     69        wp_cache_delete( $friendship->initiator_user_id, 'bp_friends_friendships_for_user' );
     70        wp_cache_delete( $friendship->friend_user_id,    'bp_friends_friendships_for_user' );
     71
     72        // Clear the friendship object cache.
     73        wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
     74}
     75add_action( 'friends_friendship_withdrawn', 'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
     76add_action( 'friends_friendship_rejected',  'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
     77
     78/**
    3879 * Clear the friend request cache for the user not initiating the friendship.
    3980 *
    4081 * @since 2.0.0
  • src/bp-friends/bp-friends-filters.php

    diff --git src/bp-friends/bp-friends-filters.php src/bp-friends/bp-friends-filters.php
    index 3a06422..9513b47 100644
    function bp_friends_filter_user_query_populate_extras( BP_User_Query $user_query 
    2828        global $wpdb;
    2929
    3030        // Stop if user isn't logged in.
    31         if ( ! is_user_logged_in() ) {
     31        if ( ! $user_id = bp_loggedin_user_id() ) {
    3232                return;
    3333        }
    3434
    35         $bp = buddypress();
     35        $maybe_friend_ids = wp_parse_id_list( $user_ids_sql );
    3636
    37         // Fetch whether or not the user is a friend of the current user.
    38         $friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids_sql} ) ) OR (initiator_user_id IN ( {$user_ids_sql} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
    39 
    40         // Keep track of members that have a friendship status with the current user.
    41         $friend_user_ids = array();
    42 
    43         // The "friend" is the user ID in the pair who is *not* the logged in user.
    44         foreach ( (array) $friend_status as $fs ) {
    45                 $friend_id = bp_loggedin_user_id() == $fs->initiator_user_id ? $fs->friend_user_id : $fs->initiator_user_id;
    46                 $friend_user_ids[] = $friend_id;
    47 
    48                 if ( isset( $user_query->results[ $friend_id ] ) ) {
    49                         if ( 0 == $fs->is_confirmed ) {
    50                                 $status = $fs->initiator_user_id == bp_loggedin_user_id() ? 'pending' : 'awaiting_response';
    51                         } else {
    52                                 $status = 'is_friend';
    53                         }
    54 
    55                         $user_query->results[ $friend_id ]->is_friend         = $fs->is_confirmed;
    56                         $user_query->results[ $friend_id ]->friendship_status = $status;
    57                 }
    58         }
    59 
    60         // The rest are not friends with the current user, so set status accordingly.
    61         $not_friends = array_diff( $user_query->user_ids, $friend_user_ids );
    62         foreach ( (array) $not_friends as $nf ) {
    63                 if ( bp_loggedin_user_id() == $nf ) {
    64                         continue;
    65                 }
    66 
    67                 if ( isset( $user_query->results[ $nf ] ) ) {
    68                         $user_query->results[ $nf ]->friendship_status = 'not_friends';
     37        foreach ( $maybe_friend_ids as $friend_id ) {
     38                $status = BP_Friends_Friendship::check_is_friend( $user_id, $friend_id );
     39                $user_query->results[ $friend_id ]->friendship_status = $status;
     40                if ( 'is_friend' == $status ) {
     41                        $user_query->results[ $friend_id ]->is_friend = 1;
    6942                }
    7043        }
    7144
  • src/bp-friends/classes/class-bp-friends-component.php

    diff --git src/bp-friends/classes/class-bp-friends-component.php src/bp-friends/classes/class-bp-friends-component.php
    index e066898..d6e357b 100644
    class BP_Friends_Component extends BP_Component { 
    288288
    289289                // Global groups.
    290290                wp_cache_add_global_groups( array(
    291                         'bp_friends_requests'
     291                        'bp_friends_requests',
     292                        'bp_friends_friendships', // Individual friendship objects are cached here by ID.
     293                        'bp_friends_friendships_for_user' // All friendship IDs for a single user.
    292294                ) );
    293295
    294296                parent::setup_cache_groups();
  • src/bp-friends/classes/class-bp-friends-friendship.php

    diff --git src/bp-friends/classes/class-bp-friends-friendship.php src/bp-friends/classes/class-bp-friends-friendship.php
    index e607215..01eba76 100644
    class BP_Friends_Friendship { 
    122122
    123123                $bp = buddypress();
    124124
    125                 if ( $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) ) ) {
    126                         $this->initiator_user_id = (int) $friendship->initiator_user_id;
    127                         $this->friend_user_id    = (int) $friendship->friend_user_id;
    128                         $this->is_confirmed      = (int) $friendship->is_confirmed;
    129                         $this->is_limited        = (int) $friendship->is_limited;
    130                         $this->date_created      = $friendship->date_created;
     125                // Check cache for friendship data.
     126                $friendship = wp_cache_get( $this->id, 'bp_friends_friendships' );
     127
     128                // Cache missed, so query the DB.
     129                if ( false === $friendship ) {
     130                        $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) );
     131
     132                        wp_cache_set( $this->id, $friendship, 'bp_friends_friendships' );
     133                }
     134
     135                // No friendship found so set the ID and bail.
     136                if ( empty( $friendship ) || is_wp_error( $friendship ) ) {
     137                        $this->id = 0;
     138                        return;
    131139                }
    132140
    133                 if ( !empty( $this->populate_friend_details ) ) {
     141                $this->initiator_user_id = (int) $friendship->initiator_user_id;
     142                $this->friend_user_id    = (int) $friendship->friend_user_id;
     143                $this->is_confirmed      = (int) $friendship->is_confirmed;
     144                $this->is_limited        = (int) $friendship->is_limited;
     145                $this->date_created      = $friendship->date_created;
     146
     147                if ( ! empty( $this->populate_friend_details ) ) {
    134148                        if ( $this->friend_user_id == bp_displayed_user_id() ) {
    135149                                $this->friend = new BP_Core_User( $this->initiator_user_id );
    136150                        } else {
    class BP_Friends_Friendship { 
    206220        /** Static Methods ********************************************************/
    207221
    208222        /**
     223         * Get the friendships for a given user.
     224         *
     225         * @since 2.6.0
     226         *
     227         * @param int   $user_id              ID of the user whose friends are being retrieved.
     228         * @param array $args {
     229         *        Optional. Filter parameters.
     230         *        @type int    $id                ID of specific friendship to retrieve.
     231         *        @type int    $initiator_user_id ID of friendship initiator.
     232         *        @type int    $friend_user_id    ID of specific friendship to retrieve.
     233         *        @type int    $is_confirmed      Whether the friendship has been accepted.
     234         *        @type int    $is_limited        Whether the friendship is limited.
     235         *        @type string $order_by          Column name to order by.
     236         *        @type string $sort_order        ASC or DESC. Default DESC.
     237         * }
     238         * @param string $operator            Optional. Operator to use in `wp_list_filter()`.
     239         *
     240         * @return array $friendships Array of friendship objects.
     241         */
     242        public static function get_friendships( $user_id, $args = array(), $operator = 'AND' ) {
     243
     244                if ( empty( $user_id ) ) {
     245                        $user_id = bp_loggedin_user_id();
     246                }
     247
     248                $r = bp_parse_args( $args, array(
     249                        'id'                => null,
     250                        'initiator_user_id' => null,
     251                        'friend_user_id'    => null,
     252                        'is_confirmed'      => null,
     253                        'is_limited'        => null,
     254                        'order_by'          => 'date_created',
     255                        'sort_order'        => 'DESC',
     256                        'page'              => null,
     257                        'per_page'          => null
     258                ), 'bp_get_user_friendships' );
     259
     260                // First, we get all friendships that involve the user.
     261                $friendship_ids = wp_cache_get( $user_id, 'bp_friends_friendships_for_user' );
     262                if ( false === $friendship_ids ) {
     263                        $friendship_ids = self::get_friendship_ids_for_user( $user_id );
     264                        wp_cache_set( $user_id, $friendship_ids, 'bp_friends_friendships_for_user' );
     265                }
     266
     267                // Prime the membership cache.
     268                $uncached_friendship_ids = bp_get_non_cached_ids( $friendship_ids, 'bp_friends_friendships' );
     269                if ( ! empty( $uncached_friendship_ids ) ) {
     270                        $uncached_friendships = self::get_friendships_by_id( $uncached_friendship_ids );
     271
     272                        foreach ( $uncached_friendships as $uncached_friendship ) {
     273                                wp_cache_set( $uncached_friendship->id, $uncached_friendship, 'bp_friends_friendships' );
     274                        }
     275                }
     276
     277                // Assemble filter array.
     278                $filters = wp_array_slice_assoc( $r, array( 'id', 'initiator_user_id', 'friend_user_id', 'is_confirmed', 'is_limited' ) );
     279                foreach ( $filters as $filter_name => $filter_value ) {
     280                        if ( is_null( $filter_value ) ) {
     281                                unset( $filters[ $filter_name ] );
     282                        }
     283                }
     284
     285                // Populate friendship array from cache, and normalize.
     286                $friendships = array();
     287                $int_keys    = array( 'id', 'initiator_user_id', 'friend_user_id' );
     288                $bool_keys   = array( 'is_confirmed', 'is_limited' );
     289                foreach ( $friendship_ids as $friendship_id ) {
     290                        // Create a limited BP_Friends_Friendship object (don't fetch the user details).
     291                        $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
     292
     293                        // Sanity check.
     294                        if ( ! isset( $friendship->id ) ) {
     295                                continue;
     296                        }
     297
     298                        // Integer values.
     299                        foreach ( $int_keys as $index ) {
     300                                $friendship->{$index} = intval( $friendship->{$index} );
     301                        }
     302
     303                        // Boolean values.
     304                        foreach ( $bool_keys as $index ) {
     305                                $friendship->{$index} = (bool) $friendship->{$index};
     306                        }
     307
     308                        // We need to support the same operators as wp_list_filter().
     309                        if ( 'OR' == $operator || 'NOT' == $operator ) {
     310                                $matched = 0;
     311
     312                                foreach ( $filters as $filter_name => $filter_value ) {
     313                                        if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) {
     314                                                $matched++;
     315                                        }
     316                                }
     317
     318                                if ( ( 'OR' == $operator && $matched > 0 )
     319                                  || ( 'NOT' == $operator && 0 == $matched ) ) {
     320                                        $friendships[ $friendship->id ] = $friendship;
     321                                }
     322
     323                        } else {
     324                                /*
     325                                 * This is the more typical 'AND' style of filter.
     326                                 * If any of the filters miss, we move on.
     327                                 */
     328                                foreach ( $filters as $filter_name => $filter_value ) {
     329                                        if ( ! isset( $friendship->{$filter_name} ) || $filter_value != $friendship->{$filter_name} ) {
     330                                                continue 2;
     331                                        }
     332                                }
     333                                $friendships[ $friendship->id ] = $friendship;
     334                        }
     335
     336                }
     337
     338                // Sort the results on a column name.
     339                if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) {
     340                        $friendships = bp_sort_by_key( $friendships, $r['order_by'], 'num', true );
     341                }
     342
     343                // Adjust the sort direction of the results.
     344                if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
     345                        // `true` to preserve keys.
     346                        $friendships = array_reverse( $friendships, true );
     347                }
     348
     349                // Paginate the results.
     350                if ( $r['per_page'] && $r['page'] ) {
     351                        $start       = ( $r['page'] - 1 ) * ( $r['per_page'] );
     352                        $friendships = array_slice( $friendships, $start, $r['per_page'] );
     353                }
     354
     355                return $friendships;
     356        }
     357
     358        /**
     359         * Get all friendship IDs for a user.
     360         *
     361         * @since 2.7.0
     362         *
     363         * @param int $user_id ID of the user.
     364         * @return array
     365         */
     366        public static function get_friendship_ids_for_user( $user_id ) {
     367                global $wpdb;
     368
     369                $bp = buddypress();
     370
     371                $friendship_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) ORDER BY date_created DESC", $user_id, $user_id ) );
     372
     373                return $friendship_ids;
     374        }
     375
     376        /**
    209377         * Get the IDs of a given user's friends.
    210378         *
    211379         * @since 1.0.0
    class BP_Friends_Friendship { 
    221389        public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
    222390                global $wpdb;
    223391
    224                 if ( !empty( $friend_requests_only ) ) {
    225                         $oc_sql = 'AND is_confirmed = 0';
    226                         $friend_sql = $wpdb->prepare( " WHERE friend_user_id = %d", $user_id );
     392                if ( ! empty( $friend_requests_only ) ) {
     393                        $args = array(
     394                                'is_confirmed' => 0,
     395                                'friend_user_id' => $user_id
     396                        );
    227397                } else {
    228                         $oc_sql = 'AND is_confirmed = 1';
    229                         $friend_sql = $wpdb->prepare( " WHERE (initiator_user_id = %d OR friend_user_id = %d)", $user_id, $user_id );
     398                        $args = array(
     399                                'is_confirmed' => 1,
     400                        );
    230401                }
    231402
    232                 $bp = buddypress();
    233                 $friends = $wpdb->get_results( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} {$friend_sql} {$oc_sql} ORDER BY date_created DESC" );
    234                 $fids = array();
     403                $friendships = self::get_friendships( $user_id, $args );
    235404
    236                 for ( $i = 0, $count = count( $friends ); $i < $count; ++$i ) {
    237                         if ( !empty( $assoc_arr ) ) {
    238                                 $fids[] = array( 'user_id' => ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id );
     405                $fids = array();
     406                foreach ( $friendships as $friendship ) {
     407                        if ( ! empty( $assoc_arr ) ) {
     408                                $fids[] = array( 'user_id' => ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id );
    239409                        } else {
    240                                 $fids[] = ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id;
     410                                $fids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
    241411                        }
    242412                }
    243413
    class BP_Friends_Friendship { 
    254424         * @return int|null The ID of the friendship object if found, otherwise null.
    255425         */
    256426        public static function get_friendship_id( $user_id, $friend_id ) {
    257                 global $wpdb;
    258 
    259                 $bp = buddypress();
     427                $friendship_id = null;
    260428
    261                 $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE ( initiator_user_id = %d AND friend_user_id = %d ) OR ( initiator_user_id = %d AND friend_user_id = %d ) AND is_confirmed = 1", $user_id, $friend_id, $friend_id, $user_id ) );
     429                // Can't friend yourself.
     430                if ( $user_id == $friend_id ) {
     431                        return $friendship_id;
     432                }
    262433
    263                 return is_numeric( $query ) ? (int) $query : $query;
     434                /*
     435                 * Find friendships where the possible_friend_userid is the
     436                 * initiator or friend.
     437                 */
     438                $args = array(
     439                        'initiator_user_id' => $friend_id,
     440                        'friend_user_id'    => $friend_id
     441                );
     442                $result = self::get_friendships( $user_id, $args, 'OR' );
     443                if ( $result ) {
     444                        $friendship_id = current( $result )->id;
     445                }
     446                return $friendship_id;
    264447        }
    265448
    266449        /**
    class BP_Friends_Friendship { 
    276459                $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' );
    277460
    278461                if ( false === $friend_requests ) {
    279                         global $wpdb;
    280 
    281                         $bp = buddypress();
    282 
    283                         $friend_requests = $wpdb->get_col( $wpdb->prepare( "SELECT initiator_user_id FROM {$bp->friends->table_name} WHERE friend_user_id = %d AND is_confirmed = 0", $user_id ) );
     462                        //@TODO: this uses already cached data, so maybe `bp_friends_requests` should go away?
     463                        $friend_requests = self::get_friend_user_ids( $user_id, true );
    284464
    285465                        wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' );
    286466                }
    class BP_Friends_Friendship { 
    306486        public static function total_friend_count( $user_id = 0 ) {
    307487                global $wpdb;
    308488
    309                 if ( empty( $user_id ) )
     489                if ( empty( $user_id ) ) {
    310490                        $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
    311 
    312                 $bp = buddypress();
     491                }
    313492
    314493                /*
    315494                 * This is stored in 'total_friend_count' usermeta.
    316495                 * This function will recalculate, update and return.
    317496                 */
    318497
    319                 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) AND is_confirmed = 1", $user_id, $user_id ) );
     498                $args = array(
     499                        'is_confirmed' => 1,
     500                );
     501                $friendships = self::get_friendships( $user_id, $args );
     502                $count       = count( $friendships );
    320503
    321504                // Do not update meta if user has never had friends.
    322                 if ( empty( $count ) && !bp_get_user_meta( $user_id, 'total_friend_count', true ) )
     505                if ( ! $count && ! bp_get_user_meta( $user_id, 'total_friend_count', true ) ) {
    323506                        return 0;
     507                }
    324508
    325509                bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
    326510
    class BP_Friends_Friendship { 
    415599                        return false;
    416600                }
    417601
    418                 $bp = buddypress();
    419 
    420                 $result = $wpdb->get_results( $wpdb->prepare( "SELECT id, initiator_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id = %d) OR (initiator_user_id = %d AND friend_user_id = %d)", $initiator_userid, $possible_friend_userid, $possible_friend_userid, $initiator_userid ) );
     602                // Can't friend yourself.
     603                if ( $initiator_userid == $possible_friend_userid ) {
     604                        return 'not_friends';
     605                }
    421606
    422                 if ( ! empty( $result ) ) {
    423                         if ( 0 == (int) $result[0]->is_confirmed ) {
    424                                 $status = $initiator_userid == $result[0]->initiator_user_id ? 'pending' : 'awaiting_response';
     607                /*
     608                 * Find friendships where the possible_friend_userid is the
     609                 * initiator or friend.
     610                 */
     611                $args = array(
     612                        'initiator_user_id' => $possible_friend_userid,
     613                        'friend_user_id'    => $possible_friend_userid
     614                );
     615                $result = self::get_friendships( $initiator_userid, $args, 'OR' );
     616
     617                if ( $result ) {
     618                        $friendship = current( $result );
     619                        if ( ! $friendship->is_confirmed ) {
     620                                $status = $initiator_userid == $friendship->initiator_user_id ? 'pending' : 'awaiting_response';
    425621                        } else {
    426622                                $status = 'is_friend';
    427623                        }
    class BP_Friends_Friendship { 
    699895        }
    700896
    701897        /**
     898         * Get friendship objects by ID (or an array of IDs).
     899         *
     900         * @since 2.7.0
     901         *
     902         * @param int|string|array $friendship_ids Single friendship ID or comma-separated/array list of friendship IDs.
     903         * @return array
     904         */
     905        public static function get_friendships_by_id( $friendship_ids ) {
     906                global $wpdb;
     907
     908                $bp = buddypress();
     909
     910                $friendship_ids = implode( ',', wp_parse_id_list( $friendship_ids ) );
     911                return $wpdb->get_results( "SELECT * FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids})" );
     912        }
     913
     914        /**
    702915         * Get the friend user IDs for a given friendship.
    703916         *
    704917         * @since 1.0.0
    class BP_Friends_Friendship { 
    707920         * @return object friend_user_id and initiator_user_id.
    708921         */
    709922        public static function get_user_ids_for_friendship( $friendship_id ) {
    710                 global $wpdb;
    711923
    712                 $bp = buddypress();
     924                $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
     925
     926                if ( empty( $friendship->id ) ) {
     927                        return null;
     928                }
     929
     930                $retval = new StdClass;
     931                $retval->friend_user_id = $friendship->friend_user_id;
     932                $retval->initiator_user_id = $friendship->initiator_user_id;
    713933
    714                 return $wpdb->get_row( $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE id = %d", $friendship_id ) );
     934                return $retval;
    715935        }
    716936
    717937        /**
    class BP_Friends_Friendship { 
    726946
    727947                $bp = buddypress();
    728948
    729                 // Get friends of $user_id.
    730                 $friend_ids = BP_Friends_Friendship::get_friend_user_ids( $user_id );
     949                // Get all friendships, of any status, for the user.
     950                $friendships    = self::get_friendships( $user_id );
     951                $friend_ids     = array();
     952                $friendship_ids = array();
     953                foreach ( $friendships as $friendship ) {
     954                        $friendship_ids[] = $friendship->id;
     955                        if ( $friendship->is_confirmed ) {
     956                                $friend_ids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
     957                        }
     958                }
    731959
    732                 // Delete all friendships related to $user_id.
    733                 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE friend_user_id = %d OR initiator_user_id = %d", $user_id, $user_id ) );
     960                // Delete the friendships from the database.
     961                if ( $friendship_ids ) {
     962                        $friendship_ids_sql = implode( ',', wp_parse_id_list( $friendship_ids ) );
     963                        $wpdb->query( "DELETE FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids_sql})" );
     964                }
    734965
    735966                // Delete friend request notifications for members who have a
    736967                // notification from this user.
    class BP_Friends_Friendship { 
    738969                        $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE component_name = 'friends' AND ( component_action = 'friendship_request' OR component_action = 'friendship_accepted' ) AND item_id = %d", $user_id ) );
    739970                }
    740971
    741                 // Loop through friend_ids and update their counts.
     972                // Clean up the friendships cache.
     973                foreach ( $friendship_ids as $friendship_id ) {
     974                        wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
     975                }
     976
     977                // Loop through friend_ids to scrub user caches and update total count metas.
    742978                foreach ( (array) $friend_ids as $friend_id ) {
     979                        // Delete cached friendships.
     980                        wp_cache_delete( $friend_id, 'bp_friends_friendships_for_user' );
    743981                        BP_Friends_Friendship::total_friend_count( $friend_id );
    744982                }
     983
     984                // Delete cached friendships.
     985                wp_cache_delete( $user_id, 'bp_friends_friendships_for_user' );
    745986        }
    746987}
  • tests/phpunit/testcases/friends/functions.php

    diff --git tests/phpunit/testcases/friends/functions.php tests/phpunit/testcases/friends/functions.php
    index bd9c148..8c41570 100644
    class BP_Tests_Friends_Functions extends BP_UnitTestCase { 
    267267                $this->filter_fired = current_filter();
    268268                return $value;
    269269        }
     270
     271        /**
     272         * @group friendship_caching
     273         */
     274        public function test_friends_check_friendship_should_hit_user_cache() {
     275                global $wpdb;
     276                $now = time();
     277                $u1 = $this->factory->user->create( array(
     278                        'last_activity' => date( 'Y-m-d H:i:s', $now ),
     279                ) );
     280                $u2 = $this->factory->user->create( array(
     281                        'last_activity' => date( 'Y-m-d H:i:s', $now - 100 ),
     282                ) );
     283                $u3 = $this->factory->user->create( array(
     284                        'last_activity' => date( 'Y-m-d H:i:s', $now - 200 ),
     285                ) );
     286
     287                friends_add_friend( $u1, $u2, true );
     288                friends_add_friend( $u1, $u3, false );
     289
     290                friends_check_friendship_status( $u1, $u2 );
     291                $first_query_count = $wpdb->num_queries;
     292
     293                friends_check_friendship_status( $u1, $u3 );
     294
     295                $this->assertEquals( $first_query_count, $wpdb->num_queries );
     296        }
     297
     298        /**
     299         * @group friendship_caching
     300         */
     301        public function test_friends_check_friendship_should_hit_friendship_object_cache() {
     302                global $wpdb;
     303                $now = time();
     304                $u1 = $this->factory->user->create( array(
     305                        'last_activity' => date( 'Y-m-d H:i:s', $now ),
     306                ) );
     307                $u2 = $this->factory->user->create( array(
     308                        'last_activity' => date( 'Y-m-d H:i:s', $now - 100 ),
     309                ) );
     310
     311                friends_add_friend( $u1, $u2, true );
     312
     313                friends_check_friendship_status( $u1, $u2 );
     314                $first_query_count = $wpdb->num_queries;
     315
     316                /*
     317                 * We expect this to generate one query to find $u2's friendships,
     318                 * but the friendship object itself should come from cache.
     319                 */
     320                friends_check_friendship_status( $u2, $u1 );
     321
     322                $this->assertEquals( $first_query_count + 1, $wpdb->num_queries );
     323        }
    270324}