Skip to:
Content

BuddyPress.org

Ticket #7436: 7436.1.diff

File 7436.1.diff, 7.0 KB (added by dcavins, 4 years ago)

Add SQL-based alternative to using user-based bulk friendship cache.

  • 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 f683214..55bdbc4 100644
    class BP_Friends_Friendship { 
    257257                        'per_page'          => null
    258258                ), 'bp_get_user_friendships' );
    259259
    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' );
     260                $using_bulk_cache = apply_filters( 'bp_bulk_cache_user_friendships', true );
     261
     262                if ( $using_bulk_cache ) {
     263                        // First, we get all friendships that involve the user.
     264                        $friendship_ids = wp_cache_get( $user_id, 'bp_friends_friendships_for_user' );
     265                        if ( false === $friendship_ids ) {
     266                                $friendship_ids = self::get_friendship_ids_for_user( $user_id );
     267                                wp_cache_set( $user_id, $friendship_ids, 'bp_friends_friendships_for_user' );
     268                        }
     269                } else {
     270                        /*
     271                        * We're not using the user bulk cache method because the site has an
     272                        * unusually large number of friendships per user or something.
     273                        * In this case, we build and run direct queries.
     274                        */
     275                        global $wpdb;
     276                        $bp = buddypress();
     277                        $friendships = array();
     278
     279                        // Build an SQL query
     280                        $sql = array(
     281                                'select'     => "SELECT DISTINCT id",
     282                                'from'       => "{$bp->friends->table_name}",
     283                                'where'      => '',
     284                                'orderby'    => 'date_created',
     285                                'order'      => 'DESC',
     286                                'pagination' => '',
     287                        );
     288                        $where_conditions = array();
     289
     290                        // First limit all requests to refer to the passed user ID.
     291                        $where_user = $wpdb->prepare( "(initiator_user_id = %d OR friend_user_id = %d)", $user_id, $user_id );
     292
     293                        if ( $r['initiator_user_id'] ) {
     294                                $where_conditions['who_initiated'] = $wpdb->prepare( "initiator_user_id = %d", $r['initiator_user_id'] );
     295                        }
     296                        if ( $r['friend_user_id'] ) {
     297                                $where_conditions['who_friend'] = $wpdb->prepare( "friend_user_id = %d", $r['friend_user_id'] );
     298                        }
     299                        if ( ! is_null( $r['is_confirmed'] ) ) {
     300                                $where_conditions['is_confirmed'] = $wpdb->prepare( "is_confirmed = %d", $r['is_confirmed'] );
     301                        }
     302                        if ( ! is_null( $r['is_limited'] ) ) {
     303                                $where_conditions['is_limited'] = $wpdb->prepare( "is_limited = %d", $r['is_limited'] );
     304                        }
     305
     306                        $where = "WHERE {$where_user}";
     307                        if ( ! empty( $where_conditions ) ) {
     308                                $operator = strtoupper( $operator );
     309                                if ( ! in_array( $operator, array( 'AND', 'OR', 'NOT' ), true ) ) {
     310                                        $operator = 'AND';
     311                                }
     312                                $sql['where'] = implode( " $operator ", $where_conditions );
     313                                $where .= " AND ({$sql['where']})";
     314                        }
     315
     316                        // Sort the results on a column name.
     317                        if ( ! in_array( $r['order_by'], array( 'date_created', 'id', 'initiator_user_id', 'friend_user_id' ), true ) ) {
     318                                $r['order_by'] = 'date_created';
     319                        }
     320                        $sql['orderby'] = "ORDER BY {$r['order_by']}";
     321
     322                        // Set the sort direction of the results.
     323                        if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
     324                                $sql['order'] = 'ASC';
     325                        }
     326
     327                        if ( $r['per_page'] && $r['page'] && $r['per_page'] != -1 ) {
     328                                $sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
     329                        }
     330
     331                        // Warm the friends cache.
     332                        $friendship_ids = $wpdb->get_col( "{$sql['select']} FROM {$sql['from']} {$where} {$sql['orderby']} {$sql['order']} {$sql['pagination']}" );
    265333                }
    266334
    267335                // Prime the membership cache.
    class BP_Friends_Friendship { 
    305373                                $friendship->{$index} = (bool) $friendship->{$index};
    306374                        }
    307375
    308                         // We need to support the same operators as wp_list_filter().
    309                         if ( 'OR' == $operator || 'NOT' == $operator ) {
    310                                 $matched = 0;
     376                        // Run the filters if we're using the bulk membership cache.
     377                        if ( $using_bulk_cache ) {
     378                                // We need to support the same operators as wp_list_filter().
     379                                if ( 'OR' == $operator || 'NOT' == $operator ) {
     380                                        $matched = 0;
    311381
    312                                 foreach ( $filters as $filter_name => $filter_value ) {
    313                                         if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) {
    314                                                 $matched++;
     382                                        foreach ( $filters as $filter_name => $filter_value ) {
     383                                                if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) {
     384                                                        $matched++;
     385                                                }
    315386                                        }
    316                                 }
    317387
    318                                 if ( ( 'OR' == $operator && $matched > 0 )
    319                                   || ( 'NOT' == $operator && 0 == $matched ) ) {
    320                                         $friendships[ $friendship->id ] = $friendship;
    321                                 }
     388                                        if ( ( 'OR' == $operator && $matched > 0 )
     389                                          || ( 'NOT' == $operator && 0 == $matched ) ) {
     390                                                $friendships[ $friendship->id ] = $friendship;
     391                                        }
    322392
    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;
     393                                } else {
     394                                        /*
     395                                         * This is the more typical 'AND' style of filter.
     396                                         * If any of the filters miss, we move on.
     397                                         */
     398                                        foreach ( $filters as $filter_name => $filter_value ) {
     399                                                if ( ! isset( $friendship->{$filter_name} ) || $filter_value != $friendship->{$filter_name} ) {
     400                                                        continue 2;
     401                                                }
    331402                                        }
     403                                        $friendships[ $friendship->id ] = $friendship;
    332404                                }
     405                        } else {
     406                                // The sorting has already been done in the SQL query.
    333407                                $friendships[ $friendship->id ] = $friendship;
    334408                        }
    335409
    336410                }
    337411
    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                 }
     412                // Do some organization if we're using the bulk membership cache.
     413                if ( $using_bulk_cache ) {
     414                        // Sort the results on a column name.
     415                        if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) {
     416                                $friendships = bp_sort_by_key( $friendships, $r['order_by'], 'num', true );
     417                        }
    342418
    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                 }
     419                        // Adjust the sort direction of the results.
     420                        if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
     421                                // `true` to preserve keys.
     422                                $friendships = array_reverse( $friendships, true );
     423                        }
    348424
    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'] );
     425                        // Paginate the results.
     426                        if ( $r['per_page'] && $r['page'] ) {
     427                                $start       = ( $r['page'] - 1 ) * ( $r['per_page'] );
     428                                $friendships = array_slice( $friendships, $start, $r['per_page'] );
     429                        }
    353430                }
    354431
    355432                return $friendships;