Skip to:
Content

BuddyPress.org

Ticket #6978: 6978.caching.01.patch

File 6978.caching.01.patch, 16.4 KB (added by dcavins, 5 years ago)

Cache a user's friendships.

  • 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..b4ac52e 100644
    function friends_clear_friend_object_cache( $friendship_id ) { 
    2626        if ( !$friendship = new BP_Friends_Friendship( $friendship_id ) )
    2727                return false;
    2828
     29        // @TODO: This is a cached set of random friends. Which is a weird thing to cache. Remove?
    2930        wp_cache_delete( 'friends_friend_ids_' .    $friendship->initiator_user_id, 'bp' );
    3031        wp_cache_delete( 'friends_friend_ids_' .    $friendship->friend_user_id,    'bp' );
    3132}
    add_action( 'friends_friendship_accepted', 'friends_clear_friend_object_cache' ) 
    3536add_action( 'friends_friendship_deleted',  'friends_clear_friend_object_cache' );
    3637
    3738/**
     39 * Clear friendship caches on friendship changes.
     40 *
     41 * @since 2.6.0
     42 *
     43 * @param int $friendship_id     ID of the friendship that has changed.
     44 * @param int $initiator_user_id ID of the first user.
     45 * @param int $friend_user_id    ID of the second user.
     46 * @return bool
     47 */
     48function bp_friends_clear_bp_friends_friendships_cache( $friendship_id, $initiator_user_id, $friend_user_id ) {
     49        wp_cache_delete( $initiator_user_id, 'bp_friends_friendships' );
     50        wp_cache_delete( $friend_user_id,    'bp_friends_friendships' );
     51}
     52add_action( 'friends_friendship_requested', 'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     53add_action( 'friends_friendship_accepted',  'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     54add_action( 'friends_friendship_deleted',   'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
     55
     56/**
     57 * Clear friendship caches on friendship changes.
     58 *
     59 * @since 2.6.0
     60 *
     61 * @param int                   $friendship_id The friendship ID.
     62 * @param BP_Friends_Friendship $friendship Friendship object.
     63 */
     64function bp_friends_clear_bp_friends_friendships_cache_remove( $friendship_id, BP_Friends_Friendship $friendship ) {
     65        wp_cache_delete( $friendship->initiator_user_id, 'bp_friends_friendships' );
     66        wp_cache_delete( $friendship->friend_user_id,    'bp_friends_friendships' );
     67}
     68add_action( 'friends_friendship_withdrawn', 'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
     69add_action( 'friends_friendship_rejected',  'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
     70
     71/**
    3872 * Clear the friend request cache for the user not initiating the friendship.
    3973 *
    4074 * @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 ce0308a..b27f76f 100644
    class BP_Friends_Component extends BP_Component { 
    284284
    285285                // Global groups.
    286286                wp_cache_add_global_groups( array(
    287                         'bp_friends_requests'
     287                        'bp_friends_requests', // This can go?
     288                        'bp_friends_friendships'
    288289                ) );
    289290
    290291                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 5543502d..525f04b 100644
    class BP_Friends_Friendship { 
    206206        /** Static Methods ********************************************************/
    207207
    208208        /**
     209         * Get the friendships for a given user.
     210         *
     211         * @since 2.6.0
     212         *
     213         * @param int   $user_id              ID of the user whose friends are being retrieved.
     214         * @param array $args {
     215         *        Optional. Filter parameters.
     216         *        @type int    $id                ID of specific friendship to retrieve.
     217         *        @type int    $initiator_user_id ID of friendship initiator.
     218         *        @type int    $friend_user_id    ID of specific friendship to retrieve.
     219         *        @type int    $is_confirmed      Whether the friendship has been accepted.
     220         *        @type int    $is_limited        Whether the friendship is limited.
     221         *        @type string $order_by          Column name to order by.
     222         *        @type string $sort_order        ASC or DESC. Default DESC.
     223         * }
     224         * @param string $operator            Optional. Operator to use in `wp_list_filter()`.
     225         *
     226         * @return array $friendships Array of friendship objects.
     227         */
     228        public static function get_friendships( $user_id, $args = array(), $operator = 'AND' ) {
     229
     230                if ( empty( $user_id ) ) {
     231                        $user_id = bp_loggedin_user_id();
     232                }
     233
     234                $r = bp_parse_args( $args, array(
     235                        'id'                => 0,
     236                    'initiator_user_id' => 0,
     237                    'friend_user_id'    => 0,
     238                        'is_confirmed'      => false,
     239                'is_limited'        => false,
     240                'order_by'          => 'date_created',
     241                'sort_order'        => 'DESC',
     242                'page'              => false,
     243                'per_page'          => false
     244            ), 'bp_get_user_friendships' );
     245
     246                // First, we get all friendships that involve the user.
     247                $friendships = wp_cache_get( $user_id, 'bp_friends_friendships' );
     248                if ( false === $friendships ) {
     249                        global $wpdb;
     250                        $bp = buddypress();
     251
     252                        $friendships = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) ORDER BY date_created DESC", $user_id, $user_id ) );
     253            wp_cache_set( $user_id, $friendships, 'bp_friends_friendships' );
     254                }
     255
     256                if ( ! $friendships ) {
     257                        return array();
     258                }
     259
     260            // Normalize friendship data.
     261                foreach ( $friendships as &$friendship ) {
     262                        // Integer values.
     263                        foreach ( array( 'id', 'initiator_user_id', 'friend_user_id' ) as $index ) {
     264                                $friendship->{$index} = intval( $friendship->{$index} );
     265                        }
     266                        // Boolean values.
     267                        $friendship->is_confirmed = (bool) $friendship->is_confirmed;
     268                        $friendship->is_limited   = (bool) $friendship->is_limited;
     269                }
     270
     271                // Assemble filter array for use in `wp_list_filter()`.
     272                $filters = wp_array_slice_assoc( $r, array( 'id', 'initiator_user_id', 'friend_user_id', 'is_confirmed', 'is_limited' ) );
     273                foreach ( $filters as $filter_name => $filter_value ) {
     274                        if ( in_array( $filter_name, array( 'is_confirmed', 'is_limited' ) ) ) {
     275                                // Separate 'false' from meaningful 0s.
     276                                if ( false === $filter_value ) {
     277                                        unset( $filters[ $filter_name ] );
     278                                }
     279                        } elseif ( ! $filter_value ) {
     280                                unset( $filters[ $filter_name ] );
     281                        }
     282                }
     283
     284                if ( ! empty( $filters ) ) {
     285                        $friendships = wp_list_filter( $friendships, $filters, $operator );
     286                }
     287
     288                // Sort the results on a column name.
     289                if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) {
     290                        $friendships = bp_sort_by_key( $friendships, $r['order_by'] );
     291                }
     292
     293                // Adjust the sort direction of the results.
     294                if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
     295                        // `true` to preserve keys.
     296                        $friendships = array_reverse( $friendships, true );
     297                }
     298
     299                // Paginate the results.
     300                if ( $r['per_page'] && $r['page'] ) {
     301                        $start       = ( $r['page'] - 1 ) * ( $r['per_page'] );
     302                        $friendships = array_slice( $friendships, $start, $r['per_page'] );
     303                }
     304
     305                return $friendships;
     306        }
     307
     308        /**
    209309         * Get the IDs of a given user's friends.
    210310         *
    211311         * @since 1.0.0
    class BP_Friends_Friendship { 
    221321        public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
    222322                global $wpdb;
    223323
    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 );
     324                if ( ! empty( $friend_requests_only ) ) {
     325                        $args = array(
     326                                'is_confirmed' => 0,
     327                                'friend_user_id' => $user_id
     328                        );
    227329                } 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 );
     330                        $args = array(
     331                                'is_confirmed' => 1,
     332                        );
    230333                }
    231334
    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();
     335                $friendships = self::get_friendships( $user_id, $args );
    235336
    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 );
     337                $fids = array();
     338                foreach ( $friendships as $friendship ) {
     339                        if ( ! empty( $assoc_arr ) ) {
     340                                $fids[] = array( 'user_id' => ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id );
    239341                        } else {
    240                                 $fids[] = ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id;
     342                                $fids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
    241343                        }
    242344                }
    243345
    class BP_Friends_Friendship { 
    254356         * @return int|bool The ID of the friendship object if found, otherwise false.
    255357         */
    256358        public static function get_friendship_id( $user_id, $friend_id ) {
    257                 global $wpdb;
     359                $friendship_id = null;
    258360
    259                 $bp = buddypress();
     361                // Can't friend yourself.
     362                if ( $user_id == $friend_id ) {
     363                        return $friendship_id;
     364                }
    260365
    261                 return $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 ) );
     366                /*
     367                 * Find friendships where the possible_friend_userid is the
     368                 * initiator or friend.
     369                 */
     370                $args = array(
     371                        'initiator_user_id' => $friend_id,
     372                        'friend_user_id'    => $friend_id
     373                );
     374                $result = self::get_friendships( $user_id, $args, 'OR' );
     375                if ( $result ) {
     376                        $friendship_id = current( $result )->id;
     377                }
     378
     379                return $friendship_id;
    262380        }
    263381
    264382        /**
    class BP_Friends_Friendship { 
    274392                $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' );
    275393
    276394                if ( false === $friend_requests ) {
    277                         global $wpdb;
    278 
    279                         $bp = buddypress();
    280 
    281                         $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 ) );
     395                        //@TODO: this uses already cached data, so maybe `bp_friends_requests` should go away?
     396                        $friend_requests = self::get_friend_user_ids( $user_id, true );
    282397
    283398                        wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' );
    284399                }
    class BP_Friends_Friendship { 
    299414        public static function total_friend_count( $user_id = 0 ) {
    300415                global $wpdb;
    301416
    302                 if ( empty( $user_id ) )
     417                if ( empty( $user_id ) ) {
    303418                        $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
    304 
    305                 $bp = buddypress();
     419                }
    306420
    307421                /*
    308422                 * This is stored in 'total_friend_count' usermeta.
    309423                 * This function will recalculate, update and return.
    310424                 */
    311425
    312                 $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 ) );
     426                $args = array(
     427                                'is_confirmed' => 1,
     428                );
     429                $friendships = self::get_friendships( $user_id, $args );
     430                $count       = count( $friendships );
    313431
    314432                // Do not update meta if user has never had friends.
    315                 if ( empty( $count ) && !bp_get_user_meta( $user_id, 'total_friend_count', true ) )
     433                if ( ! $count && ! bp_get_user_meta( $user_id, 'total_friend_count', true ) ) {
    316434                        return 0;
     435                }
    317436
    318437                bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
    319438
    class BP_Friends_Friendship { 
    408527                        return false;
    409528                }
    410529
    411                 $bp = buddypress();
    412 
    413                 $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 ) );
     530                // Can't friend yourself.
     531                if ( $initiator_userid == $possible_friend_userid ) {
     532                        return 'not_friends';
     533                }
    414534
    415                 if ( ! empty( $result ) ) {
    416                         if ( 0 == (int) $result[0]->is_confirmed ) {
    417                                 $status = $initiator_userid == $result[0]->initiator_user_id ? 'pending' : 'awaiting_response';
     535                /*
     536                 * Find friendships where the possible_friend_userid is the
     537                 * initiator or friend.
     538                 */
     539                $args = array(
     540                        'initiator_user_id' => $possible_friend_userid,
     541                        'friend_user_id'    => $possible_friend_userid
     542                );
     543                $result = self::get_friendships( $initiator_userid, $args, 'OR' );
     544
     545                if ( $result ) {
     546                        $friendship = current( $result );
     547                        if ( ! $friendship->is_confirmed ) {
     548                                $status = $initiator_userid == $friendship->initiator_user_id ? 'pending' : 'awaiting_response';
    418549                        } else {
    419550                                $status = 'is_friend';
    420551                        }
    class BP_Friends_Friendship { 
    470601         * @param int $friendship_id ID of the friendship to be accepted.
    471602         * @return int Number of database rows updated.
    472603         */
    473         public static function accept($friendship_id) {
     604        public static function accept( $friendship_id ) {
    474605                global $wpdb;
    475606
    476607                $bp = buddypress();
    class BP_Friends_Friendship { 
    486617         * @param int $friendship_id ID of the friendship to be withdrawn.
    487618         * @return int Number of database rows deleted.
    488619         */
    489         public static function withdraw($friendship_id) {
     620        public static function withdraw( $friendship_id ) {
    490621                global $wpdb;
    491622
    492623                $bp = buddypress();
    class BP_Friends_Friendship { 
    502633         * @param int $friendship_id ID of the friendship to be rejected.
    503634         * @return int Number of database rows deleted.
    504635         */
    505         public static function reject($friendship_id) {
     636        public static function reject( $friendship_id ) {
    506637                global $wpdb;
    507638
    508639                $bp = buddypress();
    class BP_Friends_Friendship { 
    730861                // Loop through friend_ids and update their counts.
    731862                foreach ( (array) $friend_ids as $friend_id ) {
    732863                        BP_Friends_Friendship::total_friend_count( $friend_id );
     864                        // Delete cached friendships.
     865                        wp_cache_delete( $friend_id, 'bp_friends_friendships' );
    733866                }
     867
     868                // Delete cached friendships.
     869                wp_cache_delete( $user_id, 'bp_friends_friendships' );
     870
    734871        }
    735872}